Definir o formato, a resolução e a taxa de quadros para o MediaCaptureSet format, resolution, and frame rate for MediaCapture

Este artigo mostra como usar a interface IMediaEncodingProperties para definir a resolução e a taxa de quadro do fluxo de visualização da câmera e de fotos e vídeo capturados.This article shows you how to use the IMediaEncodingProperties interface to set the resolution and frame rate of the camera preview stream and captured photos and video. Ele também mostra como garantir que a taxa de proporção do fluxo de visualização corresponda ao da mídia capturada.It also shows how to ensure that the aspect ratio of the preview stream matches that of the captured media.

Perfis de câmera oferecem uma maneira mais avançada de descobrir e definir as propriedades de fluxo da câmera, mas eles não têm suporte em todos os dispositivos.Camera profiles offer a more advanced way of discovering and setting the stream properties of the camera, but they are not supported for all devices. Para obter mais informações, consulte Perfis de câmera.For more information, see Camera profiles.

O código neste artigo foi adaptado da amostra CameraResolution.The code in this article was adapted from the CameraResolution sample. Você pode baixar a amostra para ver o código usado no contexto ou usar a amostra como ponto de partida para seu próprio aplicativo.You can download the sample to see the code used in context or to use the sample as a starting point for your own app.

Observação

Este artigo se baseia em conceitos e códigos discutidos em Captura básica de fotos, áudio e vídeo com o MediaCapture, que descreve as etapas para implementar uma captura básica de fotos e vídeos.This article builds on concepts and code discussed in Basic photo, video, and audio capture with MediaCapture, which describes the steps for implementing basic photo and video capture. É recomendável que você se familiarize com o padrão de captura de mídia básica neste artigo antes de passar para cenários de captura mais avançados.It is recommended that you familiarize yourself with the basic media capture pattern in that article before moving on to more advanced capture scenarios. O código neste artigo presume que seu aplicativo já tenha uma instância de MediaCapture inicializada corretamente.The code in this article assumes that your app already has an instance of MediaCapture that has been properly initialized.

Uma classe auxiliar de propriedades de codificação de mídiaA media encoding properties helper class

Criar uma classe auxiliar simples para encapsular a funcionalidade da interface IMediaEncodingProperties torna mais fácil selecionar um conjunto de propriedades de codificação que atendem aos critérios específicos.Creating a simple helper class to wrap the functionality of the IMediaEncodingProperties interface makes it easier to select a set of encoding properties that meet particular criteria. Essa classe auxiliar é particularmente útil devido ao seguinte comportamento do recurso de propriedades de codificação:This helper class is particularly useful due to the following behavior of the encoding properties feature:

Aviso    O método VideoDeviceController. GetAvailableMediaStreamProperties usa um membro da enumeração MediaStreamType , como VideoRecord ou Photo, e retorna uma lista de objetos ImageEncodingProperties ou VideoEncodingProperties que transmitem as configurações de codificação de fluxo, como a resolução da foto ou vídeo capturado.Warning   The VideoDeviceController.GetAvailableMediaStreamProperties method takes a member of the MediaStreamType enumeration, such as VideoRecord or Photo, and returns a list of either ImageEncodingProperties or VideoEncodingProperties objects that convey the stream encoding settings, such as the resolution of the captured photo or video. Os resultados da chamada a GetAvailableMediaStreamProperties podem incluir ImageEncodingProperties ou VideoEncodingProperties, independentemente do valor de MediaStreamType especificado.The results of calling GetAvailableMediaStreamProperties may include ImageEncodingProperties or VideoEncodingProperties regardless of what MediaStreamType value is specified. Por esse motivo, você sempre deve verificar o tipo de cada valor retornado e convertê-lo para o tipo apropriado antes de tentar acessar qualquer um dos valores de propriedade.For this reason, you should always check the type of each returned value and cast it to the appropriate type before attempting to access any of the property values.

A classe auxiliar definida a seguir manipula a verificação e a conversão de tipo para ImageEncodingProperties ou VideoEncodingProperties, para que o código do aplicativo não precise distinguir entre os dois tipos.The helper class defined below handles the type checking and casting for ImageEncodingProperties or VideoEncodingProperties so that your app code doesn't need to distinguish between the two types. Além disso, a classe auxiliar expõe propriedades para a taxa de proporção das propriedades, a taxa de quadros (somente para propriedades de codificação de vídeo) e um nome amigável que facilita a exibição das propriedades de codificação na interface do usuário do aplicativo.In addition to this, the helper class exposes properties for the aspect ratio of the properties, the frame rate (for video encoding properties only), and a friendly name that makes it easier to display the encoding properties in the app's UI.

Você deve incluir o namespace Windows.Media.MediaProperties no arquivo de origem para a classe auxiliar.You must include the Windows.Media.MediaProperties namespace in the source file for the helper class.

using Windows.Media.MediaProperties;
using Windows.Media.Capture.Frames;
class StreamPropertiesHelper
{
    private IMediaEncodingProperties _properties;

    public StreamPropertiesHelper(IMediaEncodingProperties properties)
    {
        if (properties == null)
        {
            throw new ArgumentNullException(nameof(properties));
        }

        // This helper class only uses VideoEncodingProperties or VideoEncodingProperties
        if (!(properties is ImageEncodingProperties) && !(properties is VideoEncodingProperties))
        {
            throw new ArgumentException("Argument is of the wrong type. Required: " + typeof(ImageEncodingProperties).Name
                + " or " + typeof(VideoEncodingProperties).Name + ".", nameof(properties));
        }

        // Store the actual instance of the IMediaEncodingProperties for setting them later
        _properties = properties;
    }

    public uint Width
    {
        get
        {
            if (_properties is ImageEncodingProperties)
            {
                return (_properties as ImageEncodingProperties).Width;
            }
            else if (_properties is VideoEncodingProperties)
            {
                return (_properties as VideoEncodingProperties).Width;
            }

            return 0;
        }
    }

    public uint Height
    {
        get
        {
            if (_properties is ImageEncodingProperties)
            {
                return (_properties as ImageEncodingProperties).Height;
            }
            else if (_properties is VideoEncodingProperties)
            {
                return (_properties as VideoEncodingProperties).Height;
            }

            return 0;
        }
    }

    public uint FrameRate
    {
        get
        {
            if (_properties is VideoEncodingProperties)
            {
                if ((_properties as VideoEncodingProperties).FrameRate.Denominator != 0)
                {
                    return (_properties as VideoEncodingProperties).FrameRate.Numerator / 
                        (_properties as VideoEncodingProperties).FrameRate.Denominator;
                }
           }

            return 0;
        }
    }

    public double AspectRatio
    {
        get { return Math.Round((Height != 0) ? (Width / (double)Height) : double.NaN, 2); }
    }

    public IMediaEncodingProperties EncodingProperties
    {
        get { return _properties; }
    }

    public string GetFriendlyName(bool showFrameRate = true)
    {
        if (_properties is ImageEncodingProperties ||
            !showFrameRate)
        {
            return Width + "x" + Height + " [" + AspectRatio + "] " + _properties.Subtype;
        }
        else if (_properties is VideoEncodingProperties)
        {
            return Width + "x" + Height + " [" + AspectRatio + "] " + FrameRate + "FPS " + _properties.Subtype;
        }

        return String.Empty;
    }
    
}

Determinar se os fluxos de visualização e captura são independentesDetermine if the preview and capture streams are independent

Em alguns dispositivos, o mesmo pin de hardware é usado para fluxos de visualização e captura.On some devices, the same hardware pin is used for both preview and capture streams. Nesses dispositivos, a definição das propriedades de codificação de um também define o outro.On these devices, setting the encoding properties of one will also set the other. Em dispositivos que usam pins de hardware diferentes para captura e visualização, as propriedades podem ser definidas para cada fluxo de forma independente.On devices that use different hardware pins for capture and preview, the properties can be set for each stream independently. Use o código a seguir para determinar se os fluxos de visualização e captura são independentes.Use the following code to determine if the preview and capture streams are independent. Você deve ajustar sua interface do usuário para habilitar ou desabilitar a configuração dos fluxos de forma independente com base no resultado desse teste.You should adjust your UI to enable or disable the setting of the streams independently based on the result of this test.

private void CheckIfStreamsAreIdentical()
{
    if (_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.AllStreamsIdentical ||
        _mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.PreviewRecordStreamsIdentical)
    {
        ShowMessageToUser("Preview and video streams for this device are identical. Changing one will affect the other");
    }
}

Obter uma lista de propriedades de fluxo disponíveisGet a list of available stream properties

Obtenha uma lista das propriedades de fluxo disponíveis para um dispositivo de captura obtendo VideoDeviceController para o objeto MediaCapture do seu aplicativo e depois chamando GetAvailableMediaStreamProperties e transmitindo um dos valores de MediaStreamType: VideoPreview, VideoRecord ou Photo.Get a list of the available stream properties for a capture device by getting the VideoDeviceController for your app's MediaCapture object and then calling GetAvailableMediaStreamProperties and passing in one of the MediaStreamType values, VideoPreview, VideoRecord, or Photo. Neste exemplo, a sintaxe Linq é usada para criar uma lista de objetos StreamPropertiesHelper, definidos anteriormente neste artigo, para cada um dos valores IMediaEncodingProperties retornados de GetAvailableMediaStreamProperties.In this example, Linq syntax is used to create a list of StreamPropertiesHelper objects, defined previously in this article, for each of the IMediaEncodingProperties values returned from GetAvailableMediaStreamProperties. Este exemplo usa primeiro os métodos de extensão Linq para ordenar as propriedades retornadas com base, em primeiro lugar, na resolução e, depois, na taxa de quadros.This example first uses Linq extension methods to order the returned properties based first on resolution and then on frame rate.

Se seu aplicativo tiver requisitos de resolução ou de taxa de quadros específicos, você poderá selecionar um conjunto de propriedades de codificação de mídia de forma programática.If your app has specific resolution or frame rate requirements, you can select a set of media encoding properties programmatically. Um aplicativo de câmera comum expõe a lista de propriedades disponíveis na interface do usuário e permite que o usuário selecione as configurações desejadas.A typical camera app will instead expose the list of available properties in the UI and allow the user to select their desired settings. Um ComboBoxItem é criado para cada item na lista de objetos StreamPropertiesHelper na lista.A ComboBoxItem is created for each item in the list of StreamPropertiesHelper objects in the list. O conteúdo é definido como o nome amigável retornado pela classe auxiliar, e a marca é definida como a própria classe auxiliar para que ela possa ser usada posteriormente para recuperar as propriedades de codificação associadas.The content is set to the friendly name returned by the helper class and the tag is set to the helper class itself so it can be used later to retrieve the associated encoding properties. Cada ComboBoxItem é adicionado à ComboBox transmitida ao método.Each ComboBoxItem is then added to the ComboBox passed into the method.

private void PopulateStreamPropertiesUI(MediaStreamType streamType, ComboBox comboBox, bool showFrameRate = true)
{
    // Query all properties of the specified stream type 
    IEnumerable<StreamPropertiesHelper> allStreamProperties = 
        _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));

    // Order them by resolution then frame rate
    allStreamProperties = allStreamProperties.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);

    // Populate the combo box with the entries
    foreach (var property in allStreamProperties)
    {
        ComboBoxItem comboBoxItem = new ComboBoxItem();
        comboBoxItem.Content = property.GetFriendlyName(showFrameRate);
        comboBoxItem.Tag = property;
        comboBox.Items.Add(comboBoxItem);
    }
}

Definir as propriedades de fluxo desejadasSet the desired stream properties

Instrua o controlador de dispositivo de vídeo a usar as propriedades de codificação desejadas chamando SetMediaStreamPropertiesAsync, transmitindo o valor MediaStreamType, que indica se as propriedades de foto, vídeo ou visualização devem ser definidas.Tell the video device controller to use your desired encoding properties by calling SetMediaStreamPropertiesAsync, passing in the MediaStreamType value indicating whether the photo, video, or preview properties should be set. Este exemplo define as propriedades de codificação solicitadas quando o usuário seleciona um item em um dos objetos ComboBox populados com o método auxiliar PopulateStreamPropertiesUI.This example sets the requested encoding properties when the user selects an item in one of the ComboBox objects populated with the PopulateStreamPropertiesUI helper method.

private async void PreviewSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
    }
}
private async void PhotoSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, encodingProperties);
    }
}
private async void VideoSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, encodingProperties);
    }
}

Corresponder a taxa de proporção dos fluxos de visualização e capturaMatch the aspect ratio of the preview and capture streams

Um aplicativo de câmera típico fornecerá a interface do usuário para o usuário selecionar a resolução de captura de vídeo ou foto, mas definirá de forma programática a resolução da visualização.A typical camera app will provide UI for the user to select the video or photo capture resolution but will programmatically set the preview resolution. Há algumas estratégias diferentes para selecionar a melhor resolução de fluxo de visualização para seu aplicativo:There are a few different strategies for selecting the best preview stream resolution for your app:

  • Selecione a melhor resolução de visualização disponível, permitindo que a estrutura da IU execute qualquer dimensionamento necessário da visualização.Select the highest available preview resolution, letting the UI framework perform any necessary scaling of the preview.

  • Selecione a resolução de visualização mais próxima à resolução de captura para que a visualização mostre a representação mais próxima à mídia capturada final.Select the preview resolution closest to the capture resolution so that the preview displays the closest representation to the final captured media.

  • Selecione a resolução da visualização mais próxima ao tamanho do CaptureElement, para que não passem mais pixels do que o necessário pelo pipeline de fluxo de visualização.Select the preview resolution closest to the size of the CaptureElement so that no more pixels than necessary are going through the preview stream pipeline.

Importante    É possível, em alguns dispositivos, definir uma taxa de proporção diferente para o fluxo de visualização da câmera e o fluxo de captura.Important   It is possible, on some devices, to set a different aspect ratio for the camera's preview stream and capture stream. O corte de quadro causado por essa incompatibilidade pode resultar em conteúdo presente na mídia capturada que não estava visível na visualização, o que pode resultar em uma experiência de usuário negativa.Frame cropping caused by this mismatch can result in content being present in the captured media that was not visible in the preview which can result in a negative user experience. É altamente recomendável que você use a mesma taxa de proporção, dentro de uma pequena janela de tolerância, para os fluxos de visualização e captura.It is strongly recommended that you use the same aspect ratio, within a small tolerance window, for the preview and capture streams. Não há problemas em ter resoluções totalmente diferentes habilitadas para captura e visualização, desde que a taxa de proporção tenha correspondência aproximada.It is fine to have entirely different resolutions enabled for capture and preview as long as the aspect ratio match closely.

Para garantir que os fluxos de captura de foto ou de vídeo correspondam à taxa de proporção do fluxo de visualização, este exemplo chama VideoDeviceController.GetMediaStreamProperties e transmite o valor de enumeração VideoPreview para solicitar as propriedades de fluxo atuais para o fluxo de visualização.To ensure that the photo or video capture streams match the aspect ratio of the preview stream, this example calls VideoDeviceController.GetMediaStreamProperties and passes in the VideoPreview enum value to request the current stream properties for the preview stream. Em seguida, uma pequena janela de tolerância de taxa de proporção é definida para que possamos incluir taxas de proporção que não sejam exatamente iguais ao fluxo de visualização, desde que sejam aproximadas.Next a small aspect ratio tolerance window is defined so that we can include aspect ratios that are not exactly the same as the preview stream, as long as they are close. Em seguida, um método de extensão Linq é usado para selecionar apenas os objetos StreamPropertiesHelper em que a taxa de proporção esteja dentro do intervalo de tolerância definido do fluxo de visualização.Next, a Linq extension method is used to select just the StreamPropertiesHelper objects where the aspect ratio is within the defined tolerance range of the preview stream.

private void MatchPreviewAspectRatio(MediaStreamType streamType, ComboBox comboBox)
{
    // Query all properties of the specified stream type
    IEnumerable<StreamPropertiesHelper> allVideoProperties = 
        _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));

    // Query the current preview settings
    StreamPropertiesHelper previewProperties = new StreamPropertiesHelper(_mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview));

    // Get all formats that have the same-ish aspect ratio as the preview
    // Allow for some tolerance in the aspect ratio comparison
    const double ASPECT_RATIO_TOLERANCE = 0.015;
    var matchingFormats = allVideoProperties.Where(x => Math.Abs(x.AspectRatio - previewProperties.AspectRatio) < ASPECT_RATIO_TOLERANCE);

    // Order them by resolution then frame rate
    allVideoProperties = matchingFormats.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);

    // Clear out old entries and populate the video combo box with new matching entries
    comboBox.Items.Clear();
    foreach (var property in allVideoProperties)
    {
        ComboBoxItem comboBoxItem = new ComboBoxItem();
        comboBoxItem.Content = property.GetFriendlyName();
        comboBoxItem.Tag = property;
        comboBox.Items.Add(comboBoxItem);
    }
    comboBox.SelectedIndex = -1;
}