During the last few weeks I have been involved in a very interesting project with lots of potential, using Windows Azure Media Services. In a nutshell, Windows Azure Media Services supports encoding, management, and streaming of media from Windows Azure, in a completely hosted solution.
The client requested a proof-of-concept end-to-end solution that involves uploading existing media assets to Windows Azure, encoding them to smooth streaming formats, and delivering them to an audience using Windows computers, iOS devices, and Android devices. (The client’s current solution involves shipping of media files to a third party company, which takes care of the encoding jobs and delivers back URLs for streaming.)
The architecture I ended up implementing on top of Windows Azure is the following:
From the client’s perspective, the only on-premise component is the uploader application, which uploads H264 MP4 files to an ASP.NET web application hosted in Windows Azure Web Sites (1). The web application creates a Windows Azure Media Services asset and streams the client’s upload to Windows Azure Blob Storage (2). Metadata about the upload, such as the file name, description, thumbnail URL, and other information is stored in Windows Azure Table Storage (3). When the upload completes, the ASP.NET application puts a message in Windows Azure Queue Storage (4), which a Worker Role dequeues and initiates an encoding job with Windows Azure Media Services (5). When the encoding job completes (6), the Worker Role generates streaming URLs with the Windows Azure Media Services origin servers, and stores these URLs for the web application to consume (8).
This end-to-end process can potentially replace the client’s current solution for media encoding and delivery. Although full pricing information for Windows Azure Media Services has not yet been disclosed (for example, the cost of on-demand streaming units), our estimates indicate a considerable cost savings when moving the whole solution to Windows Azure.
Support for multiple devices To support as many devices as possible, it was necessary to encode the original MP4 video to two streaming formats: IIS Smooth Streaming, supported easily by Silverlight players, and Apple HLS, supported natively by iOS devices as well as newer Android devices.
On Windows and Mac computers, we could stream the video using a Silverlight player, which I borrowed from CodePlex.
On iOS and Android devices, all we had to do is embed the streaming URL in a <video> element:
<video width="640" height="480" controls> <source src="..." /> </video>
Finally, for “unsupported” devices, we chose to use a <video> element pointing to the original MP4 file, progressively downloaded from Windows Azure Blob Storage. Although this does not provide the advantages of smooth streaming (adaptive bitrate), it works out of the box on any device that supports the <video> element in a browser.
Overall, rolling out the above solution took only a few days. I integrated most of the moving parts on-premises, and then started uploading parts of the system to Windows Azure. First, I uploaded the ASP.NET web application to Windows Azure Web Sites, which was a breeze. Next, I wrapped a console application (that took care of starting and monitoring the encoding process) in a Worker Role. Finally, after sorting out a few remaining issues, the solution was ready to roll on Windows Azure. Below are some of the implementation highlights:
Creating a Windows Azure Media Services asset and uploading the MP4 file to Windows Azure Blob Storage:
Stream inputStream = Request.InputStream; var blobClient = storageAccount.CreateCloudBlobClient(); var asset = mediaContext.Assets.Create( assetName, AssetCreationOptions.None); var writePolicy = mediaContext.AccessPolicies.Create( "policy for copying", TimeSpan.FromMinutes(30), AccessPermissions.Write | AccessPermissions.List); var destination = mediaContext.Locators.CreateSasLocator( asset, writePolicy, DateTime.UtcNow.AddMinutes(-5)); var destContainer = blobClient.GetContainerReference( new Uri(destination.Path).Segments); var destBlob = destContainer.GetBlockBlobReference(file); dest.UploadFromStream(inputStream); destBlob.Properties.ContentType = "video/mp4"; destBlob.SetProperties();
Getting a publicly readable URL for the static MP4 file uploaded:
var assetFile = asset.AssetFiles.Create(file); assetFile.Update(); asset = mediaContext.Assets.Where( a => a.Id == asset.Id).FirstOrDefault(); var readPolicy = mediaContext.AccessPolicies.Create( "policy for access", TimeSpan.FromDays(365 * 3), AccessPermissions.Read | AccessPermissions.List); var readLocator = mediaContext.Locators.CreateSasLocator( asset, readPolicy, DateTime.UtcNow.AddMinutes(-5)); string parts = readLocator.Path.Split('?'); string staticUrl = parts + "/" + file + "?" + parts;
Firing off an encoding job that first encodes the MP4 file to the IIS Smooth Streaming format, and then encodes the result to Apple HLS format suitable for streaming from iOS devices:
var job = mediaContext.Jobs.Create( "Encoding Job for " + asset.Name); var encoder = mediaContext.MediaProcessors.Where( m => m.Name == "Windows Azure Media Encoder").First(); var encodingTask = job.Tasks.AddNew( "Encoding Task for " + asset.Name, encoder, "H264 Smooth Streaming 720p", TaskOptions.None); encodingTask.InputAssets.Add(asset); var ssOutput = encodingTask.OutputAssets.AddNew( "output-Silverlight-" + asset.Name, AssetCreationOptions.None); var packager = mediaContext.MediaProcessors.Where( m => m.Name == "Windows Azure Media Packager").First(); var conversionTask = job.Tasks.AddNew( "Conversion Task for " + asset.Name, packager, File.ReadAllText("MediaPackager_SmoothToHLS.xml"), TaskOptions.None); conversionTask.InputAssets.Add(ssOutput); conversionTask.OutputAssets.AddNew( "output-HLS-" + asset.Name, AssetCreationOptions.None); job.Submit();
What does the future hold?
If this proof-of-concept is successful, we could be talking about petabytes of data hosted in a similar fashion on Windows Azure and streamed to millions of viewers.
We still need to find better solutions for older Android devices, which do not support Apple HLS natively; there’s also live streaming to consider, which Windows Azure Media Services currently does not support.
This was a project that highlighted the flexibility and ease of use that have been so typical of Windows Azure since the first time I’ve touched it. Whether it’s a Node.js app on Windows Azure Web Sites, a Windows Azure Mobile Service accessed by iOS and Android apps, or a fuller solution like the above, Windows Azure is fun to use and easy to understand.
When I first pitched this solution to the client, I faced lots of anxiety about putting data on Windows Azure or streaming media from a datacenter far away. Later in the project, I was greeted by the client’s less-technical folks humming away on Windows Azure Virtual Machines, configuring firewalls for Windows Azure SQL Database, and experimenting with publishing ASP.NET applications to Windows Azure Web Sites.
Thanks to Maor David and Noam King from Microsoft Israel for their support with this project.
I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn