Stream Videos over Blob Storage

Azure Blob Storage is an easy and cheap solution for hosting files in the cloud. But there is one thing that doesn't work well in the default configuration of a Storage Account: Video streaming.

The important note here is, that this only applies to Storage Accounts that are general purpose v1. In V2 everything works out of the box.

For video streaming to work nicley, the browser requires that the source (our Blob Storage) will present the Accept-Ranges header in the response of the file and know how to handle the Range header in the request. This is called partial request in the HTTP world.

Default API version of a StorageAccount in Azure is:
2009-09-19.

This is too old, according to the docs from Microsoft the minimum supported API version for range headers is 2011-08-18.

The version change can be achieved in two ways:

  • Set the x-ms-version header with every request to an higher version
    • This requires you to have full controll over the player you use and you can inject the header with JavaScript to every request the player does. (don't do this...)
  • Change the default API version of your storage account

Because the first option has some drawbacks, we are going to concentrate on the second option.

Change the defaults.

To change the defaults you must deploy the following template:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "resources": [
		{
  			"type": "Microsoft.Storage/storageAccounts/blobServices",
  			"apiVersion": "2021-09-01",
  			"name": "storageaccountname/default",
			"properties":{
				"defaultServiceVersion": "2021-08-06"
			}
			
		}
	]
}

This template will set the default service version to 2021-08-06 which is the latest version that was available while writing this article. And it is higher than 2011-08-18.

If you now try to download a file of your blobstorage you will see a new header in your response: Accept-Ranges. This header has the value bytes. This is perfect for browsers. Now we enabled partial request support from a browser view.

If you now upload a video to your blobstorage you can open it just over the link.

Here is an example: https://rfvk.blob.core.windows.net/asset-6c3d80d3-b845-4b91-b718-c0c6b4ed3b34/Wanderritt.v.2_1280x720_AACAudio_2722.mp4

And if you open the developer tools of your browser, and skip over the preloading bar, you will see a new request will be made that will end in a 206 response code. And in this request you will also see a Range header that contains a number. That is the byte position the download of the file should continue. That's exactly what we want.

The video codec is important

The things shown before in this blog post won't work with every video. For this solution to work, the video file must be encoded in a special way. In DaVinci Resolve you have an option to encode a video file "optimized for network". This means that the required metadata of the video like:

  • how long
  • what is the bitrate

are stored at the beginning of the video file and not at the end. Only if this is done the previous behavior will work.

In ffmpeg the option is called -movflags faststart and has a good explaination here:
https://manpages.org/ffmpeg

Nice to knows

This can be also helpful to support things like continue a download of a big file when it was canceled for example by network loss. So it's a good thing to enable this also for content that isn't a video.