Impostare il formato, la risoluzione e la frequenza dei fotogrammi per MediaCaptureSet format, resolution, and frame rate for MediaCapture

Questo articolo illustra come usare l'interfaccia IMediaEncodingProperties per impostare la risoluzione e la frequenza dei fotogrammi del flusso di anteprima della fotocamera e delle foto acquisite e dei video.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. Illustra anche come verificare che le proporzioni del flusso di anteprima corrispondano a quelle del contenuto multimediale acquisito.It also shows how to ensure that the aspect ratio of the preview stream matches that of the captured media.

I profili di fotocamera offrono un modo più avanzato per individuare e impostare le proprietà di flusso della fotocamera, ma non sono supportati per tutti i dispositivi.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. Per altre informazioni, vedi Profili di fotocamera.For more information, see Camera profiles.

Il codice in questo articolo è stato adattato dall’esempio CameraResolution.The code in this article was adapted from the CameraResolution sample. Puoi scaricare l'esempio per visualizzare il codice nel contesto oppure per usarlo come punto di partenza per la tua app.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.

Nota

Questo articolo è basato sui concetti e sul codice illustrati in Acquisizione di foto, video e audio di base con MediaCapture, in cui sono descritti i passaggi per l'implementazione delle funzionalità di acquisizione di foto e video di base.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. È consigliabile acquisire familiarità con il modello di acquisizione multimediale di base presentato in tale articolo prima di passare a scenari di acquisizione più avanzati.It is recommended that you familiarize yourself with the basic media capture pattern in that article before moving on to more advanced capture scenarios. Il codice in questo articolo presuppone che l'app abbia già un'istanza di MediaCapture inizializzata correttamente.The code in this article assumes that your app already has an instance of MediaCapture that has been properly initialized.

Classe helper di proprietà di codifica multimedialeA media encoding properties helper class

La creazione di una semplice classe helper per eseguire il wrapping delle funzionalità dell’interfaccia IMediaEncodingProperties rende più semplice selezionare un set di proprietà di codifica che soddisfano criteri specifici.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. Questa classe helper è particolarmente utile, grazie al comportamento seguente della funzionalità per le proprietà di codifica:This helper class is particularly useful due to the following behavior of the encoding properties feature:

Avviso    di Il metodo VideoDeviceController. GetAvailableMediaStreamProperties accetta un membro dell'enumerazione MediaStreamType , ad esempio VideoRecord o Photo, e restituisce un elenco di oggetti ImageEncodingProperties o VideoEncodingProperties che comportano le impostazioni di codifica del flusso, ad esempio la risoluzione della foto o del video acquisito.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. I risultati della chiamata a GetAvailableMediaStreamProperties possono includere ImageEncodingProperties o VideoEncodingProperties, indipendentemente dal valore MediaStreamType specificato.The results of calling GetAvailableMediaStreamProperties may include ImageEncodingProperties or VideoEncodingProperties regardless of what MediaStreamType value is specified. Per questo motivo, prima di tentare di accedere ai valori di proprietà devi sempre verificare il tipo di ogni valore restituito ed eseguirne il cast al tipo appropriato.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.

La classe helper definita sotto gestisce il controllo dei tipi e il cast per ImageEncodingProperties o VideoEncodingProperties , in modo che il codice dell'app non debba distinguere i due tipi.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. Oltre a questo, la classe helper espone proprietà per le proporzioni, la frequenza di aggiornamento (solo per le proprietà di codifica video) e un nome descrittivo che rende più semplice visualizzare le proprietà di codifica nell'interfaccia utente dell'app.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.

È necessario includere lo spazio dei nomi Windows. Media. MediaProperties nel file di origine per la classe helper.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;
    }
    
}

Determinare se i flussi di anteprima e acquisizione sono indipendentiDetermine if the preview and capture streams are independent

In alcuni dispositivi viene usato lo stesso pin hardware sia per i flussi di anteprima che per quelli di acquisizione.On some devices, the same hardware pin is used for both preview and capture streams. In questi dispositivi, le proprietà di codifica impostate sono valide per entrambi i flussi.On these devices, setting the encoding properties of one will also set the other. Nei dispositivi che usano pin hardware diversi per l'acquisizione e l'anteprima, le proprietà possono essere impostate in modo indipendente per ogni flusso.On devices that use different hardware pins for capture and preview, the properties can be set for each stream independently. Usa il codice seguente per determinare se i flussi di anteprima e acquisizione sono indipendenti.Use the following code to determine if the preview and capture streams are independent. Devi adattare la tua interfaccia utente in modo da abilitare o disabilitare l'impostazione indipendente dei flussi in base ai risultati di questo test.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");
    }
}

Ottenere un elenco delle proprietà di flusso disponibiliGet a list of available stream properties

Per ottenere un elenco delle proprietà di flusso disponibili per un dispositivo di acquisizione, devi ottenere il VideoDeviceController per l’oggetto MediaCapture della tua app, quindi chiamare GetAvailableMediaStreamProperties e passare uno dei valori, MediaStreamType, VideoPreview, VideoRecord o 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. In questo esempio viene usata la sintassi Linq per creare un elenco di oggetti StreamPropertiesHelper, definiti in precedenza in questo articolo, per ognuno dei valori IMediaEncodingProperties restituiti da 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. Questo esempio usa prima di tutto i metodi di estensione Linq per ordinare le proprietà restituite, in base prima alla risoluzione e poi alla frequenza di aggiornamento.This example first uses Linq extension methods to order the returned properties based first on resolution and then on frame rate.

Se la tua app ha requisiti specifici in termini di risoluzione o frequenza di aggiornamento, puoi selezionare un set di proprietà di codifica multimediale a livello di programmazione.If your app has specific resolution or frame rate requirements, you can select a set of media encoding properties programmatically. Una tipica app per la fotocamera esporrà invece l'elenco delle proprietà disponibili nell'interfaccia utente e consentirà all'utente di selezionare le impostazioni desiderate.A typical camera app will instead expose the list of available properties in the UI and allow the user to select their desired settings. Viene creato un oggetto ComboBoxItem per ogni elemento nell’elenco di oggetti StreamPropertiesHelper nell’elenco.A ComboBoxItem is created for each item in the list of StreamPropertiesHelper objects in the list. Il contenuto viene impostato sul nome descrittivo restituito dalla classe helper e il tag viene impostato sulla classe helper stessa, in modo che sia possibile usarlo in seguito per recuperare le proprietà di codifica associate.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. Ogni oggetto ComboBoxItem viene quindi aggiunto all'oggetto ComboBox passato al metodo.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);
    }
}

Impostare le proprietà di flusso desiderateSet the desired stream properties

Indica al controller di dispositivo video di usare le proprietà di codifica che desideri chiamando SetMediaStreamPropertiesAsync e passando il valore MediaStreamType, che indica se impostare le proprietà per le foto, i video o l’anteprima.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. Questo esempio imposta le proprietà di codifica richieste quando l'utente seleziona un elemento in uno degli oggetti ComboBox popolati con il metodo helper 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);
    }
}

Far corrispondere le proporzioni dei flussi di anteprima e di acquisizioneMatch the aspect ratio of the preview and capture streams

Una tipica un'app per la fotocamera includerà l'interfaccia utente per selezionare la risoluzione di acquisizione di video o foto, ma imposterà la risoluzione di anteprima a livello di codice.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. Hai a disposizione alcune strategie diverse per selezionare la risoluzione migliore del flusso di anteprima per la tua app:There are a few different strategies for selecting the best preview stream resolution for your app:

  • Seleziona la massima risoluzione di anteprima disponibile, permettendo al framework dell'interfaccia utente di eseguire le operazioni di ridimensionamento dell'anteprima necessarie.Select the highest available preview resolution, letting the UI framework perform any necessary scaling of the preview.

  • Seleziona la risoluzione di anteprima più vicina alla risoluzione di acquisizione in modo che l'anteprima visualizzi la rappresentazione più simile all'elemento multimediale acquisito finale.Select the preview resolution closest to the capture resolution so that the preview displays the closest representation to the final captured media.

  • Selezionare la risoluzione di anteprima più vicina alla dimensione di CaptureElement in modo che non siano più presenti pixel del necessario per la pipeline del flusso di anteprima.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    In alcuni dispositivi è possibile impostare proporzioni diverse per il flusso di anteprima della fotocamera e il flusso di acquisizione.Important   It is possible, on some devices, to set a different aspect ratio for the camera's preview stream and capture stream. Il ritaglio dei fotogrammi provocato da questa incongruenza può causare la presenza nel file multimediale acquisito di contenuti non visibili nell'anteprima, con conseguenze negative sull'esperienza utente.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. Ti consigliamo vivamente di usare le stesse proporzioni, entro una stretta finestra di tolleranza, per i flussi di anteprima e acquisizione.It is strongly recommended that you use the same aspect ratio, within a small tolerance window, for the preview and capture streams. Non è un problema se sono abilitate risoluzioni diverse per l'acquisizione e l'anteprima, purché le proporzioni corrispondano il più possibile.It is fine to have entirely different resolutions enabled for capture and preview as long as the aspect ratio match closely.

Per verificare che i flussi di acquisizione di foto o video corrispondano alle proporzioni del flusso di anteprima, questo esempio chiama VideoDeviceController.GetMediaStreamProperties e passa il valore di enumerazione VideoPreview per richiedere le proprietà di flusso correnti per il flusso di anteprima.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. Di seguito viene definita una stretta finestra di tolleranza per le proporzioni, in modo che possiamo includere proporzioni non esattamente identiche a quelle del flusso di anteprima, purché molto vicine.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. Viene poi usato un metodo di estensione Linq per selezionare solo gli oggetti StreamPropertiesHelper le cui proporzioni rientrano nell'intervallo di tolleranza definito del flusso di anteprima.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;
}