Streaming terabytes of videos for pennies

developedbyed| 00:16:13|May 19, 2026
Chapters9
Discusses why MP4 is convenient but problematic for large or slow connections and introduces HLS as the flexible alternative.

A practical, cost-conscious blueprint for hosting terabytes of video using HLS (M3U8), FFmpeg, Cloudflare R2, and a custom UI, dramatically lowering storage and streaming costs.

Summary

Ed from developedbyed shares a hands-on approach to hosting massive video libraries on a budget. He compares MP4 hosting with adaptive streaming via HLS, explaining why TS-based HLS playlists reduce bandwidth and improve mobile playback. He walks through the economics of providers like Mux, Bunny.net, Cloudinary, and Cloudflare, highlighting that Cloudflare often comes out on top due to cheap storage and free egress. The video details a practical workflow: encode MP4s into multi-bitrate HLS using FFmpeg, generate thumbnails, and upload to R2 buckets, with optional UI and server logic to manage access. Ed demonstrates a local-dotnet-esque encoding/upload flow, plus a UI for drag-and-drop uploads that handles encoding, syncing to a database, and access control. He emphasizes the convenience of consolidating tools in Cloudflare (Workers, R2, and streaming) to avoid stitching multiple services together. Real-world touches include secure vs. free preview players, server-side access checks for subscription status, and the inevitability of piracy despite protection efforts. The video ends with a practical recap and a nod to Cloudflare’s evolving ecosystem, including new transactional email capabilities on the $5 Workers plan.

Key Takeaways

  • HLS with M3U8 and TS chunks enables adaptive streaming, letting devices switch between 480p, 720p, and 1440p automatically.
  • Mux pricing for 1 TB storage plus 10 TB streaming can reach around $140 storage and $15,000 streaming, highlighting why cheaper CDNs are appealing.
  • Cloudflare R2 storage costs are around 1.5 cents/GB with free egress, making it a strong backbone for hosting and streaming videos.
  • FFmpeg-based encoding scripts plus a small UI can automate the pipeline from MP4 to multi-bitrate HLS and thumbnail generation.
  • Cloudflare Workers + R2 offer an integrated stack for hosting, encoding, access control, and delivery in one place, reducing integration overhead.
  • Encoding workflow benefits from TS-based HLS to avoid re-encoding at runtime and to cut encoding/decoding costs across providers.
  • Secure access patterns (sign-in and subscription checks) protect buckets while acknowledging that absolute piracy prevention is impractical.

Who Is This For?

Developers and indie course creators who want to stream large video libraries cost-effectively without juggling multiple services. Ideal for those already using or considering Cloudflare, R2, and FFmpeg-based pipelines.

Notable Quotes

""Video on the other hand was historically a bit more difficult uh to host, but also to create encodings and create different qualities depending how the network is for that specific user that views your content.""
Ed sets up the problem of streaming video quality and network adaptation.
""The big downside is that if it's a large file, you can even imagine a 4K video, this whole blob will have to download on that user's device.""
Illustrates why MP4-only hosting is suboptimal for bandwidth and user experience.
""The big advantage of using the M3U8, my god, who came up with this extension name, is that a lot of these services you're going to see, they're going to charge for encoding and decoding.""
Explains cost efficiency of HLS via M3U8 over plain MP4 hosting.
""Cloudflare came out on top for me. The storage is really really cheap coming at 1.5 cents per gigabyte, but egress is free.""
Cites the economic case for Cloudflare R2 in his setup.
""If people want to pirate something, trust me, they will find a way to pirate it... the effort to go through of trying to protect that is sometimes not even worth it.""
Honest note on security trade-offs and piracy.

Questions This Video Answers

  • How can I reduce video hosting costs with HLS and R2 compared to traditional MP4 hosting?
  • What is M3U8 and why is it cheaper for streaming video than encoding everything as a single MP4 file?
  • How do I encode MP4 to multiple resolutions using FFmpeg for a streaming workflow?
  • What Cloudflare tools do I need to build a production-grade video platform on a budget?
  • Is it possible to secure access to videos hosted in Cloudflare R2 without blocking legitimate viewers?
HLSM3U8FFmpegVideo EncodingCloudflareR2MuxBunny.netCloudinaryStreaming Costs
Full Transcript
Hey there, how's it going? This is not an AI video. Prayer 2026W, 99% of the internet's content usually falls into these three pillars, which is text, images, and video. Now, there's some other stuff out there like 3D rendering, uh but this is what you see usually. Now, text is super easy. You just write HTML code and you can pretty much host it anywhere. Images can be a bit trickier because you need to do some optimizations and maybe serve up different sizes for uh different devices. Uh but that's also relatively easy to do and there's many providers out there that do it relatively cheap as well. Video on the other hand was historically a bit more difficult uh to host, but also to create encodings and create different qualities depending uh how the network uh is for that specific user that views your content. So, if you're interested in hosting large amounts of video content, whether that's on the course platform or exclusive videos like Corridor Crew has, for example, here's a really good way to do it. Before we talk about different providers that can host videos, it's really important to understand what kind of files we're even working with because that's going to dictate the ultimate price we're going to pay for. So, the initial instinct people have is to host an MP4 file and the big advantage is that it's really convenient, really easy to do, supported with just a video tag, uh and then you just can just drop it in a bucket somewhere. The big downside is that if it's a large file, you can even imagine a 4K video, this whole blob will have to download on that user's device. So, they might be stuck seeing a loading screen for ages if their device is really slow. Not only that, I wouldn't want personally, if I'm on like 4G or 5G, I'm using like the mobile data usage, uh for a video to like consume 2 GB. Like that's pretty ridiculous. So, whilst MP4s are easy to do, uh the disadvantages are quite big. So, what usually happens is if you go on YouTube, if you go on Vimeo, or pretty much any popular website, is you have different quality options. And that's essentially where HLS playlist comes in. So, what this does is it creates a master playlist, and then it breaks up the video in these small chunks that are like 4 seconds long or something like that. And you can create different qualities, and then swap them out based on the user's network connection, for example. Now, it's pretty annoying. It's a TS file, not to confuse it with a TypeScript file. But the big advantage of this is that if I view it on a phone that's lower resolution, it can potentially swap down to a lower quality. So, we don't need to do the 4K video, it could stream maybe a 1080p one. So, and it does that automatically, which is really, really nice. And the other advantage of using the M3U8, my god, who came up with this extension name, is that a lot of these services you're going to see, they're going to charge for encoding and decoding. So, you will save a significant amount of money by not going down the MP4 route. So, just to give you an example, this is the platform I've been working on last year, which I kind of put on a hold cuz all the tutorial-type videos kind of died out. That's a whole 'nother topic that I might talk about. But this is going to be changed to something else. It was just put on pause. But I used the M3U8 playlist here to stream these videos in. And I'll show you exactly how I did that. But you're going to see that I'm on a really bad internet here, and the loading times for these are really, really quick. And as you can see, I can also pick the different quality versions. So, I can go to 720p, I can go to 480p, or leave it on auto for it to change on its own. But, it's really fast, really effective, and this again, I'm on a Wi-Fi with a really bad connection, and it's super quick. So, there's a lot of different options that you have when you want to stream and store videos. So, one of the popular ones is called Mux, and initially when you look at it, it looks pretty good. You're like, "Ooh, 100k free monthly delivered minutes." You're like, "Okay, that's not too bad." I did a quick math here to kind of see how that is. So, let's put 100k in. I'll divide it by 60 to work in hours cuz minutes is just weird. So, 1,666. So, let's put that in. Let's say we have 100 users, so I'll divide it by 100. So, each user can be be potentially consume 16 hours of video. So, that's pretty good, right? But, then you check here, and it's like, "Oh, only 10 videos stored. Okay, so I have to go on the pay-as-you-go plan." But, when you go here, it's like a whole hoo-ha trying to find out how much it actually cost. Now, there's a couple of other options like Bunny.net, you have Cloudinary, and my personal favorite one that I use is going to be Cloudflare. So, I put together a little graph here to show you how much it would actually cost. So, this is for 1 TB of stored video and 10 TB of streaming. So, with Mux, you are essentially going to pay around $140 for that 1 TB of storage. Now, when it comes to actually streaming that, that's going to be 2.5 cents uh per minute, which is pretty crazy. So, if you stream 10 TB of video, it's going to cost you $15,000. That is insane. Now, they give you the player and the analytics and stuff like that. It is what it is. Okay, next up you have Cloudinary, a bit cheaper, around 120, and egress is is considerably cheaper as well. AWS is really cheap, but in my opinion, is so difficult to set up. Bunny came really close as being my go-to choice. I did like how cheap it was to store and the egress wasn't bad either. So, I really really like them, but in the end Cloudflare came out on top for me. The storage is really really cheap coming at 1.5 cents per gigabyte, but egress is free. So, you can stream content from your bucket without paying for anything, which is amazing. And now all we have to do is really solve this little problem here uh which is converting and encoding your MP4 files into a different format, but that's actually really really easy to do. Now, Bunny did have okay pricing coming in at 1 cent per gigabyte. Uh egress did cost some money, so streaming the content over, but not too bad. However, I was in the position where I was really really getting into Cloudflare. Like over the years I feel like Cloudflare was getting better and better. I was already a big fan of it, but I still had my like small issues when it came to uh their runtime, which is Worker D. And it was a bit more difficult to kind of stitch it up and make it work in your application, but once you had it working in your application, the super nice thing about Cloudflare is you can just call that worker and then call the caching layer on it or call R2 to access your R2 bucket. It's all in one place kind of bundled up, so you can just access everything through that object, which is super super convenient. So, I wanted to when I was making this platform, I was thinking, "Okay, how can I just make it so everything is in one place rather than reaching out to multiple different services?" Cuz I do have a couple of things like blog posts here that are interactive. I had streaming video here. I also have challenges here where you need to build like a URL query builder, for example, and then you can ask AI here for help. So, how do I solve this problem? And then it would answer you. And then it would also check and debug this for you. So, if I run this code here, submit the solution, it checks it and actually gives you a response of things that you did right or things that you did wrong. As you can see here, missing query builder function definition. Now, I should note that Cloudflare also has a streaming service. Uh but here you're essentially you basically it's convenience, right? So, they'll do the encoding, they'll do everything for you. And if you're already on the $5 plan, it's not too bad. But I still prefer the R2 way. Okay, so we have our MP4 video, we filmed it through OBS. How can we actually get this up and running? Well, we all we need is essentially an SSH file here, which is called HLS encode. And this will take in an input and a working directory here, and then we can define our resolutions. So, I picked three here, but you can do as many as you want. So, 480, 720, and 1440p. For me, that's enough. You also need to pick a bitrate. These are pretty good values here to use them. And that's pretty much it. You are essentially putting this through FFmpeg to generate it for you. And then you can also add This is another cool little thing that I did is I can also extract a thumbnail for each of the videos. So, I can check at a specific frame in the video, and I can grab a JPEG out of it. If you check here on the videos, as you can see, they all have one little thumbnail. So, that gets automatically generated as well. I'll leave this little script here on GitHub, so you can check it out. Now, to get this to work, you need to install FFmpeg as well on your device. And then you'd simply call the script. So, you'd go to dot slash script slash HSL encode or whatever it's called.sh and then you pass down the different parameters that you might need. So, for for my case it would be the path to the file. So, I could go to documents/video.mp4 like that. And then the output as well. So, where would that live? I can pass that down. But, if that is a bit inconvenient, you can also make a little UI for it to make this whole process simpler because after you generate the file, you would also need to use Rclone or something like that to go to that specific file and to actually sync it with your R2 bucket. Now, having the script is great and all, but it might be a bit crappy to use because if someone else also wants to push up courses or videos on your platform, you need to give them a whole explanation of how to run these scripts. And again, there are a couple of scripts cuz you have one for generating the empty U8 playlist, but you'd also need one to upload, and you would also potentially need one to sync to your database like this. Here's a really big one that just checks a bunch of different stuff and how to upload it to the database and sync it. Okay? So, it's it's quite a little bit. However, what you can do is create a little UI for it. Thankfully, with AI it's really simple to do it nowadays. And I have it right here. So, let me show you. So, we have a upload server.ts file here that specifically uses the uh what's it called? AWS package here. This is a really great package. You can use it on a bunch of different buckets that support this protocol. So, it works fine on R2 just fine. So, here it is. You give it the endpoint as well and the credentials. So, this is how it's set up. And then let's just simply head back here to the uh upload server. So, we have that. We have the bucket name, the port as well we want to run on, and the different jobs we want to do. So, whether that's encoding, uploading, whatever, it doesn't matter. And we can just do all this locally here from uh converting to syncing to deleting files. It does not need to live on on the web, okay? I I think this is fantastic. This way we can have lots of videos uploaded, all the brunt work and like processing uh the the expensive computation is done locally on the device. So, if I show you this, I'll just run this. Uh it's in bun. So, there we go. Now, we just got a super simple UI here where we can drag and upload an MP4 file. But, there we go. MP4, and I can give a name for this course. Can call it Wahoo. Can give it a chapter name, which is 01 intro, and then a lesson name as well, which is going to be baby. And then we can hit encode and upload, and something's missing. The video, there we go. Pop it in, and boom. Does the encoding for you. Might take a couple of minutes, but then it converts it, and it syncs everything up. I can just hit sync DB, and I'm good to go. It just appears on the website. Easy as that. Now, we need to also kind of protect these, especially if you're planning on doing a paid product or something, right? These are on a public bucket. But, as you can see, when I click here now on the video, it says access denied. So, here we go. We have a free preview player and a secure video player. So, the free preview player uh essentially just pulls in that link from the database that I saved, and just exposes it here in this Mux player. So, it's just the R2 prefix and I need to pass here, pointing to that path in the bucket. And that's pretty much it. Now, when it comes to the secure player, that's just as easy. If we go here, as you can see, this is going to go and call a server function here, which is get video access function. So, we call this on load, and if we check here, let me head into it. So, here we go and pass that start. I essentially have a server function here that runs a middleware here uh that checks a bunch of stuff in Cloudflare. So, it checks uh if the user is signed in, but also if the user is subscribed or not. And if they are subscribed, then he can have access to that specific path in the bucket. Now, you might be saying, "Okay, well, is that really hard security cuz once they know the URL, then they can access the video, and they can share it with someone." Uh it's true, but at the same time, you can do other stuff to kind of protect it. It's still is It's one of those things that, you know, you're going to end up finding a person that just like opens OBS and just captures the whole course for you anyway. So, uh I think that's good enough protection on my part. Uh so, if people want to pirate something, trust me, they will find a way to pirate it, and the effort to go through of trying to protect that is sometimes not even worth it. But there we go. Look at the progress it's making. It converted everything over, and now it's uploading all of those uh different uh TS segments here. So, this is why I like Cloudflare so much uh in the last, you know, couple of years is is just everything is here for me to build out a production-grade application, which is super cool. And now they have the new email as well, where you can do transactional emails. That's also included in the like $5 worker plan. You can do like 3,000 of them or something like that. That's crazy. Super, super nice. So, I'm really, really happy to see the direction that they're going to. And there we go. The video has been uploaded. We have all the different segments here, and we can simply sync it to the database. And if we check down here at the bottom, as you can see, we have Wahoo, which has one chapter in it with the video baby. So, if I head over to Cloudflare, let's check our R2 bucket. And there we go, we have two courses now. We have Build Your Own UI Library and Wahoo as well. If I click here, we have one chapter, intro, baby as well, and all the different qualities that we picked with my own little thumbnail here as well. So, if we open it, as you can see, there's a bunch of different TS segments ready to go. So, hopefully this helped. I feel like this is such a really underrated trick that you can use to host a bunch of videos. So, I hope this helped a lot. Thank you so much for watching. Appreciate you being here, and I will catch you in the next one.

Get daily recaps from
developedbyed

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.