domingo, 30 de septiembre de 2012

Windows Azure MEDIA SERVICES. In action !!!

MediaServicesArch

De la misma manera que el el post anterior exprimíamos Windows Azure MOBILE SERVICES, en este caso le toca el turno a Windows Azure MEDIA SERVICES.

Pues bien, estos recientes servicios (PaaS), aun en Preview, tienen como finalidad, facilitar, crear y entregar contenido multimedia a los diferentes dispositivos: HTML5, Silverlight, Flash, Windows (Windows 8, etc.), Windows Phone, Xbox, MacOS, iPhone/iPad y Android, aportando gracias a Windows Azure, flexibilidad, escalabilidad y fiabilidad en la nube y, todo ello basado en “Microsoft Media Platform”.

Y como siempre, Microsoft pone a nuestra disposición unos mágnificos tutoriales, donde poder seguir nuestros primeros pasos. Nosotros iremos un poco más allá hasta completar un ejemplo completo y funcional además de aclarar dudas y seguir algunas recomendaciones.

 

MEDIA SERVICES soporta los siguientes escenarios:

Una vez ya conocemos las aspectos generales, veamos a continuación lo que necesitamos para llevar a cabo nuestro ejemplo: “MyFirstMedia Services”

1. Activamos el servicio para usarlo con nuestra subscripción.

2. Creamos un servicio desde la consola de administración (Portal):

imageimage

3. Aseguramos la sincronización de “key” con nuestro storage:

image

4. Creamos, desde Visual Studio un proyecto de tipo Consola

5. Añadimos las siguientes referencias.

6.  Conectamos con Media Services obteniendo un Contexto.  En este punto podemos obtener el siguiente error: ”Error 400 Bad Request when using CloudMediaContext with Azure Media Services” si no se introducen correctamente estos parámetros:

   1: this._context = new CloudMediaContext(accountName, accountKey);

Donde:



7. Creamos y encriptamos nuestro activo y lo subimos al Storage de Windows Azure, obteniendo una referencia al container de dichos ficheros. Si el valor de encriptación es “None”, podremos ver el contenido de dichos ficheros una vez realizado el “Upload” utilizando por ejemplo, “Azure Storage Explorer”.



   1: private IAsset UpLoadFiles(string[] files)
   2: {
   3:     // (2) Creamos un asset y añadimos los activos/ficheros para hacer el Upload del asset.            
   4:     return this._context.Assets.Create(files, AssetCreationOptions.StorageEncrypted);
   5: }

En este punto podremos obtener el error: “Could not load file or assembly 'Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)” que podemos resolver (gracias al cable de John) incluyendo en nuestro “.config” el siguiente código:



   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <runtime>
   4:      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
   5:        <dependentAssembly>
   6:          <assemblyIdentity name="Microsoft.WindowsAzure.StorageClient"
   7:                            publicKeyToken="31bf3856ad364e35"
   8:                            culture="neutral" />
   9:          <bindingRedirect oldVersion="1.1.0.0"
  10:                           newVersion="1.7.0.0"/>
  11:        </dependentAssembly>
  12:        <dependentAssembly>
  13:          <assemblyIdentity name="Microsoft.WindowsAzure.StorageClient"
  14:                            publicKeyToken="31bf3856ad364e35"
  15:                            culture="neutral" />
  16:          <publisherPolicy apply="no" />
  17:        </dependentAssembly>
  18:  
  19:      </assemblyBinding>
  20:    </runtime>  
  21: </configuration>

Una vez todo ya podemos hacer el Upload de nuestro asset, ahora ya estos listo para lanzar el Job con el Encoding adecuado:



   1: public IJob CreateEncodingJob(IAsset asset, EnumMediaProcessor enumProcesor)
   2: {
   3:     // Declarar un nuevo Job.
   4:     IJob job = this._context.Jobs.Create("My encoding job");          
   5:  
   6:     string configuration = GetConfiguration(enumProcesor);
   7:     IMediaProcessor processor = this.GetMediaProcessor(enumProcesor);
   8:  
   9:  
  10:     // Crea un tarea con el detalle de codificacion(enconding) utilizando un string preestablecido.
  11:     // Strings preestablecidos para Windows Azure Media Encoder: http://msdn.microsoft.com/en-us/library/jj129582.aspx
  12:     ITask task = job.Tasks.AddNew("My encoding task",
  13:         processor,
  14:         configuration,
  15:         TaskCreationOptions.None);
  16:  
  17:     // Especificar el Asset a codificar
  18:     task.InputMediaAssets.Add(asset);
  19:  
  20:     
  21:     // Añade un asset de salida que contiene el resultado del job.
  22:     // Este asset no es encriptado "AssetCreationOption.None"
  23:     task.OutputMediaAssets.AddNew("Output asset",
  24:         true,
  25:         AssetCreationOptions.None);
  26:  
  27:     // Ejecutar el Job. 
  28:     job.Submit();
  29:  
  30:     return job;
  31: }

En este punto, tenemos que tener claras varias cosas:




   1: // http://www.windowsazure.com/en-us/develop/net/how-to-guides/media-services/
   2: // Windows Azure Media Encoder:  Media Encoder. 
   3: // PlayReady Protection Task:   PlayReady Protection. 
   4: // MP4 to Smooth Streams Task:  Conversión de  .mp4 a formato smooth streaming. 
   5: // Smooth Streams to HLS Task:  Conversión de smooth streaming a formato Apple HTTP Live Streaming (HLS). 
   6: // Storage Decryption:          Desencripta los assets que has sindo encriptados usando Storage Encription. 
   7: private IMediaProcessor GetMediaProcessor(EnumMediaProcessor mediaProcessor)
   8: {
   9:     var theProcessor =
  10:         from p in this._context.MediaProcessors
  11:         where p.Name == mediaProcessor.GetStringValue()
  12:         select p;
  13:  
  14:     IMediaProcessor processor = theProcessor.First();
  15:  
  16:     if (processor == null)
  17:     {
  18:         throw new ArgumentException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
  19:             "Unknown processor",
  20:             mediaProcessor));
  21:     }
  22:     return processor;
  23: }

Si el Job ha terminado correctamente nuestra aplicación cliente podría acceder al asset y descargarlo. No obstante se puede producir erres durante la la codificación, donde para ello, haremos un chequeo del Job para corroborar su estado:



   1: private static ReadOnlyCollection<ErrorDetail> CheckJobProgress(string jobId)
   2: {
   3:     bool jobCompleted = false;
   4:     ReadOnlyCollection<ErrorDetail> jobErrors = null;
   5:  
   6:     while (!jobCompleted && (null == jobErrors))
   7:     {
   8:         IJob theJob = _manager.GetJob(jobId);
   9:         switch (theJob.State)
  10:         {
  11:             case JobState.Finished:
  12:                 jobCompleted = true;
  13:                 break;
  14:             case JobState.Queued:
  15:             case JobState.Scheduled:
  16:             case JobState.Processing:
  17:                 Thread.Sleep(5000);
  18:                 Console.Write(".");
  19:                 break;
  20:             case JobState.Error:
  21:                 jobErrors = theJob.Tasks[0].ErrorDetails;
  22:                 break;
  23:             default:
  24:                 Console.WriteLine("Unknown job state: {0}", theJob.State.ToString());
  25:                 break;
  26:         }
  27:     }
  28:     return jobErrors;
  29: }

A pesar de tener en cuenta las recomendaciones anteriores, se pueden producir algunos errores durante el “Upload” o el “Endonding del Job”




InnerException: System.Data.Services.Client.DataServiceClientException
            HResult=-2146233079
            Message=<?xml version="1.0" encoding="utf-8" standalone="yes"?><error xmlns="
http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><code></code><message xml:lang="en-US">Asset has no files uploaded.</message></error>
            Source=Microsoft.Data.Services.Client
            StatusCode=400
            StackTrace:
                 at System.Data.Services.Client.QueryResult.ExecuteQuery(DataServiceContext context)
                 at System.Data.Services.Client.DataServiceRequest.Execute[TElement](DataServiceContext context, QueryComponents queryComponents)



Donde Fiddler nos proporcional la siguiente información:



  • 500: <?xml version="1.0" encoding="utf-8"?><Error><Code>OperationTimedOut</Code><Message>Operation could not be completed within the specified time.
    RequestId:fc8be06f-1801-4724-a549-14a5d327d48f
    Time:2012-09-23T13:33:32.3638228Z</Message></Error>

  • 504:ReadResponse() failed: The server did not return a response for this request.
  • 502: The socket connection to mediasvc5s9w447krcczl.blob.core.windows.net failed. <br />ErrorCode: 10060. <br />A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 168.63.0.14:80
  • DNS Lookup for "mediasvc5s9w447krcczl.blob.core.windows.net" failed. No such host is known.    

Otros recomendaciones que deberíamos conocer son:




   1: foreach (var a in this._context.Assets)
   2: {
   3:     foreach (var l in a.Locators)
   4:         this._context.Locators.Revoke(l);               
   5:  
   6:         this._context.Assets.Delete(a); 
   7: }



Progreso de carga (“Upload”) de ficheros/assets:



   1: ...
   2:        _manager.Assets.OnUploadProgress += Assets_OnUploadProgress;
   3: ..
   4: rivate static void Assets_OnUploadProgress(object sender, UploadProgressEventArgs e)
   5:  
   6:    try
   7:    {
   8:        Console.WriteLine("Assets_OnUploadProgress: {0:0.00} %, {1}/{2}, {3:0.00} MB/{4:0.00} MB",
   9:        e.Progress, e.CurrentFile, e.TotalFiles, e.BytesSent / 1024 ^ 2, e.TotalBytes / 1024 ^ 2);
  10:    }
  11:    catch (Exception ex)
  12:    {
  13:        Console.WriteLine("OnUploadProgress event error: {0}{1}{2}", ex.Message, Environment.NewLine, ex.StackTrace.ToString());
  14:    }

Progreso de descarga (“Download”):



   1: private static void DownloadAssetToLocal(IAsset outputAsset, string outputFolder)
   2: {
   3:     Console.WriteLine();
   4:     Console.WriteLine("Files are downloading...please wait.");
   5:     Console.WriteLine();
   6:  
   7:     foreach (IFileInfo outputFile in outputAsset.Files)
   8:     {
   9:         outputFile.OnDownloadProgress += outputFile_OnDownloadProgress;
  10:  
  11:         string localDownloadPath = Path.GetFullPath(outputFolder + @"\" + outputFile.Name);
  12:         Console.WriteLine("File is downloading to:  " + localDownloadPath);
  13:         outputFile.DownloadToFile(Path.GetFullPath(outputFolder + @"\" + outputFile.Name));
  14:         Console.WriteLine();
  15:     }
  16: }
  17:  
  18: static void outputFile_OnDownloadProgress(object sender, DownloadProgressEventArgs e)
  19: {
  20:     Console.WriteLine("    Bytes downloaded: " + e.BytesDownloaded);
  21:     Console.WriteLine("    Download progress %:  " + e.Progress);
  22: }

Espero haber conseguido con este recorrido a través de Media Services acercarnos un poco más al mundo Cloud con Windows Azure.



Saludos @Home
Juanlu, ElGuerre

Etiquetas: ,


This page is powered by Blogger. Isn't yours?