June 2012

Volume 27 Number 06

Microsoft Azure - Democratizing Video Content with Microsoft Azure Media Services

By Bruno Terkaly | June 2012

One of the unmistakable trends slated for amazing growth over the next few years is the streaming of video content. According to the Cisco Visual Networking Index (VNI) 2011, Internet traffic related to this activity will quadruple by 2015. Multiple factors are behind this phenomenon, including: shrinking storage costs; scalable cloud compute and storage resources; high-bandwidth networks; and a multitude of video-enabled devices, such as tablets and smartphone devices. Creating, encoding and distributing video has never been more practical and affordable for even the casual hobbyist.

There’s a major battle taking place over the way video content is being delivered and protected by copyright law. Many of us have witnessed the music industry undergo an amazing transformation, moving power away from the big record labels down to Internet-based media companies. The major carriers and cable providers today are concerned about the emerging growth of video on demand and the use of Internet channels to distribute it, including YouTube, Ustream and justin.tv, to name a few.

Microsoft isn’t idly sitting by while all this happens. In May 2012, the software company released new Media Services features in Azure, which will help democratize video creation, management and delivery to the masses. Azure Media Services (just “Media Services” hereafter for brevity) support many different device types, from smartphones to tablets to high-end video workstations. This set of features—formerly code-named “Nimbus”—enables individual developers and corporations to build cloud-based media solutions for ingesting, processing, managing and delivering media content.

Solving Problems

These new Media Services features bring an automated, standardized and cost-effective solution to the media management space that dramatically lowers barriers and complexities by offering three main benefits:

  1. Automatic scalability by leveraging the benefits that cloud computing offers, including the increase of capacity on demand, based on user needs.
  2. A richly programmable interface based on a RESTful API, along with a Microsoft .NET Framework client library that allows developers to create, manage and maintain custom workflows easily.
  3. A partner ecosystem that includes components from multiple companies that can be plugged into any step of the aforementioned workflows.

These comprehensive Media Services provide solutions to a variety of common problems for companies creating, managing and distributing content. The first one is cost, because building a video-capable datacenter is expensive. Having to provision servers, encoders, networking equipment and related software represents a high barrier to entry. The second problem that Media Services solve is the industry-wide issue of customized workflows. Many companies in the media segment have created their own proprietary business contracts, which makes it difficult to coordinate related services across different vendors using multiple formats and protocols. Standardizing the way video gets processed improves coordination and productivity when you have multiple participants involved in the creation and management of content.

Open Standards

Media Services are based on open standards, meaning they can be leveraged by almost any client, including Java, PHP, Objective-C and jQuery, to name a few. The entire suite of capabilities is available through a common RESTful API, leveraging the Open Data Protocol (OData) to help with flexible querying capabilities. There’s also a .NET C# SDK—built on top of the RESTful API—that facilitates and simplifies access to the framework for developers using this language (see Figure 1).

Figure 1 Two Approaches to Programmatically Use Azure Media Services

REST/OData API

Developers can access the Media Services components through the Representational State Transfer (REST) API layer. Because REST is based on HTTP, it can be consumed from practically anywhere using a wide variety of languages, applications and platforms. In short, the REST API is the universal, public, programmatic interface for accessing the Media Services layer across the Web.

REST is an architectural strategy for building networked client-server applications based on open standards. REST provides a stateless, cacheable and standard protocol (HTTP) to send information between networked machines.

.NET API

Naturally, there’s also a .NET Client SDK (which wraps the REST API calls and simplifies the process of building a .NET-based Media Services client application).

This article will focus on the .NET API. Future articles will address REST-based approaches.

Leveraging the Media Services API

In order to better understand the benefits of the Media Services features of Azure, this article focuses on a specific case scenario. Imagine a home video that needs to be shared with multiple family members or friends who might have a wide variety of mobile devices. Figure 2 depicts the overall workflow required to deliver custom processed video content to the world.

Overall Workflow Required to Distribute Video Content
Figure 2 Overall Workflow Required to Distribute Video Content

Prerequisites

Uploading and Encoding Content

Let’s start with the basic tasks for distributing video content. The code in Figure 3 accomplishes two important goals of anyone who works with video. The first one is to upload the original content so it can be processed. The second goal is to actually encode the content in such a way that it can be consumed by multiple devices. There are many different formats for video, such as MPEG, MPEG-2 (QuickTime), RealMedia, H.264 (MP4) and Windows Media, just to name a few—even YouTube has its own encoding format. Encoding formats aren’t equal. Many of them are designed to be small, enabling fast Web downloads and renderings. Others, such as H.264, emphasize quality without a concern for video size.

Figure 3 Uploading and Executing an Encoding Job

static void Main(string[] args)
{
  // Part 1 - Connect to Media Services
  //          Setup upload progress event
  //          Upload a video to encode
  CloudMediaContext mediaContext =
    new CloudMediaContext("[ ACCOUNT NAME ]","[ ACCOUNT KEY ]");
  mediaContext.Assets.OnUploadProgress += Assets_OnUploadProgress;
  var asset = mediaContext.Assets.Create(    
    @"C:\windows\Performance\WinSat\winsat.wmv");
  // Part 2 - Create a task, specify encoding details
  Console.Clear();
  IJob job = mediaContext.Jobs.CreateJob("Sample Job");
  var expressionEncoder = mediaContext.MediaProcessors.Where(
    mp => mp.Name == "Expression Encoder").Single();
  var task = job.Tasks.Add(
    mediaProcessor: expressionEncoder,
    configuration: "H.264 HD 720p VBR");
  task.Inputs.Add(asset);
  task.Outputs.Add("Sample Task Output Asset");
  // Part 3 - Submit the encoding job to begin processing
  while (job.State != JobState.Finished)
  {
    job = mediaContext.Jobs.Refresh(job.Id);
    Console.SetCursorPosition(0, 0);
    Console.WriteLine("Job Name: " + job.Name);
    Console.WriteLine("Job ID: " + job.Id);
    Console.WriteLine();
    Console.WriteLine("Job State: {0,-20}", job.State);
    Console.WriteLine("Task Progress: {0:0.00}%  ",
      job.Tasks.Single().Progress);
    Thread.Sleep(500);
  }
  Console.WriteLine();
  Console.WriteLine("Job Complete!");
  Console.ReadLine();
}
// Part 4 - Display completion progress (See Part 1, where the callback was set up)
static void Assets_OnUploadProgress(object sender, 
  UploadProgressEventArgs e)
{
  Console.WriteLine(e.Progress);
}

Figure 4 explains the code in Figure 3 according to the sections labeled Part 1 through Part 4.

Figure 4 Comments for Source Code in Figure 3 (See Parts 1-4)

Part 1

This code accomplishes three basic goals:

   1. Creates a CloudMediaContext object, providing credentials to authenticate against the Media Services. This context is used throughout the rest of the code to manage and process the media assets.

  2. Sets up the callback code called Assets_OnUploadProgress, which is used to report back to the user the percentage completion of the uploading process.

  3. Uploads the original video file (winsat.wmv) so that it can be processed.

Note: The terminology used here is “assets,” which, in this case, refers to the original video.

Part 2 The goal of this code is to create a task, which comprises a media processor, a configuration, and inputs and outputs. Note that encoding is done with the configuration setting of “H.264 HD 720p VBR.” We’ll use Microsoft Expression Encoder. Additional media processors will be available as additional media industry partners add value on top of Media Services.
Part 3 This is where the actual processing begins. You can think of a job as being a workflow with a set of tasks. Tasks can be chained together and they can be run in parallel.
Part 4 This code is simply the callback that gets executed automatically during the video upload process. It’s typically used to report back the percentage completion of the upload process.

Managing Content

One of the challenges of managing video-based projects is keeping track of all the assets, jobs and tasks. Producing content often involves dozens of original files and potentially hundreds more created as the encoded output. Being able to track and locate a specific item for additional processing can be a daunting experience. Automating this process with standard interfaces is a game changer. The management interface in Media Services will open the door for greater collaboration among stakeholders, making it possible to coordinate long-running workflows much more efficiently. The CloudMediaContext object provides an intuitive interface to locate any of the elements associated with the workflow, organized as a series of collections that can be queried using common libraries, such as LINQ.

The code in Figure 5 demonstrates the ability to loop through the assets and display information about video files as well as other file types, such as images. Note that the context object has a collection of Assets and that an Asset object has a collection of File objects.

Figure 5 Various Assets Associated Within an Account

static void Main(string[] args)
{
  // Part 1 - Connect to Media Services
  //          Loop through assets, displaying file information
  CloudMediaContext mediaContext = 
    new CloudMediaContext("[ ACCOUNT NAME ]",
    "[ ACCOUNT KEY ]");
  Console.WriteLine("ASSET INFORMATION");
  foreach (IAsset asset in mediaContext.Assets)
  {
    // Display the collection of assets.
    Console.WriteLine("Asset ID: " + asset.Id);
    Console.WriteLine("Name: " + asset.Name);
    // Display the files associated with each asset.
    foreach (IFileInfo fileItem in asset.Files)
    {
      Console.WriteLine("File Name: " + fileItem.Name);
      Console.WriteLine("File Create Date: " + fileItem.Created);
      Console.WriteLine("File Size: " + fileItem.ContentFileSize);
    }
  }
}

The code in Figure 6 illustrates the ability to perform LINQ queries to search for specific assets. Keeping in mind that thousands of files are potentially being managed, search functionality like this can be a tremendous help.

Figure 6 The Amazing Simplicity of LINQ When Searching for Assets Using a Name or ID

// Returns an asset, given an asset name
static IAsset GetAssetNameFromContext(
  CloudMediaContext mediaContext, string assetName)
{
  IAsset asset = mediaContext.Assets.Where(a => a.Name ==
    assetName).FirstOrDefault();
  if (asset != null)
    return asset;
  else
    return null;
}
// Returns an asset, given an asset Id
static IAsset GetAssetIdFromContext(
  CloudMediaContext mediaContext, string assetId)
{
  IAsset asset = mediaContext.Assets.Where(a => a.Id ==
    assetId).FirstOrDefault();
  if (asset != null)
    return asset;
  else
    return null;
}

Access Policies

Controlling which users can view and access specific assets is a built-in ability of the framework for Media Services. To control security rights, owners of the content can programmatically specify an access policy, where details such as read/write permissions, as well as how long the access will be available, are specified. These are powerful capabilities in the context of sharing workflows with other video stakeholders.

This section shows how to perform basic tasks with access policies, such as creating and assigning them to an asset, as well as listing the ones already created. The purpose of the code in Figure 7 is to set up a “read” policy, allowing the video to be accessed for only 30 minutes. The code starts by uploading winsat.wmv. From there, a new access policy is created, called CanReadFor30Minutes, which means the file can be read only within 30 minutes of the upload process. The next step is to link the access policy to the uploaded video file.

Figure 7 Temporarily Exposing Some Video for Download

static void Main(string[] args)
{
  // Part 1 - Specify an asset to upload
  //          Connect to Media Services
  string inputFilePath =
    @"C:\windows\Performance\WinSat\winsat.wmv";
  CloudMediaContext mediaContext =
    new CloudMediaContext("[ ACCOUNT NAME ]", "[ ACCOUNT KEY ]");
  // Part 2 - Upload an asset
  //          Create a policy for the asset
  //          Link access policy to asset
  IAsset asset = mediaContext.Assets.Create(inputFilePath);
  // Because this is a single-file asset, get the name of first file.
  string fileName = asset.Files[0].Name;
  IAccessPolicy readPolicy = mediaContext.AccessPolicies.Create(
    "CanReadFor30Minutes",
    TimeSpan.FromMinutes(30),
    AccessPermissions.Read);
  // Part 3 - Define a locator based on the read policy
  //          and expiration date
  //          Print the path for the locator you created
  //          Get the locator path Uri
  //          Build the full path to the file associated
  //          with the locator.
  ILocator locator = mediaContext.Locators.CreateSasLocator(
    asset, readPolicy);
  Console.WriteLine("Locator path: " + locator.Path);
  var uriBuilder = new UriBuilder(locator.Path);
  uriBuilder.Path += Path.AltDirectorySeparatorChar + fileName;
  Uri fullUrl = uriBuilder.Uri;
  // Part 4 - Print the full path to the file
  Console.WriteLine("Full URL to file: " + fullUrl);
}

A locator is a persistent copy of the policy file whose location is expressed as a URI. The locator allows access to the asset under the terms specified by the policy. In this case, in order to access the asset (the uploaded video) within the 30-minute time limit, we need to use the full URL, along with the locator file. See fullUrl in Figure 7.

Downloading Processed Assets

Finally, the purpose of the code in Figure 8 is to download the video content to local storage. In this case, the file winsat.mp4 is the H.264-encoded output, generated from the original video stored as winsat.wmv. You can call the function like this:

DownloadAsset("nb:cid:UUID:a0297fe4-7080-4393-b874-7ddf0f759c40", @"c:\temp");

Figure 8 Downloading Assets from Azure Media Services

static void DownloadAsset(string assetId, 
    string outputMediaFilesFolder)
{
  // Part 1 - Connect to Media Services
  //          Get an existing asset based on assetId passed in.
  CloudMediaContext mediaContext =
    new CloudMediaContext("[ ACCOUNT NAME ]","[ ACCOUNT KEY ]");
  IAsset asset = mediaContext.Assets.Where(a => a.Id ==
    assetId).SingleOrDefault();
  // Part 2 - If the asset exists, download the first file in the asset
  //          Download to outputMediaFilesFolder      
  if (asset != null)
  {
    Console.WriteLine("Asset name: " + asset.Name);
    IFileInfo theFile = asset.Files.FirstOrDefault();
    // You could iterate through the asset.Files collection with a
    // foreach statement, and download all files for assets that
    // have multiple files.
    // Example: foreach(IFileInfo file in asset.Files)
    // Download the file to the specified local folder.
    if (theFile != null)
      theFile.DownloadToFile(Path.GetFullPath(outputMediaFilesFolder +
        Path.DirectorySeparatorChar + theFile.Name));
    else
      Console.WriteLine("No files available for this asset.");
  }
  else
  {
    Console.WriteLine("Asset not available.");
  }
}

The assetId of winsat.mp4 is nb:cid:UUID:a0297fe4-7080-4393-b874-7ddf0f759c40. It’s a simple case of requesting the downloadable resource by its assetId and specifying a destination folder for downloading.

Cloud Computing Benefits

Wrapping up, the Media Services features of Azure simplify the process of encoding and distributing video content to multiple devices or Web channels that require different formats and resolutions. This is achieved by leveraging the benefits that cloud computing offers, including compute and storage scalability based on variable demand. This, along with a rich REST-based API and .NET client library, facilitate the process of creating, managing and maintaining workflows that can be enhanced with components created in a vast partner ecosystem.

Media Services represent a giant leap forward in the production, management and delivery of video content, allowing you to automate and pull together a wide variety of digital assets and organize them in a centralized location or even distributed locations. As video is poised for phenomenal growth on the Web over the next few years, Media Services come at a perfect time.

Later we’ll cover the REST API in detail as well as some of the third-party support for custom encoders and high-end capabilities.


Bruno Terkaly is a developer evangelist for Microsoft. His depth of knowledge comes from years of experience in the field, writing code using a multitude of platforms, languages, frameworks, SDKs, libraries and APIs. He spends time writing code, blogging and giving live presentations on building cloud-based applications, specifically using the Azure platform.

Ricardo Villalobos is a seasoned software architect with more than 15 years of experience designing and creating applications for companies in the supply chain management industry. Holding different technical certifications, as well as an MBA in supply chain management from the University of Dallas, he works as an Azure architect evangelist for Microsoft.

Thanks to the following technical experts for reviewing this article: John Deutscher, Samuel Ng and Tim Teebken