Captura desde varios orígenes con MediaFrameSourceGroupCapture from multiple sources using MediaFrameSourceGroup

En este artículo se muestra cómo capturar vídeo de varios orígenes simultáneamente en un solo archivo con varias pistas de vídeo insertadas.This article shows you how to capture video from multiple sources simultaneously to a single file with multiple embedded video tracks. A partir de RS3, puede especificar varios objetos VideoStreamDescriptor para un único MediaEncodingProfile.Starting with RS3, you can specify multiple VideoStreamDescriptor objects for a single MediaEncodingProfile. Esto le permite codificar varias secuencias simultáneamente en un único archivo.This enables you to encode multiple streams simultaneously to a single file. Las secuencias de vídeo que se codifican en esta operación deben incluirse en una única MediaFrameSourceGroup que especifique un conjunto de cámaras en el dispositivo actual que se pueden usar al mismo tiempo.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.

Para obtener información sobre el uso de MediaFrameSourceGroup con la clase MediaFrameReader para habilitar escenarios de visión de equipos en tiempo real que usan varias cámaras, consulte procesamiento de fotogramas multimedia con 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.

El resto de este artículo le guiará a través de los pasos para grabar vídeo de dos cámaras de color a un solo archivo con varias pistas de vídeo.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.

Buscar grupos de sensores disponiblesFind available sensor groups

Un MediaFrameSourceGroup representa una colección de orígenes de fotogramas, normalmente cámaras, a la que se puede tener acceso simulataneously.A MediaFrameSourceGroup represents a collection of frame sources, typically cameras, that can be accessed simulataneously. El conjunto de grupos de orígenes de fotogramas disponibles es diferente para cada dispositivo, por lo que el primer paso de este ejemplo es obtener la lista de grupos de orígenes de fotogramas disponibles y encontrar uno que contenga las cámaras necesarias para el escenario, que en este caso requiere dos cámaras de color.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.

El método MediaFrameSourceGroup. FindAllAsync devuelve todos los grupos de origen disponibles en el dispositivo actual.The MediaFrameSourceGroup.FindAllAsync method returns all source groups available on the current device. Cada MediaFrameSourceGroup devuelto tiene una lista de objetos MediaFrameSourceInfo que describe cada origen de fotogramas del grupo.Each returned MediaFrameSourceGroup has a list of MediaFrameSourceInfo objects that describes each frame source in the group. Una consulta LINQ se usa para buscar un grupo de origen que contenga dos cámaras de color, una en el panel frontal y otra en la parte trasera.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. Se devuelve un objeto anónimo que contiene el MediaFrameSourceGroup seleccionado y el MediaFrameSourceInfo para cada cámara de color.An anonymous object is returned that contains the selected MediaFrameSourceGroup and the MediaFrameSourceInfo for each color camera. En lugar de usar la sintaxis de LINQ, puede recorrer en su lugar cada grupo y, a continuación, cada MediaFrameSourceInfo para buscar un grupo que cumpla sus requisitos.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.

Tenga en cuenta que no todos los dispositivos contendrán un grupo de origen que contenga dos cámaras de color, por lo que debe comprobar para asegurarse de que se ha encontrado un grupo de origen antes de intentar capturar el vídeo.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;
}

Inicializar el objeto MediaCaptureInitialize the MediaCapture object

La clase MediaCapture es la clase principal que se usa para la mayoría de las operaciones de captura de audio, vídeo y foto en aplicaciones UWP.The MediaCapture class is the primary class that is used for most audio, video, and photo capture operations in UWP apps. Inicialice el objeto llamando a InitializeAsync y pasando un objeto MediaCaptureInitializationSettings que contenga los parámetros de inicialización.Initialize the object by calling InitializeAsync, passing in a MediaCaptureInitializationSettings object that contains initialization parameters. En este ejemplo, la única configuración especificada es la propiedad SourceGroup , que se establece en el valor de MediaFrameSourceGroup que se recuperó en el ejemplo de código anterior.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.

Para obtener información sobre otras operaciones que puede realizar con MediaCapture y otras características de aplicaciones para UWP para capturar medios, consulte cámara.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);

Creación de un MediaEncodingProfileCreate a MediaEncodingProfile

La clase MediaEncodingProfile indica a la canalización de captura multimedia cómo se debe codificar el audio y el vídeo capturados a medida que se escriben en un archivo.The MediaEncodingProfile class tells the media capture pipeline how captured audio and video should be encoded as they are written to a file. En los escenarios de captura y transcodificación típicos, esta clase proporciona un conjunto de métodos estáticos para crear perfiles comunes, como CreateAvi y CreateMp3.For typical capture and transcoding scenarios, this class provides a set of static methods for creating common profiles, like CreateAvi and CreateMp3. En este ejemplo, se crea un perfil de codificación de forma manual mediante un contenedor MPEG4 y una codificación de vídeo H264.For this example, an encoding profile is manually created using an Mpeg4 container and H264 video encoding. La configuración de la codificación de vídeo se especifica mediante un objeto VideoEncodingProperties .Video encoding settings are specified using a VideoEncodingProperties object. Para cada cámara de color utilizada en este escenario, se configura un objeto VideoStreamDescriptor .For each color camera used in this scenario, a VideoStreamDescriptor object is configured. El descriptor se construye con el objeto VideoEncodingProperties que especifica la codificación.The descriptor is constructed with the VideoEncodingProperties object specifying the encoding. La propiedad Label de VideoStreamDescriptor debe establecerse en el identificador del origen del marco multimedia que se capturará en la secuencia.The Label property of the VideoStreamDescriptor must be set to the ID of the media frame source that will be captured to the stream. Así es como la canalización de captura sabe qué propiedades de descriptor de secuencia y de codificación deben usarse para cada cámara.This is how the capture pipeline knows which stream descriptor and encoding properties should be used for each camera. Los objetos MediaFrameSourceInfo que se encontraron en la sección anterior exponen el identificador del origen del marco, cuando se selecciona un MediaFrameSourceGroup .The ID of the frame source is exposed by the MediaFrameSourceInfo objects that were found in the previous section, when a MediaFrameSourceGroup was selected.

A partir de Windows 10, versión 1709, puede establecer varias propiedades de codificación en un MediaEncodingProfile llamando a SetVideoTracks.Starting with Windows 10, version 1709, you can set multiple encoding properties on a MediaEncodingProfile by calling SetVideoTracks. Puede recuperar la lista de descriptores de flujo de vídeo llamando a GetVideoTracks.You can retrieve the list of video stream descriptors by calling GetVideoTracks. Tenga en cuenta que si establece la propiedad vídeo , que almacena un único descriptor de secuencia, la lista de descriptores que se establece mediante una llamada a SetVideoTracks se reemplazará por una lista que contenga el único descriptor especificado.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;

Codificar metadatos con tiempo en archivos multimediaEncode timed metadata in media files

A partir de Windows 10, versión 1803, además de audio y vídeo, puede codificar los metadatos con tiempo en un archivo multimedia para el que se admite el formato de datos.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. Por ejemplo, los metadatos de GoPro (GPMD) se pueden almacenar en archivos MP4 para transmitir la ubicación geográfica correlacionada con una secuencia de vídeo.For example, GoPro metadata (gpmd) can be stored in MP4 files to convey the geographic location correlated with a video stream.

La codificación de metadatos usa un patrón que es paralelo a la codificación de audio o vídeo.Encoding metadata uses a pattern that is parallel to encoding audio or video. La clase TimedMetadataEncodingProperties describe las propiedades type, SubType y Encoding de los metadatos, como VideoEncodingProperties , para vídeo.The TimedMetadataEncodingProperties class describes the type, subtype and encoding properties of the metadata, like VideoEncodingProperties does for video. TimedMetadataStreamDescriptor identifica una secuencia de metadatos, igual que VideoStreamDescriptor , para las secuencias de vídeo.The TimedMetadataStreamDescriptor identifies a metadata stream, just as the VideoStreamDescriptor does for video streams.

En el ejemplo siguiente se muestra cómo inicializar un objeto TimedMetadataStreamDescriptor .The following example shows how to intialize a TimedMetadataStreamDescriptor object. En primer lugar, se crea un objeto TimedMetadataEncodingProperties y el subtipo se establece en un GUID que identifica el tipo de metadatos que se incluirán en la secuencia.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. En este ejemplo se usa el GUID para metadatos de GoPro (GPMD).This example uses the GUID for GoPro metadata (gpmd). Se llama al método SetFormatUserData para establecer datos específicos de formato.The SetFormatUserData method is called to set format-specific data. En el caso de los archivos MP4, los datos específicos del formato se almacenan en el cuadro SampleDescription (stsd).For MP4 files, the format-specific data is stored in the SampleDescription box (stsd). A continuación, se crea un nuevo TimedMetadataStreamDescriptor a partir de las propiedades de codificación.Next, a new TimedMetadataStreamDescriptor is created from the encoding properties. Las propiedades etiqueta y nombre se establecen para identificar la secuencia que se va a codificar.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"
           };

Llame a MediaEncodingProfile. SetTimedMetadataTracks para agregar el descriptor de flujo de metadatos al perfil de codificación.Call MediaEncodingProfile.SetTimedMetadataTracks to add the metadata stream descriptor to the encoding profile. En el ejemplo siguiente se muestra un método auxiliar que toma dos descriptores de flujo de vídeo, un descriptor de flujo de audio y un descriptor de flujo de metadatos con tiempo, y devuelve un MediaEncodingProfile que se puede usar para codificar las secuencias.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;
}

Registro mediante el MediaEncodingProfile de varios flujosRecord using the multi-stream MediaEncodingProfile

El último paso de este ejemplo es iniciar la captura de vídeo llamando a StartRecordToStorageFileAsync, pasando el elemento StorageFile en el que se escriben los medios capturados y MediaEncodingProfile creado en el ejemplo de código anterior.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. Después de esperar unos segundos, la grabación se detiene con una llamada a 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();

Una vez completada la operación, se creará un archivo de vídeo que contendrá el vídeo capturado de cada cámara codificada como una secuencia independiente dentro del archivo.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. Para obtener información sobre la reproducción de archivos multimedia que contienen varias pistas de vídeo, consulte elementos multimedia, listas de reproducción y pistas.For information on playing media files containing multiple video tracks, see Media items, playlists, and tracks.