MediaFrameSourceGroup を使用して複数のソースからキャプチャするCapture from multiple sources using MediaFrameSourceGroup

この記事では、複数のソースから同時にビデオをキャプチャして、複数のビデオ トラックが埋め込まれている 1 つのファイルを作成する方法について説明します。This article shows you how to capture video from multiple sources simultaneously to a single file with multiple embedded video tracks. RS3 以降では、1 つの MediaEncodingProfile に対して複数の VideoStreamDescriptor オブジェクトを指定できます。Starting with RS3, you can specify multiple VideoStreamDescriptor objects for a single MediaEncodingProfile. これにより、複数のストリームを同時に 1 つのファイルにエンコードすることができます。This enables you to encode multiple streams simultaneously to a single file. この操作でエンコードされたビデオ ストリームは、1 つの MediaFrameSourceGroup に含める必要があります。このクラスでは、現在のデバイスが備えている、同時使用が可能なカメラのセットを指定します。The video streams that are encoded in this operation must be included in a single MediaFrameSourceGroup which specifies a set of cameras on the current device that can be used at the same time.

MediaFrameReader クラスと共に MediaFrameSourceGroup を使用して、複数のカメラを利用するリアルタイムなコンピューター ビジョンのシナリオを実現する方法については、「MediaFrameReader を使ったメディア フレームの処理」をご覧ください。For information on using MediaFrameSourceGroup with the MediaFrameReader class to enable real-time computer vision scenarios that use multiple cameras, see Process media frames with MediaFrameReader.

この記事の残りの部分では、2 台のカラー カメラでビデオを録画し、複数のビデオ トラックが埋め込まれている 1 つのファイルを作成する手順について説明します。The rest of this article will walk you through the steps of recording video from two color cameras to a single file with multiple video tracks.

利用可能なセンサー グループを検索するFind available sensor groups

MediaFrameSourceGroup は、同時にアクセスできるフレーム ソース (通常はカメラ) のコレクションを表します。A MediaFrameSourceGroup represents a collection of frame sources, typically cameras, that can be accessed simulataneously. 利用可能なフレーム ソース グループのセットはデバイスごとに異なります。そのため、この例の最初の手順では、利用可能なフレーム ソース グループの一覧を取得し、シナリオで必要となるカメラを含んでいるグループを探します。この例では、2 台のカラー カメラが必要となります。The set of available frame source groups is different for each device, so the first step in this example is to get the list of available frame source groups and finding one that contains the necessary cameras for the scenario, which in this case requires two color cameras.

MediaFrameSourceGroup.FindAllAsync メソッドは、現在のデバイスで利用可能なすべてのソース グループを返します。The MediaFrameSourceGroup.FindAllAsync method returns all source groups available on the current device. 返された各 MediaFrameSourceGroup には、グループ内にある各フレーム ソースを記述する MediaFrameSourceInfo オブジェクトの一覧が含まれています。Each returned MediaFrameSourceGroup has a list of MediaFrameSourceInfo objects that describes each frame source in the group. Linq クエリを使用して、2 台のカラー カメラ (前面カメラと背面カメラ) を含んでいるソース グループを検索します。A Linq query is used to find a source group that contains two color cameras, one on the front panel and one on the back. 各カラー カメラについて選択した MediaFrameSourceGroupMediaFrameSourceInfo を含んでいる匿名オブジェクトが返されます。An anonymous object is returned that contains the selected MediaFrameSourceGroup and the MediaFrameSourceInfo for each color camera. Linq 構文を使用する代わりに、各グループをループ処理してから、各 MediaFrameSourceInfo をループ処理し、要件を満たしているグループを検索することもできます。Instead of using Linq syntax, you could instead loop through each group, and then each MediaFrameSourceInfo to look for a group that meets your requirements.

すべてのデバイスが 2 台のカラー カメラを含むソース グループを保持しているわけではありません。そのため、ビデオをキャプチャする前に、ソース グループが検出済みであるかどうかを確認する必要がありますNote that not every device will contain a source group that contains two color cameras, so you should check to make sure that a source group was found before trying to capture video.

var sensorGroups = await MediaFrameSourceGroup.FindAllAsync();

var foundGroup = sensorGroups.Select(g => new
{
    group = g,
    color1 = g.SourceInfos.Where(info => info.SourceKind == MediaFrameSourceKind.Color && info.DeviceInformation.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front).FirstOrDefault(),
    color2 = g.SourceInfos.Where(info => info.SourceKind == MediaFrameSourceKind.Color && info.DeviceInformation.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back).FirstOrDefault()
}).Where(g => g.color1 != null && g.color2 != null).FirstOrDefault();

if (foundGroup == null)
{
    Debug.WriteLine("No groups found.");
    return;
}

MediaCapture オブジェクトを初期化するInitialize the MediaCapture object

MediaCapture クラスは、UWP アプリでのほとんどのオーディオ、ビデオ、および写真のキャプチャ操作で使用されるプライマリ クラスです。The MediaCapture class is the primary class that is used for most audio, video, and photo capture operations in UWP apps. 初期化パラメーターを含んでいる MediaCaptureInitializationSettings オブジェクトを渡して InitializeAsync を呼び出し、オブジェクトを初期化します。Initialize the object by calling InitializeAsync, passing in a MediaCaptureInitializationSettings object that contains initialization parameters. この例では、指定した設定は SourceGroup プロパティのみで、前のコード例で取得された MediaFrameSourceGroup に設定されています。In this example, the only specified setting is the SourceGroup property, which is set to the MediaFrameSourceGroup that was retrieved in the previous code example.

メディアをキャプチャする場合に MediaCapture や他の UWP アプリの機能を使用して実行できるその他の操作については、「カメラ」をご覧ください。For information on other operations you can perform with MediaCapture and other UWP app features for capturing media, see Camera.

var settings = new MediaCaptureInitializationSettings()
{
    SourceGroup = foundGroup.group
};

mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync(settings);

MediaEncodingProfile を作成するCreate a MediaEncodingProfile

MediaEncodingProfile クラスは、キャプチャしたオーディオやビデオをファイルに書き込む際のエンコードの方法をメディア キャプチャ パイプラインに伝えます。The MediaEncodingProfile class tells the media capture pipeline how captured audio and video should be encoded as they are written to a file. 一般的なキャプチャやコード変換のシナリオでは、このクラスによって、一般的なプロファイル (CreateAviCreateMp3 など) を作成するための一連の静的メソッドが提供されます。For typical capture and transcoding scenarios, this class provides a set of static methods for creating common profiles, like CreateAvi and CreateMp3. この例では、Mpeg4 コンテナーと H264 ビデオ エンコードを使用して、エンコード プロファイルを手動で作成します。For this example, an encoding profile is manually created using an Mpeg4 container and H264 video encoding. ビデオ エンコードの設定は、VideoEncodingProperties オブジェクトを使用して指定します。Video encoding settings are specified using a VideoEncodingProperties object. このシナリオで使用される各カラー カメラに対して、VideoStreamDescriptor オブジェクトを構成します。For each color camera used in this scenario, a VideoStreamDescriptor object is configured. 記述子は、エンコードを指定する VideoEncodingProperties オブジェクトを使用して作成されます。The descriptor is constructed with the VideoEncodingProperties object specifying the encoding. VideoStreamDescriptorLabel プロパティは、ストリームにキャプチャされるメディア フレーム ソースの ID に設定する必要があります。The Label property of the VideoStreamDescriptor must be set to the ID of the media frame source that will be captured to the stream. この方法によって、キャプチャ パイプラインは、どのストリーム記述子とエンコード プロパティが各カメラで使用されるかを識別します。This is how the capture pipeline knows which stream descriptor and encoding properties should be used for each camera. フレーム ソースの ID は、MediaFrameSourceGroup が選択されたときに、MediaFrameSourceInfo オブジェクト (前のセクションをご覧ください) によって公開されます。The ID of the frame source is exposed by the MediaFrameSourceInfo objects that were found in the previous section, when a MediaFrameSourceGroup was selected.

Windows 10, version 1709 以降では、SetVideoTracks を呼び出すことによって、MediaEncodingProfile に対して複数のエンコード プロパティを設定できます。Starting with Windows 10, version 1709, you can set multiple encoding properties on a MediaEncodingProfile by calling SetVideoTracks. ビデオ ストリーム記述子の一覧は、GetVideoTracks を呼び出して取得することができます。You can retrieve the list of video stream descriptors by calling GetVideoTracks. 1 つのストリーム記述子を格納する Video プロパティを設定した場合、SetVideoTracks を呼び出して設定した記述子の一覧は、指定した 1 つの記述子を含んでいる一覧に置き換えられます。Note that if you set the Video property, which stores a single stream descriptor, the descriptor list you set by calling SetVideoTracks will be replaced with a list containing the single descriptor you specified.

var profile = new MediaEncodingProfile();
profile.Container = new ContainerEncodingProperties();
profile.Container.Subtype = MediaEncodingSubtypes.Mpeg4;

List<VideoStreamDescriptor> streams = new List<VideoStreamDescriptor>();

var encodeProps = VideoEncodingProperties.CreateH264();
encodeProps.Subtype = MediaEncodingSubtypes.H264;
var stream1Desc = new VideoStreamDescriptor(encodeProps);
stream1Desc.Label = foundGroup.color1.Id;
streams.Add(stream1Desc);

var encodeProps2 = VideoEncodingProperties.CreateH264();
encodeProps2.Subtype = MediaEncodingSubtypes.H264;
var stream2Desc = new VideoStreamDescriptor(encodeProps2);
stream2Desc.Label = foundGroup.color2.Id;
streams.Add(stream2Desc);

profile.SetVideoTracks(streams);
profile.Audio = null;

メディア ファイルでタイミングが設定されたメタデータをエンコードするEncode timed metadata in media files

Windows 10、バージョン 1803 以降では、オーディオとビデオに加え、タイミングが設定されたメタデータを、サポートされている形式のメディア ファイルにエンコードできます。Starting with Windows 10, version 1803, in addition to audio and video you can encode timed metadata into a media file for which the data format is supported. たとえば、GoPro メタデータ (gpmd) を MP4 ファイルに格納して、ビデオ ストリームに関連付けられた地理的位置情報を伝達できます。For example, GoPro metadata (gpmd) can be stored in MP4 files to convey the geographic location correlated with a video stream.

メタデータのエンコードでは、オーディオやビデオのエンコードと同様のパターンが使用されます。Encoding metadata uses a pattern that is parallel to encoding audio or video. TimedMetadataEncodingProperties クラスが、タイプ、サブタイプに加え、メタデータのエンコード プロパティを記述します (ビデオの VideoEncodingProperties に相当します)。The TimedMetadataEncodingProperties class describes the type, subtype and encoding properties of the metadata, like VideoEncodingProperties does for video. TimedMetadataStreamDescriptor は、メタデータ ストリームを識別します (ビデオ ストリームの VideoStreamDescriptor に相当します)。The TimedMetadataStreamDescriptor identifies a metadata stream, just as the VideoStreamDescriptor does for video streams.

次の例では、TimedMetadataStreamDescriptorオブジェクトを初期化する方法を示します。The following example shows how to intialize a TimedMetadataStreamDescriptor object. まず、TimedMetadataEncodingProperties オブジェクトが作成されると、Subtype が、ストリームに含めるメタデータのタイプを識別する GUID に設定されます。First, a TimedMetadataEncodingProperties object is created and the Subtype is set to a GUID that identifies the type of metadata that will be included in the stream. この例では、GoPro メタデータ (gpmd) の GUID が使用されています。This example uses the GUID for GoPro metadata (gpmd). SetFormatUserData メソッドが呼び出されて形式固有のデータが設定されます。The SetFormatUserData method is called to set format-specific data. MP4 ファイルの場合、形式固有のデータが SampleDescription ボックス (stsd) に格納されます。For MP4 files, the format-specific data is stored in the SampleDescription box (stsd). 次に、エンコード プロパティから、新しいTimedMetadataStreamDescriptor が作成されます。Next, a new TimedMetadataStreamDescriptor is created from the encoding properties. Label プロパティと Name プロパティが、エンコードするストリームの ID に設定されます。The Label and Name properties are set to identify the stream to be encoded.

           TimedMetadataEncodingProperties encodingProperties = new TimedMetadataEncodingProperties
           {
               Subtype = "{67706D64-BF10-48B4-BC18-593DC1DB950F}"
           };

           byte[] streamDescriptionData = GetStreamDescriptionDataForGpmdEncodingSubtype();
           encodingProperties.SetFormatUserData(streamDescriptionData);

           TimedMetadataStreamDescriptor descriptor = new TimedMetadataStreamDescriptor(encodingProperties)
           {
               Name = "GPS Info",
               Label = "GPS Info"
           };

呼び出す MediaEncodingProfile.SetTimedMetadataTracks エンコードのプロファイルに、メタデータ ストリーム記述子を追加します。Call MediaEncodingProfile.SetTimedMetadataTracks to add the metadata stream descriptor to the encoding profile. 次の例では、2 つのビデオ ストリーム記述子、1 つのオーディオ ストリーム記述子、1 つのタイミングが設定されたメタデータ ストリーム記述子を受け取り、ストリームのエンコードに使用できる MediaEncodingProfile を返すヘルパー メソッドを示します。The following example shows a helper method that takes two video stream descriptors, one audio stream descriptor, and one timed metadata stream descriptor and returns a MediaEncodingProfile that can be used to encode the streams.

public MediaEncodingProfile CreateProfileForTranscoder(VideoStreamDescriptor videoStream1, VideoStreamDescriptor videoStream2, AudioStreamDescriptor audioStream, TimedMetadataStreamDescriptor timedMetadataStream)
{
    ContainerEncodingProperties container = new ContainerEncodingProperties()
    {
        Subtype = MediaEncodingSubtypes.Mpeg4
    };

    MediaEncodingProfile profile = new MediaEncodingProfile()
    {
        Container = container
    };


    VideoStreamDescriptor encodingVideoStream1 = videoStream1.Copy();
    encodingVideoStream1.EncodingProperties.Subtype = MediaEncodingSubtypes.H264;
    encodingVideoStream1.Label = videoStream1.Name;

    VideoStreamDescriptor encodingVideoStream2 = videoStream2.Copy();
    encodingVideoStream2.EncodingProperties.Subtype = MediaEncodingSubtypes.H264;
    encodingVideoStream2.Label = videoStream2.Name;

    AudioStreamDescriptor encodingAudioStream = audioStream.Copy();
    encodingAudioStream.EncodingProperties.Subtype = MediaEncodingSubtypes.Ac3;
    encodingAudioStream.Label = audioStream.Name;

    TimedMetadataStreamDescriptor encodingTimedMetadataStream = timedMetadataStream.Copy();

    profile.SetTimedMetadataTracks(new TimedMetadataStreamDescriptor[] { encodingTimedMetadataStream });
    profile.SetVideoTracks(new VideoStreamDescriptor[] { encodingVideoStream1, encodingVideoStream2 });
    profile.SetAudioTracks(new AudioStreamDescriptor[] { encodingAudioStream });
    return profile;
}

マルチストリームの MediaEncodingProfile を使用して録画するRecord using the multi-stream MediaEncodingProfile

この例の最期の手順では、キャプチャしたメディアが書き込まれる StorageFile と前のコード例で作成した MediaEncodingProfile を渡して StartRecordToStorageFileAsync を呼び出し、ビデオ キャプチャを開始します。The final step in this example is to initiate video capture by calling StartRecordToStorageFileAsync, passing in the StorageFile to which the captured media is written, and the MediaEncodingProfile created in the previous code example. 数秒待機した後で、StopRecordAsync が呼び出され録画が停止します。After waiting a few seconds, the recording is stopped with a call to StopRecordAsync.

var recordFile = await Windows.Storage.KnownFolders.CameraRoll.CreateFileAsync("record.mp4", Windows.Storage.CreationCollisionOption.GenerateUniqueName);
await mediaCapture.StartRecordToStorageFileAsync(profile, recordFile);
await Task.Delay(8000);
await mediaCapture.StopRecordAsync();

操作が完了すると、各カメラからキャプチャしたビデオを含むビデオ ファイルが作成されます。このファイルでは、それぞれのビデオが個別のストリームとしてエンコードされています。When the operation is complete, a video file will have been created that contains the video captured from each camera encoded as a separate stream within the file. 複数のビデオ トラックが含まれているメディア ファイルを再生する方法について詳しくは、「メディア項目、プレイリスト、トラック」をご覧ください。For information on playing media files containing multiple video tracks, see Media items, playlists, and tracks.