[Windows 10] HTTP Live Streaming

Introducción

En el desarrollo de nuestras Apps hay ciertos contenidos que los
usuarios aprecian especialmente. Entre el contenido destacado contamos
con el multimedia.

HTTP Live Streaming o HLS es un protocolo de
streaming de contenido multimedia que consiste en segmentar en
diferentes archivos pequeños, cada uno de ellos en diferentes tamaños y
calidades para permitir difundir el contenido con una tasa adaptativa
dependiendo de la calidad de la conexión.

HTTP Live Streaming

Hasta ahora podíamos implementar HLS en nuestras Apps utilizando componentes de terceros como por ejemplo Windows Phone Streaming Media o Player Framework.

Con la llegada de Windows 10 contamos con lo necesario para trabajar con contenido multimedia adaptativo gracias a la clase AdaptiveMediaSource.

Crearemos un nuevo proyecto UAP:

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo en este ejemplo será analizar todo lo necesario para
realizar streaming adaptativo de contenido multimedia utilizando las
nuevas APIs disponibles en Windows 10.

Comenzamos diseñando nuestra interfaz. El reproductor será un control de tipo MediaElement:

<MediaElement />

Control que soporta reproducción de audio y video ante múltiples
formatos. Añadiremos también un botón para lanzar la reproducción:

<Button
     Grid.Row="1"
     HorizontalAlignment="Center"
     Content="Play"/>

El resultado:

Al pulsar el botón lanzaremos un comando en la ViewModel:

private ICommand _playCommand;
 
public ICommand PlayCommand
{
     get { return _playCommand = _playCommand ?? new DelegateCommandAsync(PlayCommandExecute); }
}
 
private async Task PlayCommandExecute()
{
 
}

Quedando la definición del botón de la siguiente forma:

<Button
     Grid.Row="1"
     HorizontalAlignment="Center"
     Content="Play"
     Command="{Binding PlayCommand}"/>

El comando se encargará de acceder a contenido multimedia adapatativo:

var hlsUri = new Uri(HlsUrl);
var hlsSource = await AdaptiveMediaSource.CreateFromUriAsync(hlsUri);

La clase AdaptiveMediaSource nos permite trabajar con una fuente de streaming adaptativo. Utilizamos CreateFromUriAsync, método asíncrono que nos permite crear una instancia de AdaptiveMediaSource desde una Uri, es decir, trabajando directamente con una Url.

NOTA: Tenemos la posibilidad de obtener la
instancia de AdaptiveMediaSource trabajando con Streams utilizando el
método CreateFromStreamAsync.

El resultado obtenido es una instancia de la clase AdaptiveMediaSourceCreationResult que contiene información imprescindible relacionada con el estado, conexión y contenido de la fuente de streaming adaptativo:

  • HttpResponseMessage:
    Contiene la respuesta de la petición Http realizada para acceder al
    contenido multimedia. Útil para obtener información sobretodo en caso de
    errores.
  • MediaSource: Instancia de la clase AdaptiveMediaSource  que representa el contenido multimedia.
  • Status: Valor contemplado en enumeración que nos indica el estado de la creación de  MediaSource.

Crearemos una propiedad pública para enlazar contenido obtenido:

private AdaptiveMediaSource _mediaSource;  
 
public AdaptiveMediaSource MediaSource
{
     get { return _mediaSource; }
     set
     {
          _mediaSource = value;
          RaisePropertyChanged();
     }
}

Siempre antes, utilizaremos la propiedad Status para verificar que todo ha ido sin problemas:

if (hlsSource.Status == AdaptiveMediaSourceCreationStatus.Success)
{
     MediaSource = hlsSource.MediaSource;
}

Llegados a este punto, solo tenemos que asignar el contenido obtenido
de la fuente de streaming multimedia adapatativo a nuestro control MediaElement.

Creando un Behavior

A pesar de tener una propiedad Source, la asignación de AdaptiveMediaSource al MediaElement se realiza utilizando el método SetMediaStreamSource del MediaElement, ¿cómo podemos enlazarlo directamente?

Crearemos un Behavior para ello. Añadiremos la referencia a Extensions SDK:

En nuestro proyecto, dentro de la carpeta Behaviors, crearemos una nueva clase que heredará de IBehavior:

public class MediaStreamSourceBehavior : DependencyObject, IBehavior
{
     public void Attach(DependencyObject associatedObject)
     {
         var control = associatedObject as MediaElement;
         if (control == null)
             throw new ArgumentException(
                 "MediaStreamSourceBehavior can be attached only to MediaElement.");
 
         AssociatedObject = associatedObject;
     }
 
     public void Detach()
     {
         AssociatedObject = null;
     }
}

Realizamos la implementación de la interfaz IBehavior asociando el Behavior al elemento MediaElement. A continuación, crearemos una nueva propiedad de dependencia de tipo AdaptiveMediaSource a la que bindearemos la propiedad MediaSource que creamos previamente en nuestra ViewModel:

public AdaptiveMediaSource Media
{
     get { return (AdaptiveMediaSource)GetValue(MediaProperty); }
     set { SetValue(MediaProperty, value); }
}
 
public static readonly DependencyProperty MediaProperty =
            DependencyProperty.Register("Media",
            typeof(AdaptiveMediaSource),
            typeof(MediaStreamSourceBehavior),
            new PropertyMetadata(null, OnMediaChanged));
 
private static void OnMediaChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
     var behavior = sender as MediaStreamSourceBehavior;
     if (behavior.AssociatedObject == null || e.NewValue == null) return;
 
     var mediaElement = behavior.AssociatedObject as MediaElement;
     if (mediaElement != null)
          mediaElement.SetMediaStreamSource((AdaptiveMediaSource)e.NewValue);
}

Al asignar el valor de la propiedad de depencia creada, utilizaremos el método SetMediaStreamSource del control MediaElement para asignar la fuente.

Solo nos queda utilizar el Behavior en nuestra interfaz de usuario. Añadimos los namespaces necesarios:

xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:HlsPlayer.Behaviors"

Utilizamos el Behavior con nuestro control MediaElement bindeando la fuente de streaming:

<MediaElement
     AutoPlay="True">
     <i:Interaction.Behaviors>
           <behaviors:MediaStreamSourceBehavior
                Media="{Binding MediaSource}"/>
     </i:Interaction.Behaviors>
</MediaElement>

Al ejecutar la Aplicación y pulsar el botón Play:

Comienza la reproducción del streaming adaptativo de contenido multimedia.

Podéis descargar el ejemplo realizado a continuación:

También podéis acceder al código fuente directamente en GitHub:

Ver GitHub

Recordar que cualquier tipo de duda o sugerencia la podéis dejar en los comentarios de la entrada.

Más información

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *