Воспроизведение аудио и видео с помощью MediaPlayerPlay audio and video with MediaPlayer

В этой статье рассказывается, как воспроизводить мультимедиа в универсальном приложении для Windows с помощью класса MediaPlayer.This article shows you how to play media in your Universal Windows app using the MediaPlayer class. В Windows 10 версии 1607 были внесены значительные улучшения в интерфейсы API воспроизведения мультимедиа, включая упрощенную однопроцессную разработку для фонового звука, автоматическую интеграцию с системными элементами управления транспортным носителем (СМТК), возможность синхронизации нескольких проигрывателей мультимедиа, возможность отрисовки видеокадров в Windows. UI. композиция и простой интерфейс для создания и планирования разрывов мультимедиа в содержимом.With 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. Для реализации этих улучшений рекомендуется использовать класс MediaPlayer вместо MediaElement для воспроизведения мультимедийного содержимого.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. Добавлен облегченный элемент управления XAML MediaPlayerElement, предназначенный для отрисовки мультимедийного содержимого на странице XAML.The lightweight XAML control, MediaPlayerElement, has been introduced to allow you render media content in a XAML page. Многие API состояния и управления воспроизведением, предоставляемые классом MediaElement, теперь доступны с помощью нового объекта MediaPlaybackSession.Many of the playback control and status APIs provided by MediaElement are now available through the new MediaPlaybackSession object. MediaElement продолжает выполнять функцию поддержки обратной совместимости, но дополнительные возможности в этот класс добавляться не будут.MediaElement continues to function to support backwards compatibility, but no additional features will be added to this class.

Эта статья содержит подробный разбор функций MediaPlayer, которые обычно используются в приложениях для воспроизведения мультимедиа.This article will walk you through the MediaPlayer features that a typical media playback app will use. Обратите внимание, что MediaPlayer использует класс MediaSource в качестве контейнера для всех элементов мультимедиа.Note that MediaPlayer uses the MediaSource class as a container for all media items. Этот класс позволяет загружать и воспроизводить мультимедиа из множества различных источников, включая локальные файлы, потоки в памяти и сетевые источники, с использованием одного интерфейса.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. Также существуют классы более высокого уровня, совместимые с MediaSource, например MediaPlaybackItem и MediaPlaybackList, которые предоставляют расширенные возможности, такие как списки воспроизведения, и обеспечивают способность работать с источниками мультимедиа, содержащими несколько дорожек видео-, аудио- и метаданных.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. Подробные сведения о классе MediaSource и связанных с ним API см. в разделе Элементы, плей-листы и звуковые дорожки мультимедиа.For more information on MediaSource and related APIs, see Media items, playlists, and tracks.

Примечание

В выпусках Windows 10 N и Windows 10 KN нет компонентов мультимедиа, необходимых для использования MediaPlayer для воспроизведения.Windows 10 N and Windows 10 KN editions do not include the media features required to use MediaPlayer for playback. Эти компоненты можно установить вручную.These features can be installed manually. Дополнительные сведения см. в разделе Пакет дополнительных компонентов для работы с мультимедиа для выпусков Windows 10 N и Windows 10 KN.For more information, see Media feature pack for Windows 10 N and Windows 10 KN editions.

Воспроизведение файла мультимедиа с помощью MediaPlayerPlay a media file with MediaPlayer

Простое воспроизведение мультимедиа с помощью MediaPlayer реализовать очень легко.Basic media playback with MediaPlayer is very simple to implement. Сначала создайте новый экземпляр класса MediaPlayer.First, create a new instance of the MediaPlayer class. Ваше приложение может содержать несколько активных экземпляров MediaPlayer одновременно.Your app can have multiple MediaPlayer instances active at once. Затем задайте свойству Source проигрывателя значение объекта, реализующего IMediaPlaybackSource, такого как MediaSource, MediaPlaybackItem или 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. В этом примере MediaSource создается из файла в локальном хранилище приложения, затем из источника создается MediaPlaybackItem и далее назначается свойству Source проигрывателя.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.

В отличие от MediaElement, MediaPlayer по умолчанию не начинает воспроизведение автоматически.Unlike MediaElement, MediaPlayer does not automatically begin playback by default. Начать воспроизведение можно путем вызова Play, путем присвоения свойству AutoPlay значения true, а также можно дождаться, пока пользователь не начнет воспроизведение с помощью встроенных элементов управления мультимедиа.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();

Когда приложение завершает использование MediaPlayer, необходимо вызвать метод Close (соответствующий Dispose в C#), чтобы высвободить ресурсы, используемые проигрывателем.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();

Использование MediaPlayerElement для отрисовки видео в XAMLUse MediaPlayerElement to render video in XAML

Вы можете воспроизводить мультимедиа в MediaPlayer без отображения в XAML, но для многих приложений с воспроизведением мультимедиа потребуется отрисовка мультимедиа на странице 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. Для этого используйте облегченный элемент управления MediaPlayerElement.To do this, use the lightweight MediaPlayerElement control. Как и MediaElement, MediaPlayerElement позволяет указать, следует ли отображать встроенные элементы управления транспортировкой.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"/>

Вы можете задать экземпляр MediaPlayer, к которому привязан элемент управления, вызвав метод SetMediaPlayer.You can set the MediaPlayer instance that the element is bound to by calling SetMediaPlayer.

_mediaPlayerElement.SetMediaPlayer(mediaPlayer);

Вы можете также задать источник воспроизведения в MediaPlayerElement, и этот элемент автоматически создаст новый экземпляр MediaPlayer, получить доступ к которому можно с помощью свойства 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();

Примечание

Если вы отключите MediaPlaybackCommandManager в объекте MediaPlayer, установив для свойства IsEnabled значение false, это нарушит связь между свойством TransportControls объекта MediaPlayer, предоставляемым классом MediaPlayerElement, поэтому встроенные элементы управления транспортом больше не будут автоматически управлять воспроизведением мультимедиа.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. Вместо этого вам нужно будет реализовать собственные элементы управления для управления воспроизведением MediaPlayer.Instead, you must implement your own controls to control the MediaPlayer.

Типичные задачи, связанные с MediaPlayerCommon MediaPlayer tasks

В этом разделе рассказывается, как использовать некоторые функции MediaPlayer.This section shows you how to use some of the features of the MediaPlayer.

Задание категории аудиоSet the audio category

Задайте свойству AudioCategory объекта MediaPlayer одно из значений из перечисления MediaPlayerAudioCategory, чтобы сообщить системе, какой тип мультимедиа воспроизводится.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. Игры должны относить свои потоки музыки к категории GameMedia, чтобы звук музыки в игре автоматически отключался, если другое приложение воспроизводит музыку в фоновом режиме.Games should categorize their music streams as GameMedia so that game music mutes automatically if another application plays music in the background. Приложения для музыки и видео должны относить свои потоки к категории Media или Movie, чтобы у них был приоритет перед потоками 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;

Вывод на определенную конечную точку аудиоOutput to a specific audio endpoint

По умолчанию вывод звука из MediaPlayer направляется на конечную точку системы по умолчанию, но вы можете указать собственную конечную точку аудио, которую MediaPlayer будет использовать для вывода.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. В примере ниже MediaDevice.GetAudioRenderSelector возвращает строку, которая уникальным образом идентифицирует категорию обработки аудио для устройств.In the example below, MediaDevice.GetAudioRenderSelector returns a string that uniquely idenfies the audio render category of devices. Далее вызывается метод FindAllAsync класса DeviceInformation, чтобы получить список всех доступных устройств выбранного типа.Next, the DeviceInformation method FindAllAsync is called to get a list of all available devices of the selected type. Можно программным способом определить, какое устройство требуется использовать, или добавить возвращаемые устройства в ComboBox, чтобы пользователь мог выбрать устройство.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);
}

В событии SelectionChanged для поля со списком устройств свойству AudioDevice объекта MediaPlayer задано значение выбранного устройства, которое хранилось в свойстве Tag объекта 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;
    }
}

Сеанс воспроизведенияPlayback session

Как описано ранее в этой статье, множество функций, которые предоставляются классом MediaElement, перенесены в класс 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. Сюда относятся сведения о состоянии воспроизведения проигрывателя, такие как текущая позиция воспроизведения, включение режима паузы проигрывателя, а также текущая скорость воспроизведения.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 также предоставляет ряд событий, предназначенных для уведомления о смене состояния, включая текущую загрузку буфера и процент загрузки воспроизводимого содержимого, а также фактический размер и соотношение сторон воспроизводимого сейчас видео.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.

В следующем примере показано, как реализовать обработчик нажатия кнопки, который перематывает содержимое на 10 секунд вперед.The following example shows you how to implement a button click handler that skips 10 seconds forward in the content. Сначала с помощью свойства PlaybackSession создается объект MediaPlaybackSession для проигрывателя.First, the MediaPlaybackSession object for the player is retrieved with the PlaybackSession property. Затем свойству Position задается текущая позиция воспроизведения с добавлением 10 секунд.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);
}

Следующий пример иллюстрирует использование кнопки-переключателя для выбора обычной или двукратной скорости воспроизведения путем изменения свойства PlaybackRate этого сеанса.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;
}

Начиная с Windows 10 версии 1803 можно настроить поворот видео в MediaPlayer с шагом 90 градусов.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;

Обнаружение ожидаемой и непредвиденной буферизацииDetect expected and unexpected buffering

Объект MediaPlaybackSession, описанный в предыдущем разделе предоставляет два события для обнаружения момента начала и окончания буферизации проигрываемого в данный момент файла мультимедиа: BufferingStarted и 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. Это позволяет показывать в пользовательском интерфейсе состояние буферизации.This allows you to update your UI to show the user that buffering is occurring. Момент начала буферизации ожидается при первом открытии файла мультимедиа, а также при включении пользователем нового элемента в списке воспроизведения.Initial buffering is expected when a media file is first opened or when the user switches to a new item in a playlist. Непредвиденная буферизации может произойти при ухудшения скорости сетевой передачи или при возникновении технических сбоев в системе управления содержимым.Unexpected buffering can occur when the network speed degrades or if the content management system providing the content experiences technical issues. Начиная с RS3, можно использовать событие BufferingStarted, чтобы определить, является событие буферизации ожидаемым или непредвиденным, и прерывает ли оно воспроизведение.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. Эти сведения можно использовать в качестве данных телеметрии для вашего приложения или службы доставки содержимого.You can use this information as telemetry data for your app or media delivery service.

Зарегистрируйте обработчики для событий BufferingStarted и BufferingEnded, чтобы получать уведомления о состояния буферизации.Register handlers for the BufferingStarted and BufferingEnded events to receive buffering state notifications.

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

В обработчике события BufferingStarted приведите аргументы, переданных событию, к типу MediaPlaybackSessionBufferingStartedEventArgs и проверьте свойство IsPlaybackInterruption.In the BufferingStarted event handler, cast the event args passed into the event to a MediaPlaybackSessionBufferingStartedEventArgs object and check the IsPlaybackInterruption property. Если это значение равно true, то буферизация, ставшее причиной события, является непредвиденным и прерывает воспроизведение.If this value is true, the buffering that triggered the event is unexpected and interrupting playback. В противном случае — это ожидаемая буферизация.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
}

Сжатие и растяжение видеоPinch and zoom video

MediaPlayer позволяет определить в видеосодержимом прямоугольник источника, который подлежит отрисовке, что позволяет увеличивать определенную область видеоизображения.MediaPlayer allows you to specify the source rectangle within video content that should be rendered, effectively allowing you to zoom into video. Прямоугольник определяется относительно стандартного прямоугольника (0,0,1,1), где 0,0 соответствует верхнему левому углу кадра, а 1,1 задает полную ширину и высоту кадра.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. Например, чтобы установить прямоугольник увеличения в верхнюю правую часть отображаемого видео, необходимо задать прямоугольник (.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). Важно проверить устанавливаемые значения, чтобы ваш прямоугольник источника находился в пределах (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. Попытка установить значения за пределами этого диапазона приведет к возникновению исключения.Attempting to set a value outside of this range will cause an exception to be thrown.

Для реализации сжатия и растяжения с помощью мультисенсорных жестов сначала нужно определить, какие жесты вы хотите поддерживать.To implement pinch and zoom using multi-touch gestures, you must first specify which gestures you want to support. В этом примере запрашиваются жесты масштабирования и перехода.In this example, scale and translate gestures are requested. Событие ManipulationDelta возникает, когда выполняется один из запрошенных жестов.The ManipulationDelta event is raised when one of the subscribed gestures occurs. Событие DoubleTapped будет использоваться для сброса масштабирования до полного кадра.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;

Затем создайте объект Rect, который будет хранить текущий прямоугольник источника для масштабирования.Next, declare a Rect object that will store the current zoom source rectangle.

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

Обработчик ManipulationDelta подстраивает либо масштаб, либо перемещение прямоугольника масштабирования.The ManipulationDelta handler adjusts either the scale or the translation of the zoom rectangle. Если значение изменения масштаба не равно 1, это означает, что пользователь выполнил жест сжатия.If the delta scale value is not 1, it means that the user performed a pinch gesture. Если значение больше 1, прямоугольник источника необходимо уменьшить для увеличения содержимого.If the value is greater than 1, the source rectangle should be made smaller to zoom into the content. Если значение меньше 1, то прямоугольник источника необходимо сделать больше для уменьшения масштаба. Перед установкой новых значений масштабирования проверятся целевой прямоугольник, чтобы он находится в пределах (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.

Если значение масштабирования равно 1, обрабатывается жест перемещения.If the scale value is 1, then the translation gesture is handled. Прямоугольник просто перемещается на количество пикселей в жесте, разделенное на ширину и высоту элемента управления.The rectangle is simply translated by the number of pixels in gesture divided by the width and height of the control. И снова образуемый прямоугольник проверяется на предмет полного размещения в границах (0,0,1.1).Again, the resulting rectangle is checked to make sure it lies within the (0,0,1,1) bounds.

Наконец, свойству NormalizedSourceRect класса MediaPlaybackSession задается только что подогнанный прямоугольник, определяя область видеокадра, которую необходимо отобразить.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;
}

В обработчике событий DoubleTapped прямоугольник источника возвращается к значениям (0,0,1,1), что приводит к отрисовке всего видеокадра.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;
}

Примечание . В этом разделе описывается сенсорный ввод.NOTE This section describes touch input. Сенсорная панель отправляет события указателя и не отправляет события манипуляции.Touchpad sends pointer events and will not send Manipulation events.

Обработка снижения качества воспроизведения на основе политикHandling policy-based playback degradation

В некоторых случаях система уменьшить качество воспроизведения элемента мультимедиа, например, уменьшив разрешение (ограничением) на основе заданной политики, а не из-за проблемы с производительностью.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. Например, качество видео может снижено системой, если воспроизведение выполняется с использованием неподписанного видеодрайвера.For example, video may be degraded by the system if it is being played using an unsigned video driver. Вы можете вызвать метод MediaPlaybackSession.GetOutputDegradationPolicyState, чтобы определить выполняется ли ухудшение качества на основе политики и почему это происходит, после чего уведомить пользователя или записать причину этого события для сбора телеметрических данных.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.

В следующем примере показана реализация обработчика события MediaPlayer.MediaOpened, которое возникает при открытии нового элемента мультимедиа в средстве воспроизведения.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. Вызывается метод GetOutputDegradationPolicyState переданного в обработчик объекта MediaPlayer.GetOutputDegradationPolicyState is called on the MediaPlayer passed into the handler. Значение VideoConstrictionReason — это причину политики, из-за которой было ограничено воспроизведение видео.The value of VideoConstrictionReason indicates the policy reason that the video is constricted. Если значение не равно None, то этот пример записывает причину снижения качества для сбора телеметрических данных.If the value isn't None, this example logs the degradation reason for telemetry purposes. В этом примере также показана установка скорости воспроизводимого объекта AdaptiveMediaSource до наименьшего значения в целях экономии трафика, так как видео ограничено и в любом случае не будет воспроизводится в высоком разрешении.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. Дополнительные сведения об использовании AdaptiveMediaSource см. в разделе Адаптивная потоковая передача.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);
    }
}

Использование MediaPlayerSurface для отрисовки видео на поверхности Windows.UI.CompositionUse MediaPlayerSurface to render video to a Windows.UI.Composition surface

Начиная c Windows 10 версии 1607, можно использовать MediaPlayer для отрисовки видео на ICompositionSurface, что позволяет проигрывателю взаимодействовать с интерфейсами API в пространстве имен 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. Среда построения позволяет работать с изображениями на визуальном уровне между XAML и низкоуровневыми API графики DirectX.The composition framework allows you to work with graphics in the visual layer between XAML and the low-level DirectX graphics APIs. Это делает возможным реализацию таких сценариев, как отрисовка видео в любом элементе управления XAML.This enables scenarios like rendering video into any XAML control. Подробные сведения об использовании API построения см. в разделе Визуальный уровень.For more information on using the composition APIs, see Visual Layer.

В следующем примере показано, как отрисовывать содержимое видеопроигрывателя на элементе управления Canvas.The following example illustrates how to render video player content onto a Canvas control. В этом примере используются следующие характерные для проигрывателя мультимедиа вызовы: SetSurfaceSize и GetSurface.The media player-specific calls in this example are SetSurfaceSize and GetSurface. SetSurfaceSize сообщает системе размер буфера, который необходимо выделить для отрисовки содержимого.SetSurfaceSize tells the system the size of the buffer that should be allocated for rendering content. GetSurface принимает Compositor в качестве аргумента и запрашивает экземпляр класса MediaPlayerSurface.GetSurface takes a Compositor as an arguemnt and retreives an instance of the MediaPlayerSurface class. Этот класс предоставляет доступ к объектам MediaPlayer и Compositor, используемым для создания поверхности, и предоставляет саму поверхность с помощью свойства CompositionSurface.This class provides access to the MediaPlayer and Compositor used to create the surface and exposes the surface itself through the CompositionSurface property.

Остаток кода в этом примере создает объект SpriteVisual, на котором отрисовывается видео, и устанавливает размер в соответствии с размером элемента холста, который будет отображать визуальный элемент.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. Затем из MediaPlayerSurface создается CompositionBrush и назначается свойству Brush визуального элемента.Next a CompositionBrush is created from the MediaPlayerSurface and assigned to the Brush property of the visual. Затем создается объект ContainerVisual, и SpriteVisual вставляется в верхней части его визуального дерева.Next a ContainerVisual is created and the SpriteVisual is inserted at the top of its visual tree. Наконец, вызывается SetElementChildVisual для назначения визуального элемента контейнера объекту 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);

Используйте MediaTimelineController для синхронизации содержимого в нескольких проигрывателях.Use MediaTimelineController to synchronize content across multiple players.

Как отмечено ранее в этой статье, ваше приложение может иметь несколько активных объектов MediaPlayer одновременно.As discussed previously in this article, your app can have several MediaPlayer objects active at a time. По умолчанию каждый создаваемый вами объект MediaPlayer работает независимо.By default, each MediaPlayer you create operates independently. В некоторых случаях, например при синхронизации дорожки комментария с видео, может потребоваться синхронизировать состояние, положение воспроизведения и скорость воспроизведения нескольких проигрывателей.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. Начиная c Windows 10 версии 1607, можно реализовать это поведение с помощью класса MediaTimelineController.Starting with Windows 10, version 1607, you can implement this behavior by using the MediaTimelineController class.

Реализация элементов управления воспроизведениемImplement playback controls

В следующем примере показано, как использовать MediaTimelineController для управления двумя экземплярами MediaPlayer.The following example shows how to use a MediaTimelineController to control two instances of MediaPlayer. Во-первых, создается каждый экземпляр MediaPlayer, а в качестве Source задается файл мультимедиа.First, each instance of the MediaPlayer is instantiated and the Source is set to a media file. После этого создается новый MediaTimelineController.Next, a new MediaTimelineController is created. Для каждого MediaPlayer отключается соответствующий ему MediaPlaybackCommandManager путем установки значения false для свойства IsEnabled.For each MediaPlayer, the MediaPlaybackCommandManager associated with each player is disabled by setting the IsEnabled property to false. Затем в свойстве TimelineController указывается контроллер временной шкалы.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;

Внимание!MediaPlaybackCommandManager обеспечивает автоматическую интеграцию MediaPlayer и системных элементов управления транспортом мультимедиа (SMTC), однако эта автоматическая интеграция не может использоваться с проигрывателями мультимедиа, которыми управляет 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. Поэтому перед установкой контроллера временной шкалы проигрывателя необходимо отключить менеджер команд для проигрывателя мультимедиа.Therefore you must disable the command manager for the media player before setting the player's timeline controller. Невыполнение этого условия приведет к созданию исключения со следующим сообщением: "Attaching Media Timeline Controller is blocked because of the current state of the object" (Прикрепление контроллера временной шкалы мультимедиа заблокировано в связи с текущим состоянием объекта).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." Подробные сведения об интеграции проигрывателя с SMTC см. в разделе Интеграция с системными элементами управления транспортировкой мультимедиа.For more information on media player integration with the SMTC, see Integrate with the System Media Transport Controls. Если вы используете MediaTimelineController, управление SMTC по-прежнему можно осуществлять вручную.If you are using a MediaTimelineController you can still control the SMTC manually. Дополнительные сведения см. в разделе Ручное управление системными элементами управления воспроизведением мультимедиа.For more information, see Manual control of the System Media Transport Controls.

После прикрепления MediaTimelineController к одному или нескольким проигрывателям мультимедиа управлять состоянием воспроизведения можно с помощью методов, предоставляемых контроллером.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. В следующем примере производится вызов Start, чтобы начать воспроизведение с начала мультимедийного содержимого на всех связанных проигрывателях.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();
}

Этот пример иллюстрирует приостановку и возобновление воспроизведения на всех подключенных проигрывателях.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";
    }
}

Чтобы выполнить перемотку вперед на всех подключенных проигрывателях, задайте скорость воспроизведения выше 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;
}

В следующем примере показано, как использовать элемент управления Slider, чтобы отображать текущую позицию воспроизведения для контроллера временной шкалы относительно длительности содержимого одного из подключенных проигрывателей мультимедиа.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. Сначала создается новый объект MediaSource и регистрируется обработчик для события OpenOperationCompleted источника мультимедиа.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);

Обработчик OpenOperationCompleted используется как возможность для определения продолжительности содержимого источника мультимедиа.The OpenOperationCompleted handler is used as an opportunity to discover the duration of the media source content. После определения длительности максимальное значение элемента управления Slider устанавливается равным общему числу секунд в элементе мультимедиа.Once the duration is determined, the maximum value of the Slider control is set to the total number of seconds of the media item. Значение задается внутри вызова RunAsync, чтобы обеспечить выполнение в потоке пользовательского интерфейса.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;
    }); 
}

Далее регистрируется обработчик для события PositionChanged контроллера временной шкалы.Next, a handler for the timeline controller's PositionChanged event is registered. Этот вызов производится системой периодически, примерно 4 раза в секунду.This is called periodically by the system, approximately 4 times per second.

_mediaTimelineController.PositionChanged += _mediaTimelineController_PositionChanged;

В обработчике PositionChanged значение ползунка обновляется для отражения текущей позиции контроллера временной шкалы.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;
        });
    }
}

Смещение позиции воспроизведения относительно позиции временной шкалыOffset the playback position from the timeline position

В некоторых случаях может потребоваться смещение позиции воспроизведения одного или нескольких проигрывателей, связанных с контроллером временной шкалы, относительно других проигрывателей.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. Этого можно достичь, задав свойство TimelineControllerPositionOffset объекта MediaPlayer, для которого требуется смещение.You can do this by setting the TimelineControllerPositionOffset property of the MediaPlayer object you want to be offset. В следующем примере используются значения длительности содержимого двух проигрывателей мультимедиа для установки минимального и максимального значений двух ползунков управления в соответствии с длительностью элемента мультимедиа в отрицательном и положительном направлениях.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;

В событии ValueChanged для каждого ползунка свойству TimelineControllerPositionOffset каждого проигрывателя задается соответствующее значение.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);
}

Обратите внимание, что если значение смещения проигрывателя попадает на отрицательную позицию воспроизведения, содержимое останется в режиме паузы до достижения нулевого смещения, а затем начнется воспроизведение.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. Аналогичным образом, если значение смещения попадает на позицию воспроизведения, превышающую продолжительность элемента мультимедиа, будет отображаться последний кадр, как в случае достижения одним проигрывателем конца содержимого.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.

Воспроизведение сферической проекции видео с помощью MediaPlayerPlay spherical video with MediaPlayer

Начиная с Windows 10 версии 1703, MediaPlayer поддерживает равноугольную проекцию для сферического воспроизведения видео.Starting with Windows 10, version 1703, MediaPlayer supports equirectangular projection for spherical video playback. Видео в сферической проекции ничем не отличается от обычного плоского видео в том плане, что MediaPlayer выполняет отрисовку видео, если поддерживается кодирование.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. Если сферическое видео содержит тег метаданных, который указывает, что для видео используется равноугольная проекция, MediaPlayer может выполнить отрисовку с учетом указанного поля зрения и ориентации представления.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. Это позволяет реализовывать такие сценарии, как воспроизведение видео в виртуальной реальности в видеошлеме или панорамирование сферического видео с помощью мыши или клавиатуры.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.

Чтобы воспроизвести сферическое видео, выполните инструкции по воспроизведению видео, приведенные ранее в этой статье.To play back spherical video, use the steps for playing back video content described previously in this article. Еще один дополнительный шаг — зарегистрировать обработчик для события MediaPlayer. MediaOpened .The one additional step is to register a handler for the MediaPlayer.MediaOpened event. Это событие позволяет включать параметры воспроизведения сферического видео и управлять ими.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();

В обработчике MediaOpened в первую очередь необходимо проверить формат кадра недавно открытого мультимедийного элемента с помощью свойства 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. Если значение равно SphericaVideoFrameFormat.Equirectangular, система может автоматически проецировать видео.If this value is SphericaVideoFrameFormat.Equirectangular, then the system can automatically project the video content. Сначала задайте для свойства PlaybackSession.SphericalVideoProjection.IsEnabled значение true.First, set the PlaybackSession.SphericalVideoProjection.IsEnabled property to true. Также можно настроить другие свойства, например ориентацию представления и поле зрения, которые проигрыватель мультимедиа будет использовать при проецировании видео.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. В этом примере для поля зрения задано значение 120 градусов с помощью свойства HorizontalFieldOfViewInDegrees.In this example, the field of view is set to a wide value of 120 degrees by setting the HorizontalFieldOfViewInDegrees property.

Если видео сферическое, но формат проекции отличается от равноугольного, можно реализовать собственный алгоритм проецирования в режиме сервера кадров. Этот режим позволяет проигрывателю мультимедиа получать и обрабатывать отдельные кадры.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
    }
}

В следующем примере кода показано, как изменить ориентацию представления для сферического видео с помощью клавиш со стрелками влево и вправо.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;
    }
}

Если ваше приложение поддерживает списки воспроизведения видео, в пользовательском интерфейсе можно определить элементы воспроизведения, содержащие сферическое видео.If your app supports playlists of video, you may want to identify playback items that contain spherical video in your UI. Списки воспроизведения мультимедиа подробно описаны в статье, Элементы, списки воспроизведения и звуковые дорожки мультимедиа.Media playlists are discussed in detail in the article, Media items, playlists, and tracks. В следующем примере показано, как создать новый список воспроизведения, добавить элемент и зарегистрировать обработчик для события MediaPlaybackItem.VideoTracksChanged, которое возникает во время разрешения видеодорожек для элемента мультимедиа.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;

В обработчике события VideoTracksChanged получите свойства кодирования всех добавленных видеодорожек, вызвав метод VideoTrack.GetEncodingProperties.In the VideoTracksChanged event handler, get the encoding properties for any added video tracks by calling VideoTrack.GetEncodingProperties. Если значение свойства кодирования SphericalVideoFrameFormat отличается от SphericaVideoFrameFormat.None, то видеодорожка содержит сферическое видео. При необходимости можно внести соответствующие изменения в пользовательский интерфейс.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
        }
    }
}

Использование MediaPlayer в режиме сервера кадровUse MediaPlayer in frame server mode

Начиная с Windows 10 версии 1703, можно использовать MediaPlayer в режиме сервера кадров.Starting with Windows 10, version 1703, you can use MediaPlayer in frame server mode. В этом режиме MediaPlayer не выполняет автоматическую отрисовку кадров для соответствующего элемента MediaPlayerElement.In this mode, the MediaPlayer does not automatically render frames to an associated MediaPlayerElement. Вместо этого ваше приложение копирует текущий кадр из MediaPlayer в объект, реализующий IDirect3DSurface.Instead, your app copies the current frame from the MediaPlayer to an object that implements IDirect3DSurface. Основной сценарий, который реализует эта функция, заключается обработке видеокадров, предоставляемых MediaPlayer, с помощью построителей текстуры.The primary scenario this feature enables is using pixel shaders to process video frames provided by the MediaPlayer. Ваше приложение отвечает за отображение каждого кадра после обработки, например отображение кадра в элементе управления XAML Image.Your app is responsible for displaying each frame after processing, such as by showing the frame in a XAML Image control.

В следующем примере инициализируется новый MediaPlayer и загружается видео.In the following example, a new MediaPlayer is initialized and video content is loaded. Затем регистрируется обработчик для события VideoFrameAvailable.Next, a handler for VideoFrameAvailable is registered. Чтобы включить режим сервера кадров, задайте для свойства объекта MediaPlayerIsVideoFrameServerEnabled значение true.Frame server mode is enabled by setting the MediaPlayer object's IsVideoFrameServerEnabled property to true. Наконец, начните воспроизведение мультимедиа, вызвав метод 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();

В следующем примере показан обработчик для события VideoFrameAvailable, использующий Win2D для добавления простого эффекта размытия в каждый кадр видео. Затем обработанные кадры отображаются в элементе управления XAML Image.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.

Каждый раз, когда вызывается обработчик события VideoFrameAvailable, метод CopyFrameToVideoSurface используется для копирования содержимого кадра в IDirect3DSurface.Whenever the VideoFrameAvailable handler is called, the CopyFrameToVideoSurface method is used to copy the contents of the frame to an IDirect3DSurface. Также можно использовать CopyFrameToStereoscopicVideoSurfaces для копирования трехмерного содержимого в две плоскости, с отдельной обработкой данных для левого и правого глаза.You can also use CopyFrameToStereoscopicVideoSurfaces to copy 3D content into two surfaces, for processing the left eye and right eye content separately. Для получения объекта, реализующего IDirect3DSurface, в этом примере создается объект SoftwareBitmap. Этот объект впоследствии используется для создания объекта Win2D CanvasBitmap, реализующего необходимый интерфейс.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. CanvasImageSource — это объект Win2D, который можно использовать в качестве источника для элемента управления Image, поэтому создается новый объект и указывается в качестве источника для элемента управления Image, в котором отображается содержимое.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. Далее создается CanvasDrawingSession.Next, a CanvasDrawingSession is created. Win2D использует этот объект для отрисовки эффекта размытия.This is used by Win2D to render the blur effect.

После создания экземпляров всех необходимых объектов вызывается метод CopyFrameToVideoSurface, который копирует текущий кадр из MediaPlayer в CanvasBitmap.Once all of the necessary objects have been instantiated, CopyFrameToVideoSurface is called, which copies the current frame from the MediaPlayer into the CanvasBitmap. Затем создается объект Win2D GaussianBlurEffect, а CanvasBitmap указывается в качестве источника операции.Next, a Win2D GaussianBlurEffect is created, with the CanvasBitmap set as the source of the operation. Наконец, вызывается функция CanvasDrawingSession.DrawImage для рисования исходного изображения с примененным эффектом размытия. Это изображение передается в CanvasImageSource, связанный с элементом управления Image, и отрисовывается в пользовательском интерфейсе.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);
            }
        }
    });
}

Дополнительные сведения об использовании Win2D см. в репозитории Win2D в GitHub.For more information on Win2D, see the Win2D GitHub repository. Чтобы протестировать приведенный выше пример кода, необходимо добавить в проект пакет Win2D NuGet (см. инструкции ниже).To try out the sample code shown above, you will need to add the Win2D NuGet package to your project with the following instructions.

Добавление пакета Win2D NuGet в проект эффектаTo add the Win2D NuGet package to your effect project

  1. В обозревателе решений щелкните проект правой кнопкой мыши и выберите Управление пакетами NuGet.In Solution Explorer, right-click your project and select Manage NuGet Packages.
  2. В верхней части окна выберите вкладку Обзор.At the top of the window, select the Browse tab.
  3. В поле поиска введите Win2D.In the search box, enter Win2D.
  4. Выберите Win2D.uwp, а затем — Установить в области справа.Select Win2D.uwp, and then select Install in the right pane.
  5. В диалоговом окне Просмотр изменений отобразится назначенный для установки пакет.The Review Changes dialog shows you the package to be installed. Нажмите кнопку ОК.Click OK.
  6. Примите условия лицензии пакета.Accept the package license.

Обнаружение изменения громкости звука системой и реагирование на это событиеDetect and respond to audio level changes by the system

Начиная с Windows 10 версии 1803, ваше приложение может определить момент, когда система уменьшает громкость звука или отключает его в MediaPlayer, который осуществляет воспроизведение содержимого.Starting with Windows 10, version 1803, your app can detect when the system lowers or mutes the audio level of a currently playing MediaPlayer. Например, система может снизить уровень звука, если включается будильник.For example, the system may lower, or "duck", the audio playback level when an alarm is ringing. Система отключает звук приложения, когда оно переходит в фоновый режим, если приложение не объявило возможность backgroundMediaPlayback в манифесте приложения.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. В классе AudioStateMonitor можно зарегистрировать обработчик события, отправляемого когда система изменяет громкость звукового потока.The AudioStateMonitor class allows you to register to receive an event when the system modifies the volume of an audio stream. Обратитесь к свойству AudioStateMonitor объекта MediaPlayer и зарегистрируйте обработчик события SoundLevelChanged, чтобы получить уведомление про изменение системой громкости звука для 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;

При обработке события SoundLevelChanged, вы можете выполнить различные в зависимости от типа воспроизводимого содержимого.When handling the SoundLevelChanged event, you may take different actions depending on the type of content being played. Если в данный момент воспроизводится музыка, то, возможно, стоит не прерывать ее воспроизведение на время отключения звука.If you are currently playing music, then you may want to let the music continue to play while the volume is ducked. Однако, если идет воспроизведение подкаста, то, пожалуй, стоит приостановить процесс на время отключения звука, чтобы пользователь не пропустил часть прослушиваемого материала.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.

В этом примере объявляется переменная, в которой отслеживается не воспроизводится ли сейчас подкаст. Предполагается, что вы будете задавать правильное значение переменной при выборе содержимого для 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. Мы также сделали переменную класса, чтобы отслеживать момент программной приостановки воспроизведения после изменения громкости звука.We also create a class variable to track when we pause playback programmatically when the audio level changes.

bool isPodcast;
bool isPausedDueToAudioStateMonitor;

В обработчике события SoundLevelChanged проверьте свойство SoundLevel отправителя AudioStateMonitor и выясните каков новый уровень громкости.In the SoundLevelChanged event handler, check the SoundLevel property of the AudioStateMonitor sender to determine the new sound level. В этом примере проверяется, выставлен ли полный уровень громкости. Это означает, что система отменила выключение звука или уровень громкости был уменьшен, но идет воспроизведение не подкаста.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. Если любое из этих условий верно, а содержимое ранее было приостановлено программным способом, то воспроизведение возобновляется.If either of these are true and the content was previously paused programmatically, playback is resumed. Если звук был отключен, или если воспроизводится подкаст, и задана низкий уровень громкости, то воспроизведение приостанавливается и в переменной указывается, что пауза произведена программным способом.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;
        }
    }

}

Пользователь может выбрать — приостановить или продолжить воспроизведение, даже если звук был приглушен системой.The user may decide that they want to pause or continue playback, even if the audio is ducked by the system. В этом примере показаны обработчики событий для кнопок воспроизведения и паузы.This example shows event handlers for a play and a pause button. В обработчике нажатия кнопки паузы происходит следующее: если воспроизведение уже была приостановлено программно, то мы меняем значение переменной, чтобы указать, что это пользователь приостановил воспроизведение.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. В обработчике нажатия кнопки воспроизведения, мы возобновляем процесс и сбрасываем значение переменной.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();
}