MediaPlayer を使ったオーディオとビデオの再生Play audio and video with MediaPlayer

この記事では、MediaPlayer クラスを使ってユニバーサル Windows アプリでメディアを再生する方法を示します。This article shows you how to play media in your Universal Windows app using the MediaPlayer class. Windows 10 バージョン 1607 で、メディア再生 API が大幅に強化されました。これには、バックグラウンド オーディオ向けの簡素化された単一プロセス設計、システム メディア トランスポート コントロール (SMTC) との自動統合、複数のメディア プレーヤーを同期する機能、Windows.UI.Composition サーフェスに対する機能、コンテンツでメディアの中断を作成およびスケジュールするための簡単なインターフェイスなどが含まれます。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 a Windows.UI.Composition surface, and an easy interface for creating and scheduling media breaks in your content. これらの強化機能を活用できるように、メディアを再生するためのベスト プラクティスとして、メディア再生に MediaElement の代わりに MediaPlayer クラスを使うことが推奨されます。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. MediaElement によって提供される再生コントロールと状態 API の多くは、新しい 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. MediaPlaybackItemMediaPlaybackList など、MediaSource と共に使用できる上位レベルのクラスもあります。これらは、プレイリストや、複数のオーディオ、ビデオ、メタデータ トラックでメディア ソースを管理する機能など、より高度な機能を提供します。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 エディション用の Media Feature Pack」を参照してください。For more information, see Media feature pack for Windows 10 N and Windows 10 KN editions.

MediaPlayer でメディア ファイルを再生するPlay 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 プロパティを、MediaSourceMediaPlaybackItemMediaPlaybackList など、IMediaPlaybackSource を実装するオブジェクトに設定します。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 メソッド (C# で Dispose に投影される) を呼び出して、プレーヤーで使われるリソースをクリーンアップしてください。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 を使って XAML でビデオをレンダリングするUse MediaPlayerElement to render video in XAML

メディアを XAML で表示せずに MediaPlayer で再生することはできますが、多くのメディア再生アプリは 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"/>

SetMediaPlayer を呼び出して、要素がバインドされている MediaPlayer インスタンスを設定することができます。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();

注意

IsEnabled を false に設定して、MediaPlayerMediaPlaybackCommandManager を無効にすると、MediaPlayerElement で提供される MediaPlayerTransportControls の間のリンクが解除されます。このため組み込みトランスポート コントロールはプレーヤーの再生を自動的に制御しなくなります。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.

MediaPlayer の一般的なタスクCommon MediaPlayer tasks

このセクションでは、MediaPlayer の一部の機能の使用方法を示します。This section shows you how to use some of the features of the MediaPlayer.

オーディオ カテゴリの設定Set the audio category

MediaPlayerAudioCategory プロパティを 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. 音楽またはビデオ アプリケーションでは、ストリームの優先順位が GameMedia ストリームより高くなるように、ストリームを Media または Movie として分類してください。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. 次に、DeviceInformation メソッドの FindAllAsync を呼び出して、選択した種類の利用可能なデバイスの一覧を取得します。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 イベントで、MediaPlayerAudioDevice プロパティが選択されたデバイスに設定されます。これは、ComboBoxItemTag プロパティに格納されていました。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. まず、プレイヤーの MediaPlaybackSession オブジェクトが PlaybackSession プロパティで取得されます。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 プロパティを設定して通常の再生速度と 2 倍の速度を切り替えるトグル ボタンを示しています。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 オブジェクトでは、BufferingStartedBufferingEnded という 2 つのイベントによって、現在再生中のメディアファイルが開始および停止した時点を検出します。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. これにより、バッファー処理が行われていることを UI を更新の更新によってユーザーに表示できます。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. たとえば、ビデオを 4 分割した右上の領域がレンダリングされるようにズーム四角形を設定するには、四角形 (.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.

最後に、MediaPlaybackSessionNormalizedSourceRect が新たに調整された四角形に設定され、レンダリングするビデオ フレーム内の領域が指定されます。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;
}

ポリシーベースの再生品質低下の処理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. ハンドラーに渡された MediaPlayer に対して GetOutputDegradationPolicyStateが呼び出されます。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.Composition サーフェスにビデオをレンダリングするUse MediaPlayerSurface to render video to a Windows.UI.Composition surface

Windows 10 バージョン 1607 からは、MediaPlayer を使って ICompositionSurface にビデオをレンダリングできるため、プレイヤーは Windows.UI.Composition 名前空間で API と相互運用することができます。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 と低レベルの DirectX グラフィックス API の間のビジュアル レイヤーでグラフィックスを操作することができます。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. この例でのメディア プレーヤー固有の呼び出しは、SetSurfaceSizeGetSurface です。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. このクラスは、サーフェスを作成するために使われる MediaPlayerCompositor へのアクセスを提供し、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. 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 の 2 つのインスタンスを制御する方法を示しています。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 ごとに、IsEnabled プロパティを false に設定することで、各プレーヤー関連付けられている MediaPlaybackCommandManager が無効にされます。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. こうしないと、例外がスローされ、"オブジェクトの現在の状態により、メディア タイムライン コントローラーのアタッチがブロックされています。" というメッセージが表示されます。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.

1 つ以上のメディア プレーヤーに 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;
}

次の例は、スライダー コントロールを使って、接続されているメディア プレーヤーの 1 つのコンテンツの再生時間を基準としてタイムライン コント ローラーの現在の再生位置を表示する方法を示しています。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 の呼び出しの中で値を設定して、UI スレッドで実行されていることを確認します。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. これは 1 秒間に 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

場合によっては、タイムライン コント ローラーに関連付けられている 1 つ以上のメディア プレーヤーの再生位置に、他のプレーヤーからのオフセットを付けたいことがあります。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. これを行うには、オフセットを付ける MediaPlayer オブジェクトの TimelineControllerPositionOffset プロパティを設定します。You can do this by setting the TimelineControllerPositionOffset property of the MediaPlayer object you want to be offset. 次の例では、2 つのメディア プレーヤーのコンテンツの再生時間を使って、項目の長さを加えるか差し引くように 2 つのスライダー コントロールの最小値と最大値を設定しています。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. 同様に、オフセット値がメディア項目の再生時間を超える再生位置にマップされる場合は、1 つのメディア プレーヤーがそのコンテンツの最後に達したときのように最終フレームが表示されます。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.

MediaPlayer を使った球面ビデオの再生Play spherical video with MediaPlayer

Windows 10 Version 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. 1 つ追加される手順は、MediaPlayer.MediaOpened イベントのハンドラーを登録することです。The one additional step is to register a handler for the [MediaPlayer.MediaOpened])https://docs.microsoft.com/uwp/api/Windows.Media.Playback.MediaPlayer#Windows_Media_Playback_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. この例では、HorizontalFieldOfViewInDegrees プロパティを設定することによって、120 度という広い視野の値を設定しています。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;
    }
}

アプリでビデオの再生リストをサポートしている場合、UI で球面ビデオを含む再生項目の識別が必要になることがあります。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 以外の値である場合、ビデオ トラックには球面ビデオが含まれており、選択した場合は適切に UI を更新できます。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 Version 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. MediaPlayer オブジェクトの IsVideoFrameServerEnabled プロパティを 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();

次の例は、Win2D を使用してビデオの各フレームに単純なぼかし効果を追加し、処理されたフレームを XAML Image コントロールで表示する VideoFrameAvailable ハンドラーを示しています。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 を使用して 3D コンテンツを 2 つのサーフェスにコピーし、左目用と右目用のコンテンツを個別に処理することもできます。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. CanvasImageSourceImage コントロールのソースとして使用できる Win2D オブジェクトであるため、新しいオブジェクトを作成し、コンテンツを表示する 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 が呼び出され、ぼかし効果が適用されたソース画像が、Image コントロールに関連付けられた CanvasImageSource に描画され、それが UI に描画されます。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. [OK] をクリックします。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. その MediaPlayer のオーディオ レベルがシステムによって変更されたときに通知を受け取るには、MediaPlayerAudioStateMonitor プロパティにアクセスし、SoundLevelChanged イベントのハンドラーを登録します。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 イベント ハンドラーで、AudioStateMonitor センダーの SoundLevel プロパティを確認すると、新しいサウンド レベルを判定できます。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. これらのいずれかが true で、コンテンツがプログラムによって一時停止されている場合、再生が再開されます。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();
}