using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.MediaServices.Client;
namespace WindowsAzureMediaServicesSample
{
class Program
[STAThread]
static void Main(string[] args)
try
Console.WriteLine("retrieving context");
CloudMediaContext context = new CloudMediaContext(Configuration.AccountName, Configuration.AccountKey);
Console.WriteLine("context is retrieved");
//(new SampleCode2(context)).Show();
//(new SampleCode2(context)).Reset();
(new SampleCode5(context)).Run();
}
catch (Exception ex)
Console.WriteLine("Oops: {0}", ex);
finally
Console.WriteLine("---");
Console.ReadLine();
SampleCode2:
public class SampleCode2
private CloudMediaContext context = null;
public SampleCode2(CloudMediaContext context)
this.context = context;
this.context.Assets.OnUploadProgress += Assets_OnUploadProgress;
public void Show()
Console.WriteLine("--- media processors ---");
foreach (var mp in context.MediaProcessors)
Console.WriteLine("name={0}, Vendor={1}, version={2}", mp.Name, mp.Vendor, mp.Version);
Console.WriteLine();
foreach (var job in context.Jobs)
Console.WriteLine("{0} {1} {2} {3} {4}", job.Name, job.State, job.Created, job.EndTime, job.RunningDuration);
foreach (var t in job.Tasks)
Console.WriteLine("{0} {1}", t.Name, t.State);
foreach (var d in t.ErrorDetails)
Console.WriteLine("\t{0}\t{1}", d.Code, d.Message);
foreach (var p in context.AccessPolicies)
Console.WriteLine("policy Id={0}, name={1}, modified={2}, permissions={3}, duration={4}"
, p.Id, p.Name, p.LastModified, p.Permissions, p.Duration);
foreach (var l in context.Locators)
Console.WriteLine("Id={0}, Path={1}, expires={2}", l.Id, l.Path, l.ExpirationDateTime);
var p = l.AccessPolicy;
public void Reset()
Console.WriteLine("will reset");
job.Delete();
context.Locators.Revoke(l);
context.AccessPolicies.Delete(p);
foreach (var a in context.Assets)
context.Assets.Delete(a);
private void Assets_OnUploadProgress(object sender, UploadProgressEventArgs e)
Console.WriteLine("Assets_OnUploadProgress: {0:0.00} %, {1} / {2}, {3:0.00} MB / {4:0.00} MB",
e.Progress, e.CurrentFile, e.TotalFiles, e.BytesSent / 1024 ^ 2, e.TotalBytes / 1024 ^ 2);
HLSConfiguration.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!-- cf http://msdn.microsoft.com/en-us/library/hh973636.aspx -->
<taskDefinition xmlns="http://schemas.microsoft.com/iis/media/v4/TM/TaskDefinition#">
<name>Smooth Streams to Apple HTTP Live Streams</name>
<id>A72D7A5D-3022-45f2-89B4-1DDC5457C111</id>
<description xml:lang="en">Converts on-demand Smooth Streams encoded with H.264 (AVC) video and AAC-LC audio codecs to Apple HTTP Live Streams (MPEG-2 TS) and creates an Apple HTTP Live Streaming playlist (.m3u8) file for the converted presentation.</description>
<inputDirectory></inputDirectory>
<outputFolder>TS_Out</outputFolder>
<properties namespace="http://schemas.microsoft.com/iis/media/AppleHTTP#" prefix="hls">
<property name="maxbitrate" required="true" value="1600000" helpText="The maximum bit rate, in bits per second (bps), to be converted to MPEG-2 TS. On-demand Smooth Streams at or below this value are converted to MPEG-2 TS segments. Smooth Streams above this value are not converted. Most Apple devices can play media encoded at bit rates up to 1,600 Kbps."/>
<property name="manifest" required="false" value="" helpText="The file name to use for the converted Apple HTTP Live Streaming playlist file (a file with an .m3u8 file name extension). If no value is specified, the following default value is used: <ISM_file_name>-m3u8-aapl.m3u8"/>
<property name="segment" required="false" value="10" helpText="The duration of each MPEG-2 TS segment, in seconds. 10 seconds is the Apple-recommended setting for most Apple mobile digital devices."/>
<property name="log" required="false" value="" helpText="The file name to use for a log file (with a .log file name extension) that records the conversion activity. If you specify a log file name, the file is stored in the task output folder." />
<property name="encrypt" required="false" value="false" helpText="Enables encryption of MPEG-2 TS segments by using the Advanced Encryption Standard (AES) with a 128-bit key (AES-128)." />
<property name="pid" required="false" value="" helpText="The program ID of the MPEG-2 TS presentation. Different encodings of MPEG-2 TS streams in the same presentation use the same program ID so that clients can easily switch between bit rates." />
<property name="codecs" required="false" value="false" helpText="Enables codec format identifiers, as defined by RFC 4281, to be included in the Apple HTTP Live Streaming playlist (.m3u8) file." />
<property name="backwardcompatible" required="false" value="false" helpText="Enables playback of the MPEG-2 TS presentation on devices that use the Apple iOS 3.0 mobile operating system." />
<property name="allowcaching" required="false" value="true" helpText="Enables the MPEG-2 TS segments to be cached on Apple devices for later playback." />
<property name="passphrase" required="false" value="" helpText="A passphrase that is used to generate the content key identifier." />
<property name="key" required="false" value="" helpText="The hexadecimal representation of the 16-octet content key value that is used for encryption." />
<property name="keyuri" required="false" value="" helpText="An alternate URI to be used by clients for downloading the key file. If no value is specified, it is assumed that the Live Smooth Streaming publishing point provides the key file." />
<property name="overwrite" required="false" value="true" helpText="Enables existing files in the output folder to be overwritten if converted output files have identical file names." />
</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>
SampleCode5:
using System.Windows.Forms;
public class SampleCode5
private System.Timers.Timer jobTimer;
private string runningJobId = null;
private bool jobCompleted = false;
private IJob job;
public SampleCode5(CloudMediaContext context)
public void Run()
#region upload or find MP4 initial asset
IAsset asset = null;
if (!Configuration.SampleFile3AlreadyUploaded)
asset = context.Assets.Create(Configuration.SampleFile3LocalPath, AssetCreationOptions.None); // an MP4 file
else
foreach (var f in a.Files)
if (string.Compare(f.Name, Configuration.SampleFile3, false) == 0)
asset = a;
break;
if (asset != null) break;
#endregion
#region submit or find job 1: MP4 => Smooth Streaming
job = context.Jobs.Where(j => j.Name == Configuration.JobNameSampleCode5).SingleOrDefault<IJob>();
if (job == null)
Console.WriteLine("submitting job");
var q = from p in context.MediaProcessors
where p.Name == "Windows Azure Media Encoder"
select p;
IMediaProcessor processor = q.FirstOrDefault<IMediaProcessor>();
if (processor == null)
throw new ApplicationException("media processor for smooth streaming not found");
job = context.Jobs.Create(Configuration.JobNameSampleCode5);
ITask task = job.Tasks.AddNew("sample encoding task",
processor,
"H.264 IIS Smooth Streaming - HD 720p CBR" /* cf http://msdn.microsoft.com/en-us/library/jj129582.aspx */,
TaskCreationOptions.None);
task.InputMediaAssets.Add(asset);
IAsset task1OutputAsset = task.OutputMediaAssets.AddNew(
"Smooth Streaming Output", true, AssetCreationOptions.None);
var q2 = from p in context.MediaProcessors
where p.Name == "Smooth Streams to HLS Task"
IMediaProcessor processor2 = q2.FirstOrDefault<IMediaProcessor>();
if (processor2 == null)
throw new ApplicationException("media processor for HLS task not found");
string hlsConfiguration = File.ReadAllText("HLSConfiguration.xml");
ITask task2 = job.Tasks.AddNew("sample HLS task 2",
processor2, hlsConfiguration,
task2.InputMediaAssets.Add(task1OutputAsset); // start from output assets of previous task
task2.OutputMediaAssets.AddNew("HLS Output", true, AssetCreationOptions.None);
job.Submit();
WaitForJob();
// If the job completes, have the files available for smooth streaming
if (jobCompleted)
Console.WriteLine("publishing smooth streaming and HLS results");
IAccessPolicy streamingPolicy = context.AccessPolicies.Create("Streaming policy",
TimeSpan.FromDays(5), AccessPermissions.Read);
foreach (var outputAsset in t.OutputMediaAssets)
Console.WriteLine("output asset: {0} has {1} file(s)", outputAsset.Name, outputAsset.Files.Count);
foreach (var f in outputAsset.Files.Where(x => x.Name.EndsWith(".ism")))
if (f.Name.Contains("m3u8"))
#region publish HLS to a WAMS origin
Console.WriteLine("will create a new locator for HLS");
IFileInfo manifestFile = f;
ILocator originLocator = context.Locators.CreateOriginLocator(
outputAsset, streamingPolicy, DateTime.UtcNow.AddMinutes(-5));
string urlForClientStreaming = originLocator.Path + manifestFile.Name
+ "/manifest(format=m3u8-aapl)";
Console.WriteLine("URL to manifest for client HSL streaming: ");
Console.WriteLine(urlForClientStreaming);
Clipboard.SetText(urlForClientStreaming);
#region publish smooth streaming to a WAMS origin
string urlForClientStreaming = originLocator.Path + manifestFile.Name + "/manifest";
Console.WriteLine("URL to manifest for client smooth streaming: ");
#region download smooth streaming files locally
//string localFileName = Path.Combine(Configuration.OutputFolder, f.Name);
//Console.WriteLine("Asset {0}, downloading to {1}", outputAsset.Id, localFileName);
//f.OnDownloadProgress += new EventHandler<DownloadProgressEventArgs>(f_OnDownloadProgress);
//f.DownloadToFile(localFileName);
Console.WriteLine("Please check job again later.");
private void WaitForJob()
runningJobId = job.Id;
if (job.State == JobState.Finished)
jobCompleted = true;
Console.WriteLine("");
Console.WriteLine("********************");
Console.WriteLine("Job state is: " + job.State + ".");
Console.WriteLine("task {0} state={1} duration={2}, PerfMessage={3}",
t.Name, t.State, t.RunningDuration, t.PerfMessage);
Console.WriteLine("Job completed successfully.");
return;
// Expected polling interval in milliseconds. Adjust this
// interval as needed based on estimated job completion times.
const int JobProgressInterval = 10000;
// Create a timer with the specified interval, and an event
// to check job progress. This is an optional workaround
// because job progress checking is not currently implemented.
this.jobTimer = new System.Timers.Timer(JobProgressInterval);
// Hook up an event handler.
jobTimer.Elapsed += new System.Timers.ElapsedEventHandler(jobTimer_Elapsed);
jobTimer.Start();
Console.WriteLine("Please wait, checking job status...");
// Wait for timer to elapse.
// After the job progress event, stop timer.
jobTimer.Stop();
// Refresh the reference to the job object.
context.Detach(job);
job = context.Jobs.Where(j => j.Id == runningJobId).SingleOrDefault();
void f_OnDownloadProgress(object sender, DownloadProgressEventArgs e)
Console.WriteLine("Download progress: {0:0.00} %, {1:0.00} MB / {2:0.00} MB",
e.Progress, Convert.ToDouble(e.BytesDownloaded) / (1024 * 1024), Convert.ToDouble(e.TotalBytes) / (1024 * 1024));
void jobTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
//Get a refreshed job reference each time the event fires.
IJob theJob = context.Jobs.Where(j => j.Id ==
runningJobId).SingleOrDefault();
// Check and handle various possible job states.
switch (theJob.State)
case JobState.Finished:
Console.WriteLine("Job state is: " + theJob.State + ".");
foreach (var t in theJob.Tasks)
Console.WriteLine("Press Enter to complete the job.");
case JobState.Queued:
case JobState.Scheduled:
case JobState.Processing:
Console.WriteLine("Continue waiting for the job to complete, or " +
"press Enter in the console to exit without waiting.");
case JobState.Error:
Console.WriteLine("Error:");
Console.WriteLine("task {0} state={1}", t.Name, t.State);
Console.WriteLine("\tdetails:");
//Console.WriteLine("task body: '{0}'", t.TaskBody);
default:
Console.WriteLine(theJob.State.ToString());
// Detach the job to prevent the reference going stale.
context.Detach(theJob);
void Assets_OnUploadProgress(object sender, UploadProgressEventArgs e)
e.Progress, e.CurrentFile, e.TotalFiles,
Convert.ToDouble(e.BytesSent) / (1024 * 1024), Convert.ToDouble(e.TotalBytes / (1024 * 1024)));
…
Benjamin