Wrapcode

Windows Azure Media Services, Convert MP4 to smooth streaming format.

| 12 min read

Windows Azure, a rock solid cloud platform.

Windows Azure is not "just another cloud service". It lets you develop cloud applications with the variety of tools, languages or framework. Well, I assume you are already familiar with Windows Azure. Let's get familiar with Windows Azure Media Services.

Windows Azure Media Services Architecture

Windows Azure Media Services provides several media technologies from Microsoft Media platform and third party media partners such as encoding, format conversion, content protection, on-demand and live streaming facilities.

[caption id="attachment_639" align="aligncenter" width="600"] Windows Azure Media Services Windows Azure Media Services[/caption]

Windows Azure Media Services
  1. Ingest
  2. Encoding and Format Conversion
  3. Content Protection
  4. On-Demand Sharing
  5. Live Streaming
  6. Analytics (Coming soon)

The Workflow

In general, there are four types of operations are involved while working with media assets. Windows Azure Media Services provides full support for the following four operations that makes application workflow

Ingest

Brings assets to system i.e. Upload media content to cloud.

Process

This involves encoding, format conversion and generating media assets.

Manage

This operation manages the assets that are already present in system / Media Services. Operations such as listing, editing, deleting assets.

Deliver

Gets your media content back out of Media Services. This includes delivery of media on demand, deploying media to Azure CDN

Prerequisites

Before you begin, make sure you have following prerequisites.

  • Windows Azure account along with Media Services feature enabled
  • Operating System : Windows 7 or later
  • .NET framework 4 or later
  • Visual Studio 2010 SP1 or later (Visual Studio 2012 Recommended)
  • MediaServices package installed on Visual Studio (Get it from here : http://nuget.org/packages/windowsazure.mediaservices) Before we begin, I would love to clarify one thing. I am only going to explain how to use the media services operations with a very simple demo code. It is okay to use it in your application, however I will recommend you to keep it only as a reference code and make improvements over it.

Setting up a project

  1. Create a project in VS2012 or VS2010SP1 (C# Console application or Windows Forms applications)
  2. Add references to the following Microsoft.WindowsAzure ** Microsoft.WindowsAzure.StorageClient** ** Microsoft.WindowsAzure.MediaServices.Client** ** System.Configuration**
  3. Import following libraries to your project (Program.cs in my case)[code lang="csharp"] using System; using System.Linq; using System.Configuration; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using Microsoft.WindowsAzure.MediaServices.Client;[/code]

Declaring keys

We will need to declare Azure Media Services keys in order to connect to Media Context later on.

How to create a Media Service Account?

Go through this article to know more about how to create a Media Service Account -> http://www.windowsazure.com/en-us/manage/services/media-services/how-to-create-a-media-services-account/

From where should I get Azure Media Services Key?
  1. Go to : https://manage.windowsazure.com/#Workspace/MediaServicesExtension/MediaServices
  2. Click on Manage Keys present at footer.
  3. Copy Account name and Key After retrieving account name and key (either primary or secondary, both works), declare them in your program.

[code lang="csharp"] //Declaring account name and key private static string accName = "YOUR ACCOUNTNAMEHERE"; private static string accKey = "YOURACCOUNTKEYHERE"; [/code]

Declaring Cloud Context and Directory Paths

Now we need to declare context from which Microsoft Windows Azure Media Services can be accessed. Write this down just below Account name and key

[code lang="csharp"] //Declare cloud contenxt private static CloudMediaContext mediaContext = null; [/code]

Now declare the input and output directories. Input directory is a directory from where the program will pick up MP4 video and output directory is where the program will generate text file with stream ready link (and a smooth streaming video file probably)

[code lang="csharp"] //Input and output path for video.. private static string inputFolder= Path.GetFullPath(@"D:\input\sample.mp4"); private static string outFolder= Path.GetFullPath(@"D:\output"); private static string mp4Configuration= Path.GetFullPath(@"D:\input\mp4smooth.xml"); [/code]

mp4Configuration is a task preset for Windows Azure Media Packager. We will discuss about it later on. Let's move on the the next part of this article

Connect to Media Services

Enough declaration and initialization, let's connect to Media Services. We can connect to Media Services using CloudMediaContext Inside your main function write this code down

[code lang="csharp"] static void Main(string[] args) { //connect to cloud media context _context = new CloudMediaContext(accName, accKey);

[/code]

accName and accKey refers to the account Name and Key we have declared earlier. We could directly put them here but best practice is to declare it first.

Encoding content

Let's create a new function which will encode media file (MP4 in this case) with the help of following steps:

  1. Create a new function, let's call it MediaEncoding
  2. Creating an asset
  3. Creating a new job
  4. Retrieve Media Processor
  5. Create a new task and add it to job
  6. Add an asset to a task
  7. Add new Output asset
  8. Submit a job
Create a new function, MediaEncoding

Let's create a new function MediaEncoding, which will perform all the processes as stated above. This function will take three parameters. Input media file path, destination folder and a mp4 configuration task preset. Function definition will look like

[code lang="csharp"] static void MediaEncoding(string mediaConfig, string outputFolder, string inputMediaFilePath) {

} [/code]

Now, make sure download mp4smooth.xml task preset and paste it in  D:\input\mp4smooth.xml. (Learn more about task presets : http://msdn.microsoft.com/en-us/library/hh973635.aspx)

[scbutton link="http://dl.dropbox.com/u/14849194/mp4smooth.xml" target="blank" variation="green" size="large" ]Download MP4Smooth.Xml[/scbutton]

Since we have created a new function, we need to call it from our main function. The mail function becomes

[code lang="csharp"]

static void Main(string[] args) { //connect to cloud media context _context = new CloudMediaContext(accName, accKey); MediaEncoding(configFilePath, outputPath, inputPath); [/code]

Creating an asset

Before uploading anything on a Media Services server, you will have to create a new asset. There are different approaches of creating a new asset. But it is a good practice to always create an empty asset first. We will write another function for creating assets which returns assets.

[code lang="csharp"] static public IAsset CreateAssetAndUploadSingleFile( AssetCreationOptions assetCreationOptions, string singleFilePath) { var assetName = "UploadSingleFile_" + DateTime.UtcNow.ToString(); var asset = mediaContext.Assets.Create(assetName, assetCreationOptions);

var fileName = Path.GetFileName(singleFilePath);

var assetFile = asset.AssetFiles.Create(fileName);

Console.WriteLine("Created assetFile {0}", assetFile.Name);

var accessPolicy = _context.AccessPolicies.Create(assetName, TimeSpan.FromDays(30),
                                                    AccessPermissions.Write | AccessPermissions.List);

var locator = _context.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy);

Console.WriteLine("Upload {0}", assetFile.Name);

assetFile.Upload(singleFilePath);
Console.WriteLine("Done uploading of {0} using Upload()", assetFile.Name);

return asset;

} [/code]

Since function CreateAssetAndUploadingSingleFile returns asset (IAsset), So we catch the returned asset in a new Asset.

[code lang="csharp"] static void MediaEncoding(string configFilePath, string outputFolder, string inputMediaFilePath) {

 string configuration = File.ReadAllText(Path.GetFullPath(configFilePath));

 IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted, inputMediaFilePath);

}

[/code]

Creating a new job

Job is collection of one or more tasks. Since encoding is a task, we need to create job so that the task can be assigned to it. Creating a job is simple one line code. IJob job = mediaContext.Jobs.Create("My encoding job"); This will create a new job with the name "My encoding job".

Get a media processor

We must specify media processor to handle the job. Media processor is a component that handles media processing tasks such as encoding, format conversion, encryption and decryption. By the time of writing this article, there are four types of processors available. Windows Azure Media Encoder, Windows Azure Media Packager, Windows Azure Media Encryptor and Storage Decryption. We will use following code to create a media processor. We need to call this function and pass one of four processor name as a string. Here's the function for retrieving media processor

[code lang="csharp"] private static IMediaProcessor GetLatestMediaProcessorByName(string mediaProcessorName) { // The possible strings that can be passed into the // method for the mediaProcessor parameter: // Windows Azure Media Encoder // Windows Azure Media Packager // Windows Azure Media Encryptor // Storage Decryption

var processor = _context.MediaProcessors.Where(p => p.Name == mediaProcessorName).
    ToList().OrderBy(p => new Version(p.Version)).LastOrDefault();

if (processor == null)
    throw new ArgumentException(string.Format("Unknown media processor", mediaProcessorName));

return processor;

} [/code]

To call this function, simply add following line in MediaEncoding  function just after declaring a new job. IMediaProcessor processor = GetLatestMediaProcessorByName("Windows Azure Media Packager"); MediaEncoding function will look like this :

[code lang="csharp"] static void MediaEncoding(string configFilePath, string outputFolder, string inputMediaFilePath) {

 string configuration = File.ReadAllText(Path.GetFullPath(configFilePath));

 IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted, inputMediaFilePath);

 IJob job = mediaContext.Jobs.Create("My encoding job");

 IMediaProcessor processor = GetLatestMediaProcessorByName("Windows Azure Media Packager");

} [/code]

Create and add a new task to a Job and Launch it

To encode a media file we need to assign a new task with encoding details, including processor specification, task preset configuration. ITask task = job.Tasks.AddNew("My Mp4 to Smooth Task", processor, configuration, TaskOptions.ProtectedConfiguration); Then we need to specify input asset to be loaded in task task.InputAssets.Add(asset); Then add an output asset which will contain output result. task.OutputAssets.AddNew("Output asset", true, AssetCreationOptions.None); Now, Launch the job using following statement job.Submit(); The MediaEncoding function looks like this all together

[code lang="csharp"] static void MediaEncoding(string configFilePath, string outputFolder, string inputMediaFilePath) {

 string configuration = File.ReadAllText(Path.GetFullPath(configFilePath));

 IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted, inputMediaFilePath);

 IJob job = mediaContext.Jobs.Create("My encoding job");

 IMediaProcessor processor = GetLatestMediaProcessorByName("Windows Azure Media Packager ");

ITask task = job.Tasks.AddNew("My Mp4 to Smooth Task", processor, configuration, TaskOptions.ProtectedConfiguration);

task.InputAssets.Add(asset);

task.OutputAssets.AddNew("Output asset", true, AssetCreationOptions.None);

job.Submit(); } [/code]

Checking status of a job won't hurt

This is purely optional but good to have feature. No matter whether if you are using a local hardware or a cloud,** Encoding takes some time**. How about writing a function that will show you the current status of your job?  You can make use of it in Windows Forms applications as well. Nothing fancy, you just have to add the following function in your code and call it from MediaEncoding function.

[code lang="csharp"] private static void CheckJobProgress(string jobId) { // Flag to indicate when job state is finished. bool jobCompleted = false; // Expected polling interval in milliseconds. Adjust this // interval as needed based on estimated job completion times. const int JobProgressInterval = 10000; while (!jobCompleted) { // Get an updated reference to the job in case // reference gets 'stale' while thread waits. IJob theJob = GetJob(jobId); // Check job and report state. switch (theJob.State) { case JobState.Finished: jobCompleted = true; Console.WriteLine(""); Console.WriteLine("****"); Console.WriteLine("Job state is: " + theJob.State + "."); Console.WriteLine("Please wait while local tasks complete..."); Console.WriteLine(); break; case JobState.Queued: case JobState.Scheduled: case JobState.Processing: Console.WriteLine("Job state is: " + theJob.State + "."); Console.WriteLine("Please wait..."); Console.WriteLine(); break; case JobState.Error: // Log error as needed. break; default: Console.WriteLine(theJob.State.ToString()); break; } // Wait for the specified job interval before checking state again. Thread.Sleep(JobProgressInterval); }

} [/code]

The MediaEncoding function will look like this.

[code lang="csharp"] static void MediaEncoding(string configFilePath, string outputFolder, string inputMediaFilePath) {

 string configuration = File.ReadAllText(Path.GetFullPath(configFilePath));

 IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted, inputMediaFilePath);

 IJob job = mediaContext.Jobs.Create("My encoding job");

 IMediaProcessor processor = GetLatestMediaProcessorByName("Windows Azure Media Packager");

ITask task = job.Tasks.AddNew("My Mp4 to Smooth Task", processor, configuration, TaskOptions.ProtectedConfiguration);

task.InputAssets.Add(asset);

task.OutputAssets.AddNew("Output asset", true, AssetCreationOptions.None);

job.Submit();

CheckJobProgress(job.Id);

} [/code]

Accessing media content directly from an Origin server

There are many alternative approaches to retrieve encoded media content. But since I assume you will be using smooth streaming video basically for Web Media players or windows 8 video app, We will directly get streaming URL from Origin locator.

[code lang="csharp"]

static void GetStreamingOriginLocator(IAsset assetToStream) {

// Get a reference to the asset you want to stream. var theManifest = from f in assetToStream.AssetFiles where f.Name.EndsWith(".ism") select f;

IAssetFile manifestFile = theManifest.First();

IAccessPolicy policy = null;

// Create a 30-day readonly access policy. policy = mediaContext.AccessPolicies.Create("Streaming policy", TimeSpan.FromDays(30), AccessPermissions.Read);

// Create a locator to the streaming content on an origin. ILocator originLocator = null;

originLocator = mediaContext.Locators.CreateLocator(LocatorType.OnDemandOrigin, assetToStream, policy, DateTime.UtcNow.AddMinutes(-5));

// Display some useful values based on the locator. // Display the base path to the streaming asset on the origin server. Console.WriteLine("Streaming asset base path on origin: "); Console.WriteLine(originLocator.Path);

// Create a full URL to the manifest file. Use this for playback // in streaming media clients. string urlForClientStreaming = originLocator.Path + manifestFile.Name + "/manifest";

Console.WriteLine("URL to manifest for client streaming: "); Console.WriteLine(urlForClientStreaming);

// Display the ID of the origin locator, the access policy, and the asset. Console.WriteLine("Origin locator Id: " + originLocator.Id); Console.WriteLine("Access policy Id: " + policy.Id); Console.WriteLine("Streaming asset Id: " + assetToStream.Id);

}

[/code]

Basically, in this function we get a reference from manifest file in asset (file with an extension ".ism"). Then we define access policy (Learn more about Access Policy HERE). Access Policy determines time duration for accessing asset and given permissions.

Then we create a new Origin Locator with the help of CreateLocator method. We pass the method an existing asset with streaming media files, an access policy, and a start time.

Finally we build manifest URL.

Just call this function after CheckJobProgress(job.Id); with outputAsset as a parameter.

[code lang="csharp"]

// Get a reference to the output asset from the job. IAsset outputAsset = job.OutputMediaAssets[0];

GetStreamingOriginLocator(outputAsset);

}

[/code]

Write the Stream ready URL to file

Finally, we would like to write down the streaming URL to a file. To perform a file write operation, prepare a output file path and store it in some variable, say outFilePath.

[code lang="csharp"]

var fileName = Path.GetFileName(inputPath); string outFilePath = Path.GetFullPath(outputPath + @"" + fileName + "StreamingUrl.txt"); WriteToFile(outFilePath, urlForClientStreaming);

[/code]

WriteToFile is a function that takes parameters output file path and stream ready URL.

[code lang="csharp"]

static void WriteToFile(string outFilePath, string fileContent) { StreamWriter sr = File.CreateText(outFilePath); sr.Write(fileContent); sr.Close(); }

[/code]

Summary

Run the code with sample mp4 file as an input. You'll get a text file with streaming URL. You can use the URL in HTML5 Video (with Player Framework), Silverlight. You are good to go

As you know this is just a part of Azure Media Services. You can do a lot with Media Services. Well, this is just a start. Smooth streaming and HTML5 will hopefully make flash and Silverlight obsolete for the good of Internet.

Courtesy