Dash.js y Microsoft Azure Media Services

mpeg-dash
En un post anterior estuve hablando sobre Dynamic Packaging y Microsoft Azure Media Services. En este quería mostraros cómo trabajar con la librería dash.js pensada para la implementación MPEG-DASH. Esta se apoya en la etiqueta video de HTML 5 y utiliza JavaScript para crear un contexto alrededor.

Lo primero que necesitamos es descargar dash.js del siguiente enlace.

Podemos utilizar este código de ejemplo, haciendo uso de la etiqueta video de HTML 5:

<section class="dash">
	<video id="video-dashjs" controls></video>
</section>

<script src="~/Scripts/dash.all.js"></script>
<script src="~/Scripts/App/dash.configuration.js"></script>

<script>window.onload = function(){dashPlayer.play();}</script>

dashPlayer se trata de una clase JavaScript que he creado para encapsular la configuración del reproductor:

var dashPlayer = function (url) {

    var play = function () {

        var mediaURL = "http://[YOUR_MEDIA_ACCOUNT].origin.mediaservices.windows.net/[LOCATOR]/[FILE_NAME].ism/Manifest(format=mpd-time-csf)";

        var context = Dash.di.DashContext();

        var player = new MediaPlayer(context);

        player.startup();
        player.attachView(document.querySelector("#video-dashjs"));
        player.attachSource(mediaURL);

    }

    return {
        play: play
    };

}();

Espero que sea de utilidad.

¡Saludos!

Codificando assets para Microsoft Azure Media Services desde .NET

Otra de las tareas que nos proporciona Azure Media Services es la codificación de los assets que tenemos en nuestra cuenta. Como ya comenté en el post de introducción, es posible llevar a cabo esta tarea a través del propio portal, utilizando el menú inferior (ENCODE):

Además podemos realizar esta misma tarea a través de .NET siguiendo estos pasos:

using Microsoft.WindowsAzure.MediaServices.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EncodingAssets
{
    class Program
    {
        static void Main(string[] args)
        {
            //0. Constants
            const string accountName = "YOUR_ACCOUNT_NAME";
            const string accountKey = "YOUR_ACCOUNT_KEY";
            var assetName = "WOW_Mists_of_Pandaria_MP4";
            var OutputAssetName = "WOW_Mists_of_Pandaria_H264_Smooth";
            var encodingPreset = "H264 Smooth Streaming 720p";

            //1. Nuget: Install-Package windowsazure.mediaservices

            //2. Create context
            CloudMediaContext _context = new CloudMediaContext(accountName, accountKey);

            //3. Get asset
            var asset = _context.Assets.Where(a => a.Name == assetName).FirstOrDefault();

            //4. Declare a job
            var job = _context.Jobs.Create(string.Format("Encoding {0} to {1}", assetName, encodingPreset));

            //5. Get processor
            var processor = _context.MediaProcessors.Where(p => p.Name == "Windows Azure Media Encoder").ToList().OrderBy(wame => new Version(wame.Version)).LastOrDefault();

            //6. Create task 
            var task = job.Tasks.AddNew("Encoding task", processor, encodingPreset, TaskOptions.None);

            //7. Specify the asset
            task.InputAssets.Add(asset);

            //8. Output asset with the result
            task.OutputAssets.AddNew(OutputAssetName, AssetCreationOptions.None);

            //9. Handle to check the progress
            job.StateChanged += StateChanged;

            job.Submit();

            //10. Check job execution and wait for job to finish
            Task progressJobTask = job.GetExecutionProgressTask(CancellationToken.None);
            progressJobTask.Wait();

            //11. Check final status
            Console.WriteLine("Job final state: {0}", job.State);

            Console.ReadLine();
        }

        static void StateChanged(object sender, JobStateChangedEventArgs e)
        {
            Console.WriteLine("Job stated change event:");
            Console.WriteLine("  Previous state: {0}", e.PreviousState);
            Console.WriteLine("  Current state: {0}", e.CurrentState);
        }
    }
}
  1. Constantes necesarias: Cuenta de Azure Media Services, nombre del asset que queremos codificar, nombre del asset resultante, preset que vamos a utilizar (utilizamos el nombre de los que aparecen listados en el portal cuando realizamos la tarea desde allí:
    Presets
  2. Instalamos a través de Nuget Install-Package windowsazure.mediaservices
  3. Conectamos la aplicación con la cuenta.
  4. Recuperamos el asset que queremos codificar. En este ejemplo, estamos recuperamos el asset a través del nombre pero es recomendable recuperarlo a través del Id, ya que el nombre de los assets puede repetirse.
  5. Creamos un job, que será el encargado de gestionar la tarea que vamos a llevar a cabo.
  6. Recuperamos el processor Windows Azure Media Encoder que realizará la tarea de encoding.
  7. Creamos una tarea dentro del job. Podemos tener varias tareas dentro de un job, las cuales se lanzarán de manera secuencial.
  8. Indicamos a la tarea cuál es el asset sobre el que queremos realizar la operación.
  9. Elegimos un nombre para el asset que se creará como resultado.
  10. Asociamos un handler al cambio de estado del job, para conocer cuál es el estado del mismo y lanzamos el job.
  11. Esperamos a que la tarea finalice
  12. Comprobamos el resultado del trabajo una vez finalizado.

Si lanzamos el ejemplo, podremos ver la siguiente salida en la consola:

Encoding output

Desde el portal podemos ver que en la sección CONTENT tenemos un nuevo asset con el nuevo nombre (en este caso WOW_Mists_of_Pandaria_H264_Smooth) y, si lo publicamos a través del menú inferior, veremos que el formato de la URL corresponde con el formato de Smooth Streaming:

http://[ACCOUNT_NAME].origin.mediaservices.windows.net/[LOCATOR_ID]/Mists_of_Pandaria.ism/Manifest

Espero que sea de utilidad.

¡Saludos!

Subir contenido a Microsoft Azure Media Services usando .NET

El primer paso cuando trabajamos con Microsoft Azure Media Services es la ingesta. Como se explicó en la introdución a este servicio, desde el propio portal podemos subir contenido con un tamaño máximo de 200MB o bien copiar archivos existentes en una cuenta de Azure Storage. En este post me gustaría enseñaros cómo es posible realizar la subida a través del SDK de Azure Media Services.

Para este ejemplo, he creado una aplicación de consola y he instalado el SDK a través de Nuget:

PM> Install-Package windowsazure.mediaservices

En el método principal, he enumerado el proceso que debemos seguir para subir todo el contenido que esté incluido en una carpeta:

        static void Main(string[] args)
        {
            Debug("Upload assets to Azure Media Services");

            #region Constants

            const string folderPath = @"H:\wow_trailers\";
            const string accountName = "YOUR_ACCOUNT_NAME";
            const string accountKey = "YOUR_ACCOUNT_KEY";
            const string assetName = "WoW_Asset";

            #endregion

            //1. Nuget: Install-Package windowsazure.mediaservices

            //2.Connect to the media account
            CloudMediaContext _context = new CloudMediaContext(accountName, accountKey);

            //3.Create asset
            var asset = _context.Assets.Create(assetName, AssetCreationOptions.None);

            Debug(string.Format("Asset name: {0}", asset.Name));

            //4. Access policy
            var accessPolicy = _context.AccessPolicies.Create(asset.Name, TimeSpan.FromDays(10), AccessPermissions.Write | AccessPermissions.List);

            Debug(string.Format("Access policy - Duration: {0}", accessPolicy.Duration));

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

            //6. BlobTransferClient
            var blobTransferClient = new BlobTransferClient
            {
                NumberOfConcurrentTransfers = 20,
                ParallelTransferThreadCount = 20
            };

            //7. TransferProgressChanged
            blobTransferClient.TransferProgressChanged += TransferProgressChanged;

            //8.Get files
            var files = Directory.EnumerateFiles(folderPath);

            //9. Preparing upload tasks
            var uploadTasks = new List<Task>();

            foreach (var file in files)
            {
                var assetFile = asset.AssetFiles.Create(Path.GetFileName(file));

                Debug(string.Format("Created asset for the file {0}", assetFile.Name));

                uploadTasks.Add(assetFile.UploadAsync(file, blobTransferClient, locator, CancellationToken.None));
            }

            //10. Wait
            Task.WaitAll(uploadTasks.ToArray());
                        
            Debug("Done!", MessageType.Result);
            
            Console.ReadLine();
        }
  1. Una región con los datos necesarios para la subida (ubicación de los archivos, nombre de la cuenta, clave, nombre del asset).
  2. Instalamos el SDK a través de Nuget.
  3. Conectamos la aplicación con la cuenta de Azure Media Services que vamos a utilizar.
  4. Creamos el asset, que será el contenedor donde se almacenarán los archivos. Hablaremos de ello un poco más tarde.
  5. Definimos la política de acceso. En este caso, hemos decidido que el acceso a este contenido sólo estará disponible durante 10 días para la escritura y listado del contenido.
  6. Creamos un locator, el cual nos proporciona un punto de entrada a los archivos contenidos en el asset.
  7. Instanciamos un objeto del tipo BlobTransferClient, que será utilizado para la subida del contenido.
  8. Al objeto anterior, le asociamos un handler que nos aportará información sobre el estado de la subida.
  9. Recuperamos todos los archivos ubicados en la carpeta seleccionada.
  10. Creamos un listado de tareas y damos de alta una tarea por cada archivo, recorriendo el listado de los mismos en el foreach y creando un AssetFile por cada uno de ellos y la subida a través de UploadAsyn
  11. Una vez que ya tenemos todas las tareas que queremos ejecutar, utilizamos Wait.All pasándole la lista.

El código que se utiliza para el handler TransferProgressChanged es simplemente una trazas que nos avisa del porcentaje completado:

        static void TransferProgressChanged(object sender, BlobTransferProgressChangedEventArgs e)
        {
            Debug(string.Format("{0}% upload completed for {1}", e.ProgressPercentage, e.LocalFile), MessageType.Progress);
        }

Por otro lado, se ha creado un método llamado Debug donde lo único que hago es cambiar el color del texto mostrado por consola en función de un enumerable, que me indica si es Info, Progress o Result:

        static void Debug(string message, MessageType type = MessageType.Info)
        {
            switch (type)
            {
                case MessageType.Info:
                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                    break;
                case MessageType.Progress:
                    Console.ForegroundColor = ConsoleColor.DarkYellow;
                    break;
                case MessageType.Result:
                    Console.ForegroundColor = ConsoleColor.DarkMagenta;
                    break;
                default:
                    break;
            }

            Console.WriteLine();
            Console.WriteLine(message);
        }

Cuando el proceso se haya completado podremos ver el resultado en el apartado CONTENT del portal:

Upload assets content portal

Desde aquí, no podemos comprobar cuántos archivos están incluídos dentro del asset y, además, si publicamos el contenido a través del botón PUBLISH sólamente nos devolverá una de las URLs disponibles. Sin embargo, si accedemos a la cuenta de Microsoft Azure Storage asociada, podemos comprobar que el asset se corresponde un con container y podemos listar el contenido a través del portal:

assets Storage containers

El nombre del container está compuesto por la palabra asset + el id del locator. Si accedemos a cualquiera de ellos, podremos ver los archivos que contiene un asset en concreto:

assetfiles

Un dato que debemos de tener en cuenta es que si tenemos varios archivos dentro de un asset no nos será posible utilizar la acción encode del portal sobre el mismo. Además, como comentaba, cuando hacemos uso de la acción publicar un asset que contiene varios archivos sólo se nos mostrará la URL de uno de ellos. Sin embargo, podemos construir el resto de URLs cambiando el nombre del archivo, como por ejemplo se ve en la siguiente URL:

https://gismedia.blob.core.windows.net/asset-9eaa68f6-adcf-4c57-800c-10c7e8cb04a3/Mists_of_Pandaria.mp4?sv=2012-02-12&sr=c&si=851c919d-0c13-4228-9e5b-1b8ca95fab72&sig=AOOUXluaeRmRkm%2F1Z9DOwh1Qcry4AJWTFZtkd%2Bf%2F8f8%3D&st=2014-08-13T07%3A38%3A07Z&se=2016-08-12T07%3A38%3A07Z

Para poder reproducir el archivo llamado Burning_Crusade.mp4 bastaría con modificar el nombre del archivo en la URL anterior:

https://gismedia.blob.core.windows.net/asset-9eaa68f6-adcf-4c57-800c-10c7e8cb04a3/Burning_Crusade.mp4?sv=2012-02-12&sr=c&si=851c919d-0c13-4228-9e5b-1b8ca95fab72&sig=AOOUXluaeRmRkm%2F1Z9DOwh1Qcry4AJWTFZtkd%2Bf%2F8f8%3D&st=2014-08-13T07%3A38%3A07Z&se=2016-08-12T07%3A38%3A07Z

Espero que sea de utilidad.

Happy clouding!