Streaming MP4 video files in Azure Storage containers (Blob Storage)
We recently had some problems streaming MP4 video files in a Microsoft Azure storage blob. Hopefully these pointers will help if you’re also struggling:
Get Some Tools
You’ll need some tools as you’ll need to examine and change the HTTP headers of your files, which you can’t do in the Azure Portal. From using them, I can recommend either the Azure Storage Explorer, or the CloudBerry Explorer. Both are free, and both let you download and upload files, as well as set headers. I’ll be using CloudBerry Explorer for the screenshots.
For investigation and diagnostics, you’ll also need Fiddler. If you don’t know how to use Fiddler, it’s definately worth investing some time. It’s an excellent way to start to understand how HTTP traffic works.
Check your Blob Type
Make sure your videos are BlockBlobs. Check the header x-ms-blob-type. There are BlockBlobs and PageBlobs … but for streaming video you want BlockBlobs.
Check your Content Type
Make sure you have a sensible value in the Content-Type header. By default your videos may well have the type application/octet-stream. You should change this to be correct for your media. For MP4 files, use video/mp4.
Check your Storage Version
My what? Yep, this was news to me too. The Azure Blob Storage system is big. Because it has some pretty specific and unusual requirements, Microsoft don’t run it over IIS. Instead, it’s a purpose-built system, designed to deliver content in the most efficient way possible. It’s also in a state of evolution, with new features being added all the time. When it was created, your account was assigned a specific version number, and it will run at that version number until it’s changed. This enables Microsoft to make changes to the infrastructure without breaking everyone’s code each time they change how a feature works.
However, there have been some improvements to how Azure handles streaming of MP4 file – and you will want those changes if you want to get your MP4 files streaming. So, you need to change your account version. You can’t do this in the Azure portal, but here’s how you can programatically:
To get this to work, you’ll also need the Azure.Storage nuget package, which you can install by running Install-Package WindowsAzure.Storage from the Package Manager console in Visual Studio.
In my sample, I’m updating the account to the “2013-08-15” release, one of the more recent ones. However, for the streaming video improvements, you can use any version number newer than “2012-02-12”.
My account was on version “2009-09-19” – you can also tell quickly by looking at the response headers, looking for the x-ms-version header.
There’s more on Azure Versioning on MSDN: Versioning for the Blob, Queue, and Table Services in Windows Azure.
Check your Videos
If you’ve got this far (and I got this far) then it might be time to examine your videos, to make sure they’re in the best possible shape to support streaming downloads. It seems to make a difference how you choose to play them as to what’s needed and what’s not. For instance, Google Chrome consistently streamed my MP4s without me needing to make any changes, but Windows Media Player (and anything that relied on it, such as embedded video streams) refused to.
I don’t know that much about video file formats, but I did find this blog post by Renaun Erickson which describes a problem with H.264 files where the index for the file (which allows streaming) is placed at the end of the file, meaning you can’t start streaming until you’ve downloaded the whole video! He’s created a small tool, the QTIndexSwapper, which moves this index to the beginning of the file, which you can download from that page as well (requires Adobe Air).
Doing this on my videos made an instant difference for Media Player – which now started streaming the videos correctly.
If you’re serving up your videos from a Storage Blob, have you considered a CDN? You’ll be serving your customers from a CDN node that’s best for them (UK guys get served from the UK node, US guys from the US node etc) which will give better performance. Also, if your video content doesn’t change much then you can cache the videos on the CDN. This is good for you because otherwise you’d be paying twice: once to transfer the data to your customers, and once to transfer it from your Storage Blob to the CDN. Fix the cache at a year, and you’ll only pay one lot of transfer charges!
However… make sure you get everything right BEFORE you set the cache age to its maximum possible 1 year setting. If you’ve forgotten to do something, or you need to change one of your headers, these changes won’t get picked up by the CDN until the cached copy expires. You could be waiting a very long time for your videos to start streaming! Instead, set it to a low value (like a day) whilst you verify everything is OK, then look at increasing it. There is no way to clear the Azure CDN Cache! (I didn’t do this, and now need to rename all my videos…)
You can change the cache expiry by setting the Cache-Control header. For instance, to set the header to 24 hours I use public, max-age=86400:
You can check your handiwork in Fiddler, by requesting the video (either using Media Player and watching what Fiddler does, or by using the Composer tab to request it directly). The first time you’ll see the Cache-Control header in the response. In subsequent requests (assuming you’re using the CDN URL) you’ll also start to see the age of the cached copy:
I’d not seen this before, but I was recommended the Player Framework to use as the embedded video player. This is a Microsoft Open Source project which has a number of impressive-looking features, including adaptive streaming. I shall certainly be investigating this for the next project we have that involves embedded video: it looks like it takes a lot of the hassle out of serving up video content.
Massive thank you to Vito, who’s a Azure Technical Evangelist and who helped me with a lot of this stuff. 🙂