Reproducir audio y vídeo con MediaPlayerPlay audio and video with MediaPlayer

En este artículo se muestra cómo reproducir elementos multimedia en la aplicación universal de Windows con la clase MediaPlayer.This article shows you how to play media in your Universal Windows app using the MediaPlayer class. Con Windows 10, versión 1607, se realizaron mejoras significativas en las API de reproducción multimedia, incluido un diseño simplificado de un solo proceso para audio de fondo, la integración automática con los controles de transporte de medios del sistema (SMTC), la capacidad de sincronizar varios reproductores multimedia, la capacidad de representar fotogramas de vídeo en una superficie Windows. UI. Composition y unaWith Windows 10, version 1607, significant improvements were made to the media playback APIs, including a simplified single-process design for background audio, automatic integration with the System Media Transport Controls (SMTC), the ability to synchronize multiple media players, the ability to render video frames to a Windows.UI.Composition surface, and an easy interface for creating and scheduling media breaks in your content. Para aprovechar estas mejoras, el procedimiento recomendado para reproducir elementos multimedia es usar la clase MediaPlayer en lugar de MediaElement para reproducir elementos multimedia.To take advantage of these improvements, the recommended best practice for playing media is to use the MediaPlayer class instead of MediaElement for media playback. El control de XAML ligero, MediaPlayerElement, se introdujo para permitir representar contenido multimedia en una página XAML.The lightweight XAML control, MediaPlayerElement, has been introduced to allow you render media content in a XAML page. Muchas API de estado y de control de la reproducción que proporciona la clase MediaElement están disponibles a través del nuevo objeto MediaPlaybackSession.Many of the playback control and status APIs provided by MediaElement are now available through the new MediaPlaybackSession object. La clase MediaElement continúa en funcionamiento para permitir la compatibilidad con versiones anteriores, pero no se le agregarán nuevas características.MediaElement continues to function to support backwards compatibility, but no additional features will be added to this class.

En este artículo se muestran las características de MediaPlayer que usará una aplicación típica de reproducción de elementos multimedia.This article will walk you through the MediaPlayer features that a typical media playback app will use. Ten en cuenta que MediaPlayer usa la clase MediaSource como un contenedor de todos los elementos multimedia.Note that MediaPlayer uses the MediaSource class as a container for all media items. Esta clase permite cargar y reproducir elementos multimedia de distintos orígenes, como archivos locales, secuencias de memoria y orígenes de redes, todo con la misma interfaz.This class allows you to load and play media from many different sources, including local files, memory streams, and network sources, all using the same interface. También hay clases de nivel superior que funcionan con MediaSource, como MediaPlaybackItem y MediaPlaybackList, que proporcionan características más avanzadas, como listas de reproducción y la capacidad para administrar orígenes multimedia con varias pistas de audio, vídeo y metadatos.There are also higher-level classes that work with MediaSource, such as MediaPlaybackItem and MediaPlaybackList, that provide more advanced features like playlists and the ability to manage media sources with multiple audio, video, and metadata tracks. Para obtener más información sobre MediaSource y las API relacionadas, consulta Elementos multimedia, listas de reproducción y pistas.For more information on MediaSource and related APIs, see Media items, playlists, and tracks.

Nota

Las ediciones Windows 10 N y Windows 10 KN no incluyen las características multimedia necesarias para usar MediaPlayer para la reproducción.Windows 10 N and Windows 10 KN editions do not include the media features required to use MediaPlayer for playback. Estas características se pueden instalar manualmente.These features can be installed manually. Para obtener más información, consulte Feature Pack de media para las ediciones Windows 10 N y Windows 10 kN.For more information, see Media feature pack for Windows 10 N and Windows 10 KN editions.

Reproducir un archivo multimedia con MediaPlayerPlay a media file with MediaPlayer

La reproducción básica de elementos multimedia con MediaPlayer es muy fácil de implementar.Basic media playback with MediaPlayer is very simple to implement. En primer lugar, crea una nueva instancia de la clase MediaPlayer.First, create a new instance of the MediaPlayer class. Tu aplicación puede tener varias instancias de MediaPlayer activas a la vez.Your app can have multiple MediaPlayer instances active at once. Después, establece la propiedad Source del reproductor en un objeto que implemente IMediaPlaybackSource, como un objeto MediaSource, MediaPlaybackItem o MediaPlaybackList.Next, set the Source property of the player to an object that implements the IMediaPlaybackSource, such as a MediaSource, a MediaPlaybackItem, or a MediaPlaybackList. En este ejemplo, un objeto MediaSource se crea a partir de un archivo en el almacenamiento local de la aplicación, y después se crea un objeto MediaPlaybackItem desde el origen y, se asigna a la propiedad Source del reproductor.In this example, a MediaSource is created from a file in the app's local storage, and then a MediaPlaybackItem is created from the source and then assigned to the player's Source property.

A diferencia de la clase MediaElement, la clase MediaPlayer no inicia automáticamente la reproducción de manera predeterminada.Unlike MediaElement, MediaPlayer does not automatically begin playback by default. Para iniciar la reproducción, llama al método Play, establece la propiedad AutoPlay en true o espera a que el usuario inicie la reproducción con los controles multimedia integrados.You can start playback by calling Play, by setting the AutoPlay property to true, or waiting for the user to initiate playback with the built-in media controls.

mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer.Play();

Cuando la aplicación haya terminado de usar una clase MediaPlayer, debes llamar al método Close (previsto para Dispose en C#), para liberar los recursos usados por el reproductor.When your app is done using a MediaPlayer, you should call the Close method (projected to Dispose in C#) to clean up the resources used by the player.

mediaPlayer.Dispose();

Usar MediaPlayerElement para representar vídeo en XAMLUse MediaPlayerElement to render video in XAML

Puedes reproducir elementos multimedia en una clase MediaPlayer sin que se muestren en XAML, pero muchas aplicaciones de reproducción multimedia querrán representar el contenido multimedia en una página XAML.You can play media in a MediaPlayer without displaying it in XAML, but many media playback apps will want to render the media in a XAML page. Para ello, usa el control de MediaPlayerElement ligero.To do this, use the lightweight MediaPlayerElement control. Como MediaElement, el elemento MediaPlayerElement te permite especificar si se deben mostrar los controles de transporte integrados.Like MediaElement, MediaPlayerElement allows you to specify whether the built-in transport controls should be shown.

<MediaPlayerElement x:Name="_mediaPlayerElement" AreTransportControlsEnabled="False" HorizontalAlignment="Stretch"  Grid.Row="0"/>

Para establecer la instancia MediaPlayer con la que está enlazado el elemento, llama a SetMediaPlayer.You can set the MediaPlayer instance that the element is bound to by calling SetMediaPlayer.

_mediaPlayerElement.SetMediaPlayer(mediaPlayer);

También puedes establecer el origen de reproducción en el elemento MediaPlayerElement y este creará automáticamente una nueva instancia de MediaPlayer a la que podrás acceder con la propiedad MediaPlayer.You can also set the playback source on the MediaPlayerElement and the element will automatically create a new MediaPlayer instance that you can access using the MediaPlayer property.

_mediaPlayerElement.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer = _mediaPlayerElement.MediaPlayer;
mediaPlayer.Play();

Nota

Si deshabilitas la clase MediaPlaybackCommandManager de MediaPlayer al establecer la propiedad IsEnabled en "false", se interrumpirá el vínculo entre MediaPlayer y TransportControls que proporciona el elemento MediaPlayerElement, de modo que los controles de transporte integrados ya no controlarán automáticamente la reproducción del reproductor.If you disable the MediaPlaybackCommandManager of the MediaPlayer by setting IsEnabled to false, it will break the link between the MediaPlayer the TransportControls provided by the MediaPlayerElement, so the built-in transport controls will no longer automatically control the playback of the player. En su lugar, debes implementar tus propios controles para controlar la clase MediaPlayer.Instead, you must implement your own controls to control the MediaPlayer.

Tareas comunes de MediaPlayerCommon MediaPlayer tasks

En esta sección se muestra cómo usar algunas de las características de la clase MediaPlayer.This section shows you how to use some of the features of the MediaPlayer.

Establecer la categoría de audioSet the audio category

Establece la propiedad AudioCategory de una clase MediaPlayer en uno de los valores de la enumeración MediaPlayerAudioCategory para que el sistema sepa qué tipo de elemento multimedia se está reproduciendo.Set the AudioCategory property of a MediaPlayer to one of the values of the MediaPlayerAudioCategory enumeration to let the system know what kind of media you are playing. Los juegos deben clasificar sus secuencias de música como GameMedia para que la música del juego se silencie automáticamente si otra aplicación reproduce música en segundo plano.Games should categorize their music streams as GameMedia so that game music mutes automatically if another application plays music in the background. Las aplicaciones de música o vídeo deben clasificar sus secuencias como Media o Movie para que tengan prioridad sobre las secuencias GameMedia.Music or video applications should categorize their streams as Media or Movie so they will take priority over GameMedia streams.

mediaPlayer.AudioCategory = MediaPlayerAudioCategory.Media;

Salida a un punto de conexión de audio específicoOutput to a specific audio endpoint

De manera predeterminada, la salida de audio de una clase MediaPlayer se enruta hacia el punto de conexión de audio predeterminado para el sistema, pero puedes especificar un punto de conexión de audio que la clase MediaPlayer deba usar para la salida.By default, the audio output from a MediaPlayer is routed to the default audio endpoint for the system, but you can specify a specific audio endpoint that the MediaPlayer should use for output. En el ejemplo siguiente, el elemento MediaDevice.GetAudioRenderSelector devuelve una cadena que exclusivamente identifica la categoría de representación de audio de los dispositivos.In the example below, MediaDevice.GetAudioRenderSelector returns a string that uniquely idenfies the audio render category of devices. A continuación, se llama al método DeviceInformationFindAllAsync para obtener una lista de todos los dispositivos disponibles del tipo seleccionado.Next, the DeviceInformation method FindAllAsync is called to get a list of all available devices of the selected type. Se puede determinar mediante programación el dispositivo que quieres usar o agregar los dispositivos devueltos a un control ComboBox para permitir al usuario seleccionar un dispositivo.You may programmatically determine which device you want to use or add the returned devices to a ComboBox to allow the user to select a device.

string audioSelector = MediaDevice.GetAudioRenderSelector();
var outputDevices = await DeviceInformation.FindAllAsync(audioSelector);
foreach (var device in outputDevices)
{
    var deviceItem = new ComboBoxItem();
    deviceItem.Content = device.Name;
    deviceItem.Tag = device;
    _audioDeviceComboBox.Items.Add(deviceItem);
}

En el evento SelectionChanged del cuadro combinado de dispositivos, se establece la propiedad AudioDevice de la clase MediaPlayer en el dispositivo seleccionado, que se guardó en la propiedad Tag del elemento ComboBoxItem.In the SelectionChanged event for the devices combo box, the AudioDevice property of the MediaPlayer is set to the selected device, which was stored in the Tag property of the ComboBoxItem.

private void _audioDeviceComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    DeviceInformation selectedDevice = (DeviceInformation)((ComboBoxItem)_audioDeviceComboBox.SelectedItem).Tag;
    if (selectedDevice != null)
    {
        mediaPlayer.AudioDevice = selectedDevice;
    }
}

Sesión de reproducciónPlayback session

Como se describió anteriormente en este artículo, muchas de las funciones que expone la clase MediaElement se movieron a la clase MediaPlaybackSession.As described previously in this article, many of the functions that are exposed by the MediaElement class have been moved to the MediaPlaybackSession class. Esto incluye información sobre el estado de reproducción del reproductor, como la posición de reproducción actual, si está en pausa o en reproducción y la velocidad de reproducción actual.This includes information about the playback state of the player, such as the current playback position, whether the player is paused or playing, and the current playback speed. MediaPlaybackSession también proporciona varios eventos para notificarte si cambia el estado, como el almacenamiento en búfer actual y el estado de descarga del contenido que se reproduce, y el tamaño natural y la relación de aspecto del contenido de vídeo que se reproduce actualmente.MediaPlaybackSession also provides several events to notify you when the state changes, including the current buffering and download status of content being played and the natural size and aspect ratio of the currently playing video content.

El siguiente ejemplo muestra cómo implementar un controlador de clic del botón que salta 10 segundos adelante en el contenido.The following example shows you how to implement a button click handler that skips 10 seconds forward in the content. Primero, se recupera el objeto MediaPlaybackSession del reproductor con la propiedad PlaybackSession.First, the MediaPlaybackSession object for the player is retrieved with the PlaybackSession property. A continuación, se establece la propiedad Position en la posición de reproducción actual más 10 segundos.Next the Position property is set to the current playback position plus 10 seconds.

private void _skipForwardButton_Click(object sender, RoutedEventArgs e)
{
    var session = mediaPlayer.PlaybackSession;
    session.Position = session.Position + TimeSpan.FromSeconds(10);
}

En el siguiente ejemplo se muestra cómo usar un botón de alternancia para alternar entre la velocidad de reproducción normal y la velocidad 2X con la configuración de la propiedad PlaybackRate de la sesión.The next example illustrates using a toggle button to toggle between normal playback speed and 2X speed by setting the PlaybackRate property of the session.

private void _speedToggleButton_Checked(object sender, RoutedEventArgs e)
{
    mediaPlayer.PlaybackSession.PlaybackRate = 2.0;
}
private void _speedToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
    mediaPlayer.PlaybackSession.PlaybackRate = 1.0;
}

A partir de Windows 10, versión 1803, puede establecer la rotación con la que se presenta el vídeo en el control MediaPlayer en incrementos de 90 grados.Starting with Windows 10, version 1803, you can set the rotation with which video is presented in the MediaPlayer in increments of 90 degrees.

mediaPlayer.PlaybackSession.PlaybackRotation = MediaRotation.Clockwise90Degrees;

Detectar almacenamiento en búfer esperado e inesperadoDetect expected and unexpected buffering

El objeto MediaPlaybackSession que se describe en la sección anterior proporciona dos eventos para detectar cuándo comienza el archivo multimedia que se está reproduciendo y finaliza el almacenamiento en búfer, BufferingStarted y BufferingEnded.The MediaPlaybackSession object described in the previous section provides two events for detecting when the currently playing media file begins and ends buffering, BufferingStarted and BufferingEnded. Esto le permite actualizar la interfaz de usuario para mostrar el usuario que está realizando el almacenamiento en búfer.This allows you to update your UI to show the user that buffering is occurring. El almacenamiento en búfer inicial se espera cuando se abre por primera vez un archivo multimedia o cuando el usuario cambia a un nuevo elemento en una lista de reproducción.Initial buffering is expected when a media file is first opened or when the user switches to a new item in a playlist. El almacenamiento en búfer inesperado puede producirse cuando se degrada la velocidad de la red o si el sistema de administración de contenido que proporciona el contenido experimenta problemas técnicos.Unexpected buffering can occur when the network speed degrades or if the content management system providing the content experiences technical issues. A partir de RS3, puede usar el evento BufferingStarted para determinar si se espera el evento de almacenamiento en búfer o si es inesperado e interrumpiendo la reproducción.Starting with RS3, you can use the BufferingStarted event to determine if the buffering event is expected or if it is unexpected and interrupting playback. Puede usar esta información como datos de telemetría de su aplicación o servicio de entrega multimedia.You can use this information as telemetry data for your app or media delivery service.

Registre Controladores para los eventos BufferingStarted y BufferingEnded para recibir notificaciones de estado de almacenamiento en búfer.Register handlers for the BufferingStarted and BufferingEnded events to receive buffering state notifications.

mediaPlayer.PlaybackSession.BufferingStarted += MediaPlaybackSession_BufferingStarted;
mediaPlayer.PlaybackSession.BufferingEnded += MediaPlaybackSession_BufferingEnded;

En el controlador de eventos BufferingStarted , convierta los argumentos del evento pasados en el evento a un objeto MediaPlaybackSessionBufferingStartedEventArgs y Compruebe la propiedad IsPlaybackInterruption .In the BufferingStarted event handler, cast the event args passed into the event to a MediaPlaybackSessionBufferingStartedEventArgs object and check the IsPlaybackInterruption property. Si este valor es true, el almacenamiento en búfer que desencadenó el evento es inesperado e interrumpiendo la reproducción.If this value is true, the buffering that triggered the event is unexpected and interrupting playback. De lo contrario, se espera el almacenamiento en búfer inicial.Otherwise, it is expected initial buffering.

private void MediaPlaybackSession_BufferingStarted(MediaPlaybackSession sender, object args)
{
    MediaPlaybackSessionBufferingStartedEventArgs bufferingStartedEventArgs = args as MediaPlaybackSessionBufferingStartedEventArgs;
    if (bufferingStartedEventArgs != null && bufferingStartedEventArgs.IsPlaybackInterruption)
    {
        // update the playback quality telemetry report to indicate that
        // playback was interrupted
    }

    // update the UI to indicate that playback is buffering
}
private void MediaPlaybackSession_BufferingEnded(MediaPlaybackSession sender, object args)
{
    // update the UI to indicate that playback is no longer buffering
}

Acercar los dedos y hacer zoom de vídeoPinch and zoom video

MediaPlayer te permite especificar el rectángulo de origen con el contenido de vídeo que se debe representar y permite hacer zoom en el vídeo de forma eficaz.MediaPlayer allows you to specify the source rectangle within video content that should be rendered, effectively allowing you to zoom into video. El rectángulo que especifiques es relativo a un rectángulo normalizado (0,0,1,1), donde 0,0 es la parte superior izquierda del fotograma y 1,1 especifica el ancho y alto total del fotograma.The rectangle you specify is relative to a normalized rectangle (0,0,1,1) where 0,0 is the upper left hand of the frame and 1,1 specifies the full width and height of the frame. Por lo tanto, por ejemplo, para establecer el rectángulo de zoom para que se represente el cuadrante superior derecho del vídeo, se especifica el rectángulo (.5,0,.5,.5).So, for example, to set the zoom rectangle so that the top-right quadrant of the video is rendered, you would specify the rectangle (.5,0,.5,.5). Es importante comprobar los valores para asegurarte de que el rectángulo de origen está dentro del rectángulo normalizado (0,0,1,1).It is important that you check your values to make sure that your source rectangle is within the (0,0,1,1) normalized rectangle. Intentar establecer un valor fuera de este intervalo hará que se inicie una excepción.Attempting to set a value outside of this range will cause an exception to be thrown.

Para implementar la opción de acercar los dedos y hacer zoom con gestos multitoque, antes debes especificar qué gestos quieres admitir.To implement pinch and zoom using multi-touch gestures, you must first specify which gestures you want to support. En este ejemplo, se solicitan los gestos ampliar y trasladar.In this example, scale and translate gestures are requested. El evento ManipulationDelta se genera cuando se produce uno de los gestos suscritos.The ManipulationDelta event is raised when one of the subscribed gestures occurs. El evento DoubleTapped se usará para restablecer el zoom a un fotograma completo.The DoubleTapped event will be used to reset the zoom to the full frame.

_mediaPlayerElement.ManipulationMode = ManipulationModes.Scale | ManipulationModes.TranslateX | ManipulationModes.TranslateY;
_mediaPlayerElement.ManipulationDelta += _mediaPlayerElement_ManipulationDelta;
_mediaPlayerElement.DoubleTapped += _mediaPlayerElement_DoubleTapped;

A continuación, declara un objeto Rect que almacenará el rectángulo de origen de zoom actual.Next, declare a Rect object that will store the current zoom source rectangle.

Rect _sourceRect = new Rect(0, 0, 1, 1);

El controlador ManipulationDelta ajusta la escala o la traslación del rectángulo de zoom.The ManipulationDelta handler adjusts either the scale or the translation of the zoom rectangle. Si el valor de escala delta no es 1, significa que el usuario realizó un gesto de reducir.If the delta scale value is not 1, it means that the user performed a pinch gesture. Si el valor es mayor que 1, el rectángulo de origen debe hacerse más pequeño para acercar el contenido.If the value is greater than 1, the source rectangle should be made smaller to zoom into the content. Si el valor es menor que 1, el rectángulo de origen debe hacerse más grande para alejarlo. Antes de establecer los nuevos valores de escala, se comprueba el rectángulo resultante para asegurarse de que se encuentra completamente dentro de los límites (0, 0, 1, 1).If the value is less than 1, then the source rectangle should be made bigger to zoom out. Before setting the new scale values, the resulting rectangle is checked to make sure it lies entirely within the (0,0,1,1) limits.

Si el valor de escala es 1, se controla el gesto de traslación.If the scale value is 1, then the translation gesture is handled. Simplemente, el número de píxeles en el gesto dividido por el ancho y alto del control traslada el rectángulo.The rectangle is simply translated by the number of pixels in gesture divided by the width and height of the control. De nuevo, se comprueba el rectángulo resultante para asegurarse de que se encuentra dentro de los límites (0,0,1,1).Again, the resulting rectangle is checked to make sure it lies within the (0,0,1,1) bounds.

Por último, el objeto NormalizedSourceRect del elemento MediaPlaybackSession se establece en el rectángulo recién ajustado y se especifica el área del fotograma de vídeo que se debe representar.Finally, the NormalizedSourceRect of the MediaPlaybackSession is set to the newly adjusted rectangle, specifying the area within the video frame that should be rendered.

private void _mediaPlayerElement_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{

    if (e.Delta.Scale != 1)
    {
        var halfWidth = _sourceRect.Width / 2;
        var halfHeight = _sourceRect.Height / 2;

        var centerX = _sourceRect.X + halfWidth;
        var centerY = _sourceRect.Y + halfHeight;

        var scale = e.Delta.Scale;
        var newHalfWidth = (_sourceRect.Width * e.Delta.Scale) / 2;
        var newHalfHeight = (_sourceRect.Height * e.Delta.Scale) / 2;

        if (centerX - newHalfWidth > 0 && centerX + newHalfWidth <= 1.0 &&
            centerY - newHalfHeight > 0 && centerY + newHalfHeight <= 1.0)
        {
            _sourceRect.X = centerX - newHalfWidth;
            _sourceRect.Y = centerY - newHalfHeight;
            _sourceRect.Width *= e.Delta.Scale;
            _sourceRect.Height *= e.Delta.Scale;
        }
    }
    else
    {
        var translateX = -1 * e.Delta.Translation.X / _mediaPlayerElement.ActualWidth;
        var translateY = -1 * e.Delta.Translation.Y / _mediaPlayerElement.ActualHeight;

        if (_sourceRect.X + translateX >= 0 && _sourceRect.X + _sourceRect.Width + translateX <= 1.0 &&
            _sourceRect.Y + translateY >= 0 && _sourceRect.Y + _sourceRect.Height + translateY <= 1.0)
        {
            _sourceRect.X += translateX;
            _sourceRect.Y += translateY;
        }
    }

    mediaPlayer.PlaybackSession.NormalizedSourceRect = _sourceRect;
}

En el controlador de eventos DoubleTapped, el rectángulo de origen se vuelve a establecer en (0,0,1,1) para hacer que se represente todo el fotograma de vídeo.In the DoubleTapped event handler, the source rectangle is set back to (0,0,1,1) to cause the entire video frame to be rendered.

private void _mediaPlayerElement_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
    _sourceRect = new Rect(0, 0, 1, 1);
    mediaPlayer.PlaybackSession.NormalizedSourceRect = _sourceRect;
}

Nota: En esta sección se describe la entrada táctil.NOTE This section describes touch input. Touchpad envía eventos de puntero y no envía eventos de manipulación.Touchpad sends pointer events and will not send Manipulation events.

Control de la degradación de la reproducción basada en directivasHandling policy-based playback degradation

En algunas circunstancias, el sistema puede degradar la reproducción de un elemento multimedia, como reducir la resolución (constriction), en función de una directiva en lugar de un problema de rendimiento.In some circumstances the system may degrade the playback of a media item, such as reducing the resolution (constriction), based on a policy rather than a performance issue. Por ejemplo, el vídeo puede verse afectado por el sistema si se está reproduciendo con un controlador de vídeo sin firmar.For example, video may be degraded by the system if it is being played using an unsigned video driver. Puede llamar a MediaPlaybackSession. GetOutputDegradationPolicyState para determinar si se está produciendo esta degradación del basada en directivas y avisar al usuario o registrar el motivo de la telemetría.You can call MediaPlaybackSession.GetOutputDegradationPolicyState to determine if and why this policy-based degredation is occurring and alert the user or record the reason for telemetry purposes.

En el ejemplo siguiente se muestra una implementación de un controlador para el evento MediaPlayer. MediaOpened que se genera cuando el reproductor abre un nuevo elemento multimedia.The following example shows an implementation of a handler for the MediaPlayer.MediaOpened event that is raised when the player opens a new media item. Se llama a GetOutputDegradationPolicyState en el control MediaPlayer pasado al controlador.GetOutputDegradationPolicyState is called on the MediaPlayer passed into the handler. El valor de VideoConstrictionReason indica el motivo de la Directiva que el vídeo está restringido.The value of VideoConstrictionReason indicates the policy reason that the video is constricted. Si el valor no es ninguno, este ejemplo registra el motivo de la degradación de la telemetría.If the value isn't None, this example logs the degradation reason for telemetry purposes. En este ejemplo también se muestra cómo establecer la velocidad de bits del AdaptiveMediaSource que se está reproduciendo actualmente en el ancho de banda más bajo para ahorrar el uso de datos, ya que el vídeo está restringido y no se mostrará con alta resolución.This example also shows setting the bitrate of the AdaptiveMediaSource currently being played to the lowest bandwidth to save data usage, since the video is constricted and won't be displayed at high resolution anyway. Para obtener más información sobre el uso de AdaptiveMediaSource, consulte Adaptive streaming.For more information on using AdaptiveMediaSource, see Adaptive streaming.

private void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
    MediaPlaybackSessionOutputDegradationPolicyState info = sender.PlaybackSession.GetOutputDegradationPolicyState();

    if (info.VideoConstrictionReason != MediaPlaybackSessionVideoConstrictionReason.None)
    {
        // Switch to lowest bitrate to save bandwidth
        adaptiveMediaSource.DesiredMaxBitrate = adaptiveMediaSource.AvailableBitrates[0];

        // Log the degradation reason or show a message to the user
        System.Diagnostics.Debug.WriteLine("Logging constriction reason: " + info.VideoConstrictionReason);
    }
}

Usar MediaPlayerSurface para representar vídeo en una superficie Windows.UI.CompositionUse MediaPlayerSurface to render video to a Windows.UI.Composition surface

A partir de Windows 10, versión 1607, puedes usar MediaPlayer para representar vídeo en una superficie ICompositionSurface, que permite que el reproductor interopere con las API en el espacio de nombres Windows.UI.Composition.Starting with Windows 10, version 1607, you can use MediaPlayer to render video to an to render video to an ICompositionSurface, which allows the player to interoperate with the APIs in the Windows.UI.Composition namespace. El fotograma de composición te permite trabajar con gráficos en la capa visual entre XAML y las API de gráficos de DirectX de bajo nivel.The composition framework allows you to work with graphics in the visual layer between XAML and the low-level DirectX graphics APIs. Esto permite escenarios como la representación de vídeo en cualquier control XAML.This enables scenarios like rendering video into any XAML control. Para obtener más información sobre cómo usar las API de composición, consulta Capa visual.For more information on using the composition APIs, see Visual Layer.

En el siguiente ejemplo se muestra cómo representar el contenido del reproductor de vídeo en un control Canvas.The following example illustrates how to render video player content onto a Canvas control. Las llamadas específicas del reproductor multimedia de este ejemplo son SetSurfaceSize y GetSurface.The media player-specific calls in this example are SetSurfaceSize and GetSurface. SetSurfaceSize indica al sistema el tamaño del búfer que se debe asignar para representar contenido.SetSurfaceSize tells the system the size of the buffer that should be allocated for rendering content. GetSurface toma una clase Compositor como argumento y recupera una instancia de la clase MediaPlayerSurface.GetSurface takes a Compositor as an arguemnt and retreives an instance of the MediaPlayerSurface class. Esta clase proporciona acceso a las clases MediaPlayer y Compositor usadas para crear la superficie y expone la misma superficie a través de la propiedad CompositionSurface.This class provides access to the MediaPlayer and Compositor used to create the surface and exposes the surface itself through the CompositionSurface property.

El resto del código del ejemplo crea un objeto SpriteVisual por el que se representa el vídeo y establece el tamaño en el tamaño del elemento de lienzo que mostrará el elemento visual.The rest of the code in this example creates a SpriteVisual to which the video is rendered and sets the size to the size of the canvas element that will display the visual. A continuación, se crea un objeto CompositionBrush a partir de la clase MediaPlayerSurface y se asigna a la propiedad Brush del elemento visual.Next a CompositionBrush is created from the MediaPlayerSurface and assigned to the Brush property of the visual. A continuación, se crea una clase ContainerVisual y se inserta un objeto SpriteVisual en la parte superior de su árbol visual.Next a ContainerVisual is created and the SpriteVisual is inserted at the top of its visual tree. Por último, se llama a un objeto SetElementChildVisual para asignar el elemento visual contenedor a la clase Canvas.Finally, SetElementChildVisual is called to assign the container visual to the Canvas.

mediaPlayer.SetSurfaceSize(new Size(_compositionCanvas.ActualWidth, _compositionCanvas.ActualHeight));

var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
MediaPlayerSurface surface = mediaPlayer.GetSurface(compositor);

SpriteVisual spriteVisual = compositor.CreateSpriteVisual();
spriteVisual.Size =
    new System.Numerics.Vector2((float)_compositionCanvas.ActualWidth, (float)_compositionCanvas.ActualHeight);

CompositionBrush brush = compositor.CreateSurfaceBrush(surface.CompositionSurface);
spriteVisual.Brush = brush;

ContainerVisual container = compositor.CreateContainerVisual();
container.Children.InsertAtTop(spriteVisual);

ElementCompositionPreview.SetElementChildVisual(_compositionCanvas, container);

Usa MediaTimelineController para sincronizar contenido entre varios reproductores.Use MediaTimelineController to synchronize content across multiple players.

Como se explicó anteriormente en este artículo, la aplicación puede tener varios objetos MediaPlayer activos a la vez.As discussed previously in this article, your app can have several MediaPlayer objects active at a time. De manera predeterminada, cada objeto MediaPlayer que crees funciona de forma independiente.By default, each MediaPlayer you create operates independently. En algunos escenarios, como la sincronización de una pista de comentarios en un vídeo, es posible que quieras sincronizar el estado del reproductor, la posición de reproducción y la velocidad de reproducción de varios reproductores.For some scenarios, such as synchronizing a commentary track to a video, you may want to synchronize the player state, playback position, and playback speed of multiple players. A partir de Windows 10, versión 1607, puedes implementar este comportamiento usando la clase MediaTimelineController.Starting with Windows 10, version 1607, you can implement this behavior by using the MediaTimelineController class.

Implementar controles de reproducciónImplement playback controls

En el siguiente ejemplo se muestra cómo usar un objeto MediaTimelineController para controlar dos instancias del elemento MediaPlayer.The following example shows how to use a MediaTimelineController to control two instances of MediaPlayer. En primer lugar, se crea una instancia de cada instancia de la clase MediaPlayer y la propiedad Source se establece en un archivo multimedia.First, each instance of the MediaPlayer is instantiated and the Source is set to a media file. A continuación, se crea un objeto MediaTimelineController nuevo.Next, a new MediaTimelineController is created. Para cada objeto MediaPlayer, se deshabilita la clase MediaPlaybackCommandManager asociada a cada reproductor al establecer la propiedad IsEnabled en false.For each MediaPlayer, the MediaPlaybackCommandManager associated with each player is disabled by setting the IsEnabled property to false. Y, a continuación, la propiedad TimelineController se establece en el objeto de controlador de la escala de tiempo.And then the TimelineController property is set to the timeline controller object.

MediaTimelineController _mediaTimelineController;
mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);


_mediaPlayer2 = new MediaPlayer();
_mediaPlayer2.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video_2.mkv"));
_mediaPlayerElement2.SetMediaPlayer(_mediaPlayer2);

_mediaTimelineController = new MediaTimelineController();

mediaPlayer.CommandManager.IsEnabled = false;
mediaPlayer.TimelineController = _mediaTimelineController;

_mediaPlayer2.CommandManager.IsEnabled = false;
_mediaPlayer2.TimelineController = _mediaTimelineController;

Precaución La clase MediaPlaybackCommandManager proporciona integración automática entre MediaPlayer y los controles de transporte de contenido multimedia del sistema (SMTC), pero no se puede usar esta integración automática con reproductores multimedia que se controlen con un objeto MediaTimelineController.Caution The MediaPlaybackCommandManager provides automatic integration between MediaPlayer and the System Media Transport Controls (SMTC), but this automatic integration can't be used with media players that are controlled with a MediaTimelineController. Por lo tanto, debes deshabilitar el administrador de comandos del reproductor multimedia antes de establecer el controlador de línea de tiempo del reproductor.Therefore you must disable the command manager for the media player before setting the player's timeline controller. Si no se hace, se generará una excepción con el siguiente mensaje: "Se bloqueó la adjunción del controlador de línea de tiempo multimedia debido al estado actual del objeto".Failure to do so will result in an exception being thrown with the following message: "Attaching Media Timeline Controller is blocked because of the current state of the object." Para obtener más información sobre la integración del reproductor multimedia con los SMTC, consulta Integrar con los controles de transporte multimedia del sistema.For more information on media player integration with the SMTC, see Integrate with the System Media Transport Controls. Si estás usando un objeto MediaTimelineController, aún puedes controlar los SMTC manualmente.If you are using a MediaTimelineController you can still control the SMTC manually. Para obtener más información, consulta Controles de transporte de contenido multimedia del sistema.For more information, see Manual control of the System Media Transport Controls.

Cuando hayas adjuntado un objeto MediaTimelineController a uno o más reproductores multimedia, puedes controlar el estado de reproducción con los métodos que expone el controlador.Once you have attached a MediaTimelineController to one or more media players, you can control the playback state by using the methods exposed by the controller. El siguiente ejemplo llama al método Start para iniciar la reproducción de todos los reproductores multimedia adjuntos al inicio del elemento multimedia.The following example calls Start to begin playback of all associated media players at the beginning of the media.

private void PlayButton_Click(object sender, RoutedEventArgs e)
{
    _mediaTimelineController.Start();
}

En este ejemplo se muestra cómo pausar y reanudar todos los reproductores multimedia adjuntos.This example illustrates pausing and resuming all of the attached media players.

private void PauseButton_Click(object sender, RoutedEventArgs e)
{
    if(_mediaTimelineController.State == MediaTimelineControllerState.Running)
    {
        _mediaTimelineController.Pause();
        _pauseButton.Content = "Resume";
    }
    else
    {
        _mediaTimelineController.Resume();
        _pauseButton.Content = "Pause";
    }
}

Para avanzar rápidamente todos los reproductores multimedia conectados, establece la velocidad de reproducción en un valor mayor que 1.To fast-forward all connected media players, set the playback speed to a value greater that 1.

private void FastForwardButton_Click(object sender, RoutedEventArgs e)
{
    _mediaTimelineController.ClockRate = 2.0;
}

En el siguiente ejemplo se muestra cómo usar un control deslizante para mostrar la posición de reproducción actual del controlador de línea de tiempo relativo a la duración del contenido de uno de los reproductores multimedia conectados.The next example shows how to use a Slider control to show the current playback position of the timeline controller relative to the duration of the content of one of the connected media players. En primer lugar, se crea un objeto MediaSource nuevo y se registra un controlador para el objeto OpenOperationCompleted de origen multimedia.First, a new MediaSource is created and a handler for the OpenOperationCompleted of the media source is registered.

var mediaSource = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaSource.OpenOperationCompleted += MediaSource_OpenOperationCompleted;
mediaPlayer.Source = mediaSource;
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);

El controlador OpenOperationCompleted se usa como una oportunidad para descubrir la duración del contenido de origen multimedia.The OpenOperationCompleted handler is used as an opportunity to discover the duration of the media source content. Cuando se haya determinado la duración, el valor máximo del control deslizante se establece en el número total de segundos del elemento multimedia.Once the duration is determined, the maximum value of the Slider control is set to the total number of seconds of the media item. El valor se establece dentro de una llamada al método RunAsync para asegurarse de que se ejecute en el subproceso de la interfaz de usuario.The value is set inside a call to RunAsync to make sure it is run on the UI thread.

TimeSpan _duration;
private async void MediaSource_OpenOperationCompleted(MediaSource sender, MediaSourceOpenOperationCompletedEventArgs args)
{
    _duration = sender.Duration.GetValueOrDefault();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        _positionSlider.Minimum = 0;
        _positionSlider.Maximum = _duration.TotalSeconds;
        _positionSlider.StepFrequency = 1;
    }); 
}

A continuación, se registra un controlador para el evento de controlador de línea de tiempo PositionChanged.Next, a handler for the timeline controller's PositionChanged event is registered. El sistema lo llama periódicamente, aproximadamente 4 veces por segundo.This is called periodically by the system, approximately 4 times per second.

_mediaTimelineController.PositionChanged += _mediaTimelineController_PositionChanged;

En el controlador del objeto PositionChanged, el valor del control deslizante se actualiza para reflejar la posición actual del controlador de la línea de tiempo.In the handler for PositionChanged, the slider value is updated to reflect the current position of the timeline controller.

private async void _mediaTimelineController_PositionChanged(MediaTimelineController sender, object args)
{
    if (_duration != TimeSpan.Zero)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            _positionSlider.Value = sender.Position.TotalSeconds / (float)_duration.TotalSeconds;
        });
    }
}

Desplazar la posición de reproducción desde la posición de línea de tiempoOffset the playback position from the timeline position

En algunos casos, es posible que quieras que la posición de reproducción de uno o más reproductores multimedia asociados a un controlador de línea de tiempo se desplace desde los otros reproductores.In some cases you may want the playback position of one or more media players associated with a timeline controller to be offset from the other players. Para ello, establece la propiedad TimelineControllerPositionOffset del objeto MediaPlayer que quieras desplazar.You can do this by setting the TimelineControllerPositionOffset property of the MediaPlayer object you want to be offset. En el siguiente ejemplo, se usan las duraciones del contenido de dos reproductores multimedia para establecer los valores mínimos y máximos de dos control deslizantes para aumentar y reducir la longitud del elemento.The following example uses the durations of the content of two media players to set the minimum and maximum values of two slider control to plus and minus the length of the item.

_timelineOffsetSlider1.Minimum = -1 * _duration.TotalSeconds;
_timelineOffsetSlider1.Maximum = _duration.TotalSeconds;
_timelineOffsetSlider1.StepFrequency = 1;

_timelineOffsetSlider2.Minimum = -1 * _duration2.TotalSeconds;
_timelineOffsetSlider2.Maximum = _duration2.TotalSeconds;
_timelineOffsetSlider2.StepFrequency = 1;

En el evento ValueChanged de cada control deslizante, el objeto TimelineControllerPositionOffset de cada reproductor está establecido en el valor correspondiente.In the ValueChanged event for each slider, the TimelineControllerPositionOffset for each player is set to the corresponding value.

private void _timelineOffsetSlider1_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    mediaPlayer.TimelineControllerPositionOffset = TimeSpan.FromSeconds(_timelineOffsetSlider1.Value);
}

private void _timelineOffsetSlider2_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    _mediaPlayer2.TimelineControllerPositionOffset = TimeSpan.FromSeconds(_timelineOffsetSlider2.Value);
}

Ten en cuenta que si el valor de desplazamiento de un reproductor se asigna a una posición de reproducción negativa, el clip permanecerá en pausa hasta que el desplazamiento llegue a cero y, a continuación, se iniciará la reproducción.Note that if the offset value of a player maps to a negative playback position, the clip will remain paused until the offset reaches zero and then playback will begin. Del mismo modo, si el valor de desplazamiento se asigna a una posición de reproducción mayor que la duración del elemento multimedia, se mostrará el último fotograma, igual que cuando un único reproductor multimedia alcanza el final de su contenido.Likewise, if the offset value maps to a playback position greater than the duration of the media item, the final frame will be shown, just as it does when a single media player reached the end of its content.

Reproducir vídeo esférico con MediaPlayerPlay spherical video with MediaPlayer

A partir de Windows 10, versión 1703, MediaPlayer admite la proyección equirectangular para la reproducción de vídeo esférica.Starting with Windows 10, version 1703, MediaPlayer supports equirectangular projection for spherical video playback. El contenido de vídeo esférico no es diferente del vídeo normal y plano en el que se representará el vídeo, siempre y cuando se admita la codificación de vídeo.Spherical video content is no different from regular, flat video in that MediaPlayer will render the video as long as the video encoding is supported. En el caso de vídeo esférico que contiene una etiqueta de metadatos que especifica que el vídeo usa la proyección equirectangular, MediaPlayer puede representar el vídeo con un campo de vista y una orientación de vista especificados.For spherical video that contains a metadata tag that specifies that the video uses equirectangular projection, MediaPlayer can render the video using a specified field-of-view and view orientation. Esto permite escenarios como la reproducción de vídeo de realidad virtual con una pantalla montada por el cabezal o simplemente permite al usuario desplazarse por el contenido de vídeo esférico mediante la entrada del mouse o del teclado.This enables scenarios such as virtual reality video playback with a head-mounted display or simply allowing the user to pan around within spherical video content using the mouse or keyboard input.

Para reproducir vídeo esférico, siga los pasos para reproducir el contenido de vídeo descrito anteriormente en este artículo.To play back spherical video, use the steps for playing back video content described previously in this article. El paso adicional consiste en registrar un controlador para el evento MediaPlayer. MediaOpened .The one additional step is to register a handler for the MediaPlayer.MediaOpened event. Este evento le ofrece la oportunidad de habilitar y controlar los parámetros de reproducción de vídeo esférico.This event gives you an opportunity to enable and control the spherical video playback parameters.

mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened += _mediaPlayer_MediaOpened;
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video_spherical.mp4"));
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);
mediaPlayer.Play();

En el controlador MediaOpened , compruebe primero el formato de marco del elemento multimedia recién abierto comprobando la propiedad PlaybackSession. SphericalVideoProjection. FrameFormat .In the MediaOpened handler, first check the frame format of the newly opened media item by checking the PlaybackSession.SphericalVideoProjection.FrameFormat property. Si este valor es SphericaVideoFrameFormat. equirectangular, el sistema puede proyectar automáticamente el contenido del vídeo.If this value is SphericaVideoFrameFormat.Equirectangular, then the system can automatically project the video content. En primer lugar, establezca la propiedad PlaybackSession. SphericalVideoProjection. IsEnabled en true.First, set the PlaybackSession.SphericalVideoProjection.IsEnabled property to true. También puede ajustar propiedades como la orientación de la vista y el campo de vista que el reproductor de media usará para proyectar el contenido del vídeo.You can also adjust properties such as the view orientation and field of view that the media player will use to project the video content. En este ejemplo, el campo de vista se establece en un valor ancho de 120 grados mediante el establecimiento de la propiedad HorizontalFieldOfViewInDegrees .In this example, the field of view is set to a wide value of 120 degrees by setting the HorizontalFieldOfViewInDegrees property.

Si el contenido del vídeo es esférico, pero está en un formato distinto de equirectangular, puede implementar su propio algoritmo de proyección mediante el modo de servidor de trama del reproductor de media para recibir y procesar fotogramas individuales.If the video content is spherical, but is in a format other than equirectangular, you can implement your own projection algorithm using the media player's frame server mode to receive and process individual frames.

private void _mediaPlayer_MediaOpened(MediaPlayer sender, object args)
{
    if (sender.PlaybackSession.SphericalVideoProjection.FrameFormat == SphericalVideoFrameFormat.Equirectangular)
    {
        sender.PlaybackSession.SphericalVideoProjection.IsEnabled = true;
        sender.PlaybackSession.SphericalVideoProjection.HorizontalFieldOfViewInDegrees = 120;

    }
    else if (sender.PlaybackSession.SphericalVideoProjection.FrameFormat == SphericalVideoFrameFormat.Unsupported)
    {
        // If the spherical format is unsupported, you can use frame server mode to implement a custom projection
    }
}

En el ejemplo de código siguiente se muestra cómo ajustar la orientación de la vista de vídeo esférica mediante las teclas de flecha izquierda y derecha.The following example code illustrates how to adjust the spherical video view orientation using the left and right arrow keys.

protected override void OnKeyDown(KeyRoutedEventArgs e)
{
    if (mediaPlayer.PlaybackSession.SphericalVideoProjection.FrameFormat != SphericalVideoFrameFormat.Equirectangular)
    {
        return;
    }

    switch (e.Key)
    {
        case Windows.System.VirtualKey.Right:
            mediaPlayer.PlaybackSession.SphericalVideoProjection.ViewOrientation *= Quaternion.CreateFromYawPitchRoll(.1f, 0, 0);
            break;
        case Windows.System.VirtualKey.Left:
            mediaPlayer.PlaybackSession.SphericalVideoProjection.ViewOrientation *= Quaternion.CreateFromYawPitchRoll(-.1f, 0, 0);
            break;
    }
}

Si la aplicación admite listas de reproducción de vídeo, es posible que quiera identificar elementos de reproducción que contengan vídeo esférico en la interfaz de usuario.If your app supports playlists of video, you may want to identify playback items that contain spherical video in your UI. Las listas de reproducción multimedia se tratan en detalle en el artículo elementos multimedia, listas de reproducción y pistas.Media playlists are discussed in detail in the article, Media items, playlists, and tracks. En el ejemplo siguiente se muestra cómo crear una nueva lista de reproducción, agregar un elemento y registrar un controlador para el evento MediaPlaybackItem. VideoTracksChanged , que se produce cuando se resuelven las pistas de vídeo para un elemento multimedia.The following example shows creating a new playlist, adding an item, and registering a handler for the MediaPlaybackItem.VideoTracksChanged event, which occurs when the video tracks for a media item are resolved.

var playbackList = new MediaPlaybackList();
var item = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/RIFTCOASTER HD_injected.mp4")));
item.VideoTracksChanged += Item_VideoTracksChanged;
playbackList.Items.Add(item);
mediaPlayer.Source = playbackList;

En el controlador de eventos VideoTracksChanged , obtenga las propiedades de codificación de las pistas de vídeo agregadas llamando a videotrack. GetEncodingProperties.In the VideoTracksChanged event handler, get the encoding properties for any added video tracks by calling VideoTrack.GetEncodingProperties. Si la propiedad SphericalVideoFrameFormat de las propiedades de codificación es un valor distinto de SphericaVideoFrameFormat. None, la pista de vídeo contiene vídeo esférico y puede actualizar la interfaz de usuario según corresponda si lo desea.If the SphericalVideoFrameFormat property of the encoding properties is a value other than SphericaVideoFrameFormat.None, then the video track contains spherical video and you can update your UI accordingly if you choose.

private void Item_VideoTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    if (args.CollectionChange != CollectionChange.ItemInserted)
    {
        return;
    }
    foreach (var videoTrack in sender.VideoTracks)
    {
        if (videoTrack.GetEncodingProperties().SphericalVideoFrameFormat != SphericalVideoFrameFormat.None)
        {
            // Optionally indicate in the UI that this item contains spherical video
        }
    }
}

Usar MediaPlayer en modo de servidor de marcoUse MediaPlayer in frame server mode

A partir de Windows 10, versión 1703, puede usar MediaPlayer en modo de servidor de marco.Starting with Windows 10, version 1703, you can use MediaPlayer in frame server mode. En este modo, el objeto MediaPlayer no representa automáticamente fotogramas en un objeto MediaPlayerElementasociado.In this mode, the MediaPlayer does not automatically render frames to an associated MediaPlayerElement. En su lugar, la aplicación copia el marco actual de MediaPlayer en un objeto que implementa IDirect3DSurface.Instead, your app copies the current frame from the MediaPlayer to an object that implements IDirect3DSurface. El escenario principal que esta característica permite es usar sombreadores de píxeles para procesar fotogramas de vídeo proporcionados por el MediaPlayer.The primary scenario this feature enables is using pixel shaders to process video frames provided by the MediaPlayer. La aplicación es responsable de mostrar cada fotograma después del procesamiento, como mostrar el marco en un control de imagen XAML.Your app is responsible for displaying each frame after processing, such as by showing the frame in a XAML Image control.

En el ejemplo siguiente, se inicializa un nuevo MediaPlayer y se carga el contenido de vídeo.In the following example, a new MediaPlayer is initialized and video content is loaded. A continuación, se registra un controlador de VideoFrameAvailable .Next, a handler for VideoFrameAvailable is registered. El modo de servidor de trama se habilita estableciendo la propiedad IsVideoFrameServerEnabled del objeto MediaPlayer en true.Frame server mode is enabled by setting the MediaPlayer object's IsVideoFrameServerEnabled property to true. Por último, la reproducción multimedia se inicia con una llamada a Play.Finally, media playback is started with a call to Play.

mediaPlayer = new MediaPlayer();
mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer.VideoFrameAvailable += mediaPlayer_VideoFrameAvailable;
mediaPlayer.IsVideoFrameServerEnabled = true;
mediaPlayer.Play();

En el ejemplo siguiente se muestra un controlador para VideoFrameAvailable que usa Win2D para agregar un efecto de desenfoque simple a cada fotograma de un vídeo y, a continuación, muestra los marcos procesados en un control de imagen XAML.The next example shows a handler for VideoFrameAvailable that uses Win2D to add a simple blur effect to each frame of a video and then displays the processed frames in a XAML Image control.

Cada vez que se llama al controlador VideoFrameAvailable , se usa el método CopyFrameToVideoSurface para copiar el contenido del marco en una IDirect3DSurface.Whenever the VideoFrameAvailable handler is called, the CopyFrameToVideoSurface method is used to copy the contents of the frame to an IDirect3DSurface. También puede usar CopyFrameToStereoscopicVideoSurfaces para copiar contenido 3D en dos superficies, para procesar el contenido del ojo izquierdo y el ojo secundario por separado.You can also use CopyFrameToStereoscopicVideoSurfaces to copy 3D content into two surfaces, for processing the left eye and right eye content separately. Para obtener un objeto que implementa IDirect3DSurface en este ejemplo, se crea un objeto SoftwareBitmap y, a continuación, se usa para crear un CanvasBitmapde Win2D, que implementa la interfaz necesaria.To get an object that implements IDirect3DSurface this example creates a SoftwareBitmap and then uses that object to create a Win2D CanvasBitmap, which implements the necessary interface. Un CanvasImageSource es un objeto Win2D que se puede usar como origen para un control de imagen , por lo que se crea uno nuevo y se establece como el origen de la imagen en la que se mostrará el contenido.A CanvasImageSource is a Win2D object that can be used as the source for an Image control, so a new one is created and set as the source for the Image in which the content will be displayed. A continuación, se crea un CanvasDrawingSession .Next, a CanvasDrawingSession is created. Win2D lo usa para presentar el efecto de desenfoque.This is used by Win2D to render the blur effect.

Una vez que se han creado instancias de todos los objetos necesarios, se llama a CopyFrameToVideoSurface , que copia el marco actual del objeto MediaPlayer en el CanvasBitmap.Once all of the necessary objects have been instantiated, CopyFrameToVideoSurface is called, which copies the current frame from the MediaPlayer into the CanvasBitmap. A continuación, se crea un GaussianBlurEffect de Win2D, con el CanvasBitmap establecido como el origen de la operación.Next, a Win2D GaussianBlurEffect is created, with the CanvasBitmap set as the source of the operation. Por último, se llama a CanvasDrawingSession. drawImage para dibujar la imagen de origen, con el efecto de desenfoque aplicado, en el CanvasImageSource que se ha asociado con el control de imagen , lo que provoca que se dibuje en la interfaz de usuario.Finally, CanvasDrawingSession.DrawImage is called to draw the source image, with the blur effect applied, into the CanvasImageSource that has been associated with Image control, causing it to be drawn in the UI.

private async void mediaPlayer_VideoFrameAvailable(MediaPlayer sender, object args)
{
    CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        if(frameServerDest == null)
        {
            // FrameServerImage in this example is a XAML image control
            frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, (int)FrameServerImage.Width, (int)FrameServerImage.Height, BitmapAlphaMode.Ignore);
        }
        if(canvasImageSource == null)
        {
            canvasImageSource = new CanvasImageSource(canvasDevice, (int)FrameServerImage.Width, (int)FrameServerImage.Height, DisplayInformation.GetForCurrentView().LogicalDpi);//96); 
            FrameServerImage.Source = canvasImageSource;
        }

        using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest))
        using (CanvasDrawingSession ds = canvasImageSource.CreateDrawingSession(Windows.UI.Colors.Black))
        {

            mediaPlayer.CopyFrameToVideoSurface(inputBitmap);

            var gaussianBlurEffect = new GaussianBlurEffect
            {
                Source = inputBitmap,
                BlurAmount = 5f,
                Optimization = EffectOptimization.Speed
            };

            ds.DrawImage(gaussianBlurEffect);

        }
    });
}

private void FrameServerSubtitlesButton_Click(object sender, RoutedEventArgs e)
{

    mediaPlayer = new MediaPlayer();
    var source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
    var item = new MediaPlaybackItem(source);

    item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged;


    mediaPlayer.Source = item;
    mediaPlayer.VideoFrameAvailable += mediaPlayer_VideoFrameAvailable_Subtitle;
    mediaPlayer.IsVideoFrameServerEnabled = true;
    mediaPlayer.Play();

    mediaPlayer.IsMuted = true;

}

private void Item_TimedMetadataTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    if(sender.TimedMetadataTracks.Count > 0)
    {
        sender.TimedMetadataTracks.SetPresentationMode(0, TimedMetadataTrackPresentationMode.PlatformPresented);
    }
}

private async void mediaPlayer_VideoFrameAvailable_Subtitle(MediaPlayer sender, object args)
{
    CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        if (frameServerDest == null)
        {
            // FrameServerImage in this example is a XAML image control
            frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, (int)FrameServerImage.Width, (int)FrameServerImage.Height, BitmapAlphaMode.Ignore);
        }
        if (canvasImageSource == null)
        {
            canvasImageSource = new CanvasImageSource(canvasDevice, (int)FrameServerImage.Width, (int)FrameServerImage.Height, DisplayInformation.GetForCurrentView().LogicalDpi);//96); 
            FrameServerImage.Source = canvasImageSource;
        }

        using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest))
        {
            using (CanvasDrawingSession ds = canvasImageSource.CreateDrawingSession(Windows.UI.Colors.Black))
            {

                mediaPlayer.CopyFrameToVideoSurface(inputBitmap);

                //Rect subtitleTargetRect = new Rect(0, 0, inputBitmap.Bounds.Width, inputBitmap.Bounds.Bottom * .1);
                Rect subtitleTargetRect = new Rect(0, 0, 100, 100);

                mediaPlayer.RenderSubtitlesToSurface(inputBitmap);//, subtitleTargetRect);

                //var gaussianBlurEffect = new GaussianBlurEffect
                //{
                //    Source = inputBitmap,
                //    BlurAmount = 5f,
                //    Optimization = EffectOptimization.Speed
                //};

                //ds.DrawImage(gaussianBlurEffect);

                ds.DrawImage(inputBitmap);
            }
        }
    });
}

Para obtener más información sobre Win2D, vea el repositorio de github de win2d.For more information on Win2D, see the Win2D GitHub repository. Para probar el código de ejemplo mostrado anteriormente, debe agregar el paquete NuGet de Win2D al proyecto con las siguientes instrucciones.To try out the sample code shown above, you will need to add the Win2D NuGet package to your project with the following instructions.

Para agregar el paquete de NuGet Win2D al proyecto de efectoTo add the Win2D NuGet package to your effect project

  1. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Administrar paquetes NuGet.In Solution Explorer, right-click your project and select Manage NuGet Packages.
  2. En la parte superior de la ventana, selecciona la pestaña Examinar.At the top of the window, select the Browse tab.
  3. En el cuadro de búsqueda, escribe Win2D.In the search box, enter Win2D.
  4. Selecciona Win2D.uwpy luego selecciona Instalar en el panel derecho.Select Win2D.uwp, and then select Install in the right pane.
  5. En el cuadro de diálogo Revisar cambios se muestra el paquete que se instalará.The Review Changes dialog shows you the package to be installed. Haga clic en OK.Click OK.
  6. Acepta la licencia del paquete.Accept the package license.

Detectar y responder a los cambios de nivel de audio por parte del sistemaDetect and respond to audio level changes by the system

A partir de la versión 1803 de Windows 10, la aplicación puede detectar cuándo el sistema reduce o silencia el nivel de audio de un MediaPlayeractualmente en reproducción.Starting with Windows 10, version 1803, your app can detect when the system lowers or mutes the audio level of a currently playing MediaPlayer. Por ejemplo, el sistema puede reducir o "pato" el nivel de reproducción de audio cuando se produce un timbre de alarma.For example, the system may lower, or "duck", the audio playback level when an alarm is ringing. El sistema silenciará la aplicación cuando pase a segundo plano si la aplicación no ha declarado la funcionalidad backgroundMediaPlayback en el manifiesto de la aplicación.The system will mute your app when it goes into the background if your app has not declared the backgroundMediaPlayback capability in the app manifest. La clase AudioStateMonitor permite registrarse para recibir un evento cuando el sistema modifica el volumen de una secuencia de audio.The AudioStateMonitor class allows you to register to receive an event when the system modifies the volume of an audio stream. Acceda a la propiedad AudioStateMonitor de un control MediaPlayer y registre un controlador para que se notifique al evento SoundLevelChanged cuando el sistema cambie el nivel de audio de ese MediaPlayer .Access the AudioStateMonitor property of a MediaPlayer and register a handler for the SoundLevelChanged event to be notified when the audio level for that MediaPlayer is changed by the system.

mediaPlayer.AudioStateMonitor.SoundLevelChanged += AudioStateMonitor_SoundLevelChanged;

Al controlar el evento SoundLevelChanged , puede realizar diferentes acciones en función del tipo de contenido que se reproduzca.When handling the SoundLevelChanged event, you may take different actions depending on the type of content being played. Si actualmente está reproduciendo música, puede que desee dejar que la música continúe jugando mientras el volumen está pato.If you are currently playing music, then you may want to let the music continue to play while the volume is ducked. Sin embargo, si está reproduciendo un podcast, es probable que desee pausar la reproducción mientras el audio está pato, por lo que el usuario no pierde el contenido.If you are playing a podcast, however, you likely want to pause playback while the audio is ducked so the user doesn't miss any of the content.

En este ejemplo se declara una variable para hacer un seguimiento de si el contenido que se está reproduciendo actualmente es un podcast, se supone que se establece en el valor adecuado al seleccionar el contenido de la MediaPlayer.This example declares a variable to track whether the currently playing content is a podcast, it is assumed that you set this to the appropriate value when selecting the content for the MediaPlayer. También se crea una variable de clase para realizar el seguimiento cuando se pausa la reproducción mediante programación cuando cambia el nivel de audio.We also create a class variable to track when we pause playback programmatically when the audio level changes.

bool isPodcast;
bool isPausedDueToAudioStateMonitor;

En el controlador de eventos SoundLevelChanged , Compruebe la propiedad SoundLevel del remitente AudioStateMonitor para determinar el nuevo nivel de sonido.In the SoundLevelChanged event handler, check the SoundLevel property of the AudioStateMonitor sender to determine the new sound level. En este ejemplo se comprueba si el nuevo nivel de sonido es un volumen completo, lo que significa que el sistema ha dejado de silenciar o no el volumen, o si se ha reducido el nivel de sonido pero está reproduciendo contenido que no es de podcast.This example checks to see if the new sound level is full volume, meaning the system has stopped muting or ducking the volume, or if the sound level has been lowered but is playing non-podcast content. Si alguna de estas condiciones es verdadera y el contenido se pausó previamente mediante programación, se reanuda la reproducción.If either of these are true and the content was previously paused programmatically, playback is resumed. Si el nuevo nivel de sonido está silenciado o si el contenido actual es un podcast y el nivel de sonido es bajo, se pausa la reproducción y se establece la variable para hacer un seguimiento de que la pausa se inició mediante programación.If the new sound level is muted or if the current content is a podcast and the sound level is low, playback is paused, and the variable is set to track that the pause was initiated programatically.

private void AudioStateMonitor_SoundLevelChanged(Windows.Media.Audio.AudioStateMonitor sender, object args)
{
    if ((sender.SoundLevel == SoundLevel.Full) || (sender.SoundLevel == SoundLevel.Low && !isPodcast))
    {
        if (isPausedDueToAudioStateMonitor)
        {
            mediaPlayer.Play();
            isPausedDueToAudioStateMonitor = false;
        }
    }
    else if ((sender.SoundLevel == SoundLevel.Muted) ||
         (sender.SoundLevel == SoundLevel.Low && isPodcast))
    {
        if (mediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Playing)
        {
            mediaPlayer.Pause();
            isPausedDueToAudioStateMonitor = true;
        }
    }

}

El usuario puede decidir que desea pausar o continuar la reproducción, incluso si el sistema está pato en el audio.The user may decide that they want to pause or continue playback, even if the audio is ducked by the system. Este ejemplo muestra los controladores de eventos para un botón reproducir y pausa.This example shows event handlers for a play and a pause button. En el botón pausar, el controlador de clic está en pausa y, si ya se ha pausado la reproducción mediante programación, la variable se actualiza para indicar que el usuario ha pausado el contenido.In the pause button click handler is paused, if playback had already been paused programmatically, then we update the variable to indicate that the user has paused the content. En el controlador de clic del botón reproducir, se reanuda la reproducción y se borra la variable de seguimiento.In the play button click handler, we resume playback and clear our tracking variable.

private void PauseButton_User_Click(object sender, RoutedEventArgs e)
{
    if (isPausedDueToAudioStateMonitor)
    {
        isPausedDueToAudioStateMonitor = false;
    }
    else
    {
        mediaPlayer.Pause();
    }
}

public void PlayButton_User_Click()
{
    isPausedDueToAudioStateMonitor = false;
    mediaPlayer.Play();
}