A simple scenario: Upload, Encode and Package, Stream

What’s going on when I use the Window Azure Portal to encode a job?

The Windows Azure Portal is built on top of the various REST APIs of the underlying Azure components. The presentation layer is HTML5, and uses a mix of REST and the .Net SDKs on the server-side — you could build your own portal to manage your media workflow.
In the next few weeks, under the Media Services tab, we will update the pages to include some simple code snippets that walk you through this simple scenario:

  • Create an Asset and Upload a file
  • Encode to Smooth and Package to HLS
  • Stream to both Smooth and HLS

Here is what is going on in those snippets:

Click through these slowly and try to match the various arrows to the lines of code below.

Main Program:

// Create .Net console app
// Set project properties to use the full .Net Framework (not Client Profile)
// With NuGet Package Manager, install windowsazure.mediaservices
// add: using Microsoft.WindowsAzure.MediaServices.Client;

var context = new CloudMediaContext("your_media_account", "your_media_account_key");

//Slide 1:
string inputAssetId = CreateAssetAndUploadFile(context);

//Slide 2:
IJob job = EncodeAndPackage(context, inputAssetId);

var smoothAsset = job.OutputMediaAssets.FirstOrDefault();
var hlsAsset = job.OutputMediaAssets.LastOrDefault();

//Slide 3:
string smoothStreamingUrl = GetStreamingUrl(context, smoothAsset.Id);
string hlsStreamingUrl = GetStreamingUrl(context, hlsAsset.Id);

Console.WriteLine("\nSmooth Url: \n" + smoothStreamingUrl); Console.WriteLine("\nHLS Url: \n" + hlsStreamingUrl); Console.ReadKey();
//

First slide:

private static string CreateAssetAndUploadFile(CloudMediaContext context) {

var inputFilePath = @"C:\demo\bing_social_search.mp4";

var assetName = Path.GetFileNameWithoutExtension(inputFilePath);

var inputAsset = context.Assets.Create(assetName, AssetCreationOptions.None);

var assetFile = inputAsset.AssetFiles.Create(Path.GetFileName(inputFilePath));

assetFile.UploadProgressChanged += new EventHandler<UploadProgressChangedEventArgs>(assetFile_UploadProgressChanged);
assetFile.Upload(inputFilePath);

return inputAsset.Id;
}

//Monitor progress:
static void assetFile_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e) {
Console.WriteLine(string.Format("{0}   Progress: {1:0}   Time: {2}",
((IAssetFile)sender).Name, e.Progress, DateTime.UtcNow.ToString(@"yyyy_M_d__hh_mm_ss")));
}
//

Second slide:

private static IJob EncodeAndPackage(CloudMediaContext context, string inputAssetId) {

var inputAsset = context.Assets.Where(a => a.Id == inputAssetId).FirstOrDefault();
if (inputAsset == null)
throw new ArgumentException("Could not find assetId: " + inputAssetId);

var encodingPreset = "H264 Smooth Streaming SD 16x9"; // <a href="http://msdn.microsoft.com/en-us/library/windowsazure/jj129582.aspx#H264Encoding">http://msdn.microsoft.com/en-us/library/windowsazure/jj129582.aspx#H264Encoding</a>

IJob job = context.Jobs.Create("Encoding " + inputAsset.Name + " to " + encodingPreset + " and Packaging to HLS");

IMediaProcessor latestWameMediaProcessor = (from p in context.MediaProcessors where p.Name == "Windows Azure Media Encoder" select p).ToList().OrderBy(wame => new Version(wame.Version)).LastOrDefault();

ITask encodeTask = job.Tasks.AddNew("Encoding", latestWameMediaProcessor, encodingPreset, TaskOptions.None);
encodeTask.InputAssets.Add(inputAsset);
encodeTask.OutputAssets.AddNew(inputAsset.Name + " as " + encodingPreset, AssetCreationOptions.None);

var packagingToSmoothConfig = @"<taskDefinition xmlns=""<a href="http://schemas.microsoft.com/iis/media/v4/TM/TaskDefinition#&quot;&quot;><name>Smooth">http://schemas.microsoft.com/iis/media/v4/TM/TaskDefinition#""><name>Smooth</a> Streams to Apple HTTP Live Streams</name><description xml:lang=""en""/><inputDirectory/><outputFolder/><properties namespace=""<a href="http://schemas.microsoft.com/iis/media/AppleHTTP">http://schemas.microsoft.com/iis/media/AppleHTTP</a>#"" prefix=""hls""><property name=""maxbitrate"" value=""10000000"" /><property name=""segment"" value=""10"" /><property name=""encrypt"" value=""false"" /><property name=""pid"" value="""" /><property name=""codecs"" value=""false"" /><property name=""backwardcompatible"" value=""false"" /><property name=""allowcaching"" value=""true"" /><property name=""passphrase"" value="""" /><property name=""key"" value="""" /><property name=""keyuri"" value="""" /><property name=""overwrite"" value=""true"" /></properties><taskCode><type>Microsoft.Web.Media.TransformManager.SmoothToHLS.SmoothToHLSTask, Microsoft.Web.Media.TransformManager.SmoothToHLS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</type></taskCode></taskDefinition>";

IMediaProcessor latestPackagerMediaProcessor = (from p in context.MediaProcessors where p.Name == "Windows Azure Media Packager" select p).ToList().OrderBy(wame => new Version(wame.Version)).LastOrDefault();

ITask packagingTask = job.Tasks.AddNew("Packaging to HLS", latestPackagerMediaProcessor, packagingToSmoothConfig, TaskOptions.None);
packagingTask.InputAssets.Add(encodeTask.OutputAssets[0]);
packagingTask.OutputAssets.AddNew(inputAsset.Name + " encoded and packaged to HLS", AssetCreationOptions.None);

job.StateChanged += new EventHandler<JobStateChangedEventArgs>(JobStateChanged);
job.Submit();
job.GetExecutionProgressTask(CancellationToken.None).Wait();

return job;
}

static void JobStateChanged(object sender, JobStateChangedEventArgs e) {
Console.WriteLine(string.Format("{0}\n  State: {1}\n  Time: {2}\n\n",
((IJob)sender).Name, e.CurrentState, DateTime.UtcNow.ToString(@"yyyy_M_d__hh_mm_ss")));
}
//

Third slide:

(provisioning of the origins is done through the management portal scale page)

private static string GetStreamingUrl(CloudMediaContext context, string outputAssetId) {
var daysForWhichStreamingUrlIsActive = 365;

var outputAsset = context.Assets.Where(a => a.Id == outputAssetId).FirstOrDefault();

var accessPolicy = context.AccessPolicies.Create(outputAsset.Name,
                   TimeSpan.FromDays(daysForWhichStreamingUrlIsActive),
                   AccessPermissions.Read);

var assetFiles = outputAsset.AssetFiles.ToList();

var assetFile = assetFiles.Where(f => f.Name.ToLower().EndsWith("m3u8-aapl.ism")).FirstOrDefault();
if (assetFile != null) {
var locator = context.Locators.CreateLocator(LocatorType.OnDemandOrigin, outputAsset, accessPolicy);

Uri hlsUri = new Uri(locator.Path + assetFile.Name + "/manifest(format=m3u8-aapl)");
return hlsUri.ToString();
}

assetFile = assetFiles.Where(f => f.Name.ToLower().EndsWith(".ism")).FirstOrDefault();
if (assetFile != null) {
var locator = context.Locators.CreateLocator(LocatorType.OnDemandOrigin, outputAsset, accessPolicy);
Uri smoothUri = new Uri(locator.Path + assetFile.Name + "/manifest");
return smoothUri.ToString();
}

assetFile = assetFiles.Where(f => f.Name.ToLower().EndsWith(".mp4")).FirstOrDefault();
if (assetFile != null) {
var locator = context.Locators.CreateLocator(LocatorType.Sas, outputAsset, accessPolicy);
var mp4Uri = new UriBuilder(locator.Path);
mp4Uri.Path += "/" + assetFile.Name;
return mp4Uri.ToString();
}
return string.Empty;
}
//

Now you put that smooth URL into http://smf.cloudapp.net/healthmonitor or the HLS Url into your iOS device, and you’re ready to go.

This entry was posted in Windows Azure Media Services. Bookmark the permalink.