Festlegen von Format, Auflösung und Bildfrequenz für „MediaCapture“

In diesem Artikel erfahren Sie, wie Sie die IMediaEncodingProperties-Schnittstelle verwenden, um die Auflösung und Bildfrequenz des Kameravorschaustreams und aufgenommener Fotos und Videos festzulegen. Außerdem wird beschrieben, wie Sie sicherstellen, dass das Seitenverhältnis des Vorschaudatenstroms mit dem Seitenverhältnis der aufgenommenen Medien übereinstimmt.

Kameraprofile bieten eine erweiterte Möglichkeit zum Ermitteln und Festlegen der Datenstromeigenschaften der Kamera, werden jedoch für alle Geräte nicht unterstützt. Weitere Informationen finden Sie unter Kameraprofile.

Der Code in diesem Artikel wurde aus dem CameraResolution-Beispiel angepasst. Sie können das Beispiel herunterladen, um den verwendeten Code im Kontext zu sehen oder um das Beispiel als Ausgangspunkt für Ihre eigene Anwendung zu verwenden.

Hinweis

Dieser Artikel baut auf Konzepten und Code auf, die unter Allgemeine Foto-, Video- und Audioaufnahme mit „MediaCapture“ erläutert werden. Dort werden die Schritte für die Implementierung einer grundlegenden Foto- und Videoaufnahme beschrieben. Es wird empfohlen, dass Sie sich mit dem grundlegenden Muster für die Medienerfassung in diesem Artikel vertraut machen, bevor Sie in fortgeschrittene Aufnahmeszenarien einsteigen. Der Code in diesem Artikel setzt voraus, dass Ihre App bereits über eine korrekt initialisierte MediaCapture-Instanz verfügt.

Hilfsklasse für Mediencodierungseigenschaften

Das Erstellen einer einfachen Hilfsklasse zum Umschließen der Funktionalität der IMediaEncodingProperties-Schnittstelle erleichtert das Auswählen einer Reihe von Codierungseigenschaften, die bestimmten Kriterien entsprechen. Diese Hilfsklasse ist aufgrund des folgenden Verhaltens des Codierungseigenschaftenfeatures besonders nützlich:

Warnung Die VideoDeviceController.GetAvailableMediaStreamProperties-Methode akzeptiert ein Element der MediaStreamType-Aufzählung, z. B. VideoRecord oder Photo, und gibt eine Liste der ImageEncodingProperties- oder VideoEncodingProperties-Objekte zurück, die die Streamcodierungseinstellungen vermitteln, z. B. die Auflösung des aufgenommenen Fotos oder Videos. Die Ergebnisse des Aufrufens von GetAvailableMediaStreamProperties können ImageEncodingProperties oder VideoEncodingProperties enthalten, unabhängig davon, welcher MediaStreamType-Wert angegeben ist. Aus diesem Grund sollten Sie immer den Typ jedes zurückgegebenen Werts überprüfen und in den entsprechenden Typ umwandeln, bevor Sie versuchen, auf einen der Eigenschaftswerte zuzugreifen.

Die unten definierte Hilfsklasse behandelt die Typüberprüfung und -umwandlung für ImageEncodingProperties oder VideoEncodingProperties, sodass ihr App-Code nicht zwischen den beiden Typen unterscheiden muss. Darüber hinaus macht die Hilfsklasse Eigenschaften für das Seitenverhältnis der Eigenschaften, die Framerate (nur für Videocodierungseigenschaften) und einen Anzeigenamen verfügbar, mit dem die Codierungseigenschaften in der Benutzeroberfläche der App einfacher angezeigt werden können.

Sie müssen den Windows.Media.MediaProperties-Namespace in die Quelldatei für die Hilfsklasse einschließen.

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;
    }
    
}

Ermitteln, ob die Vorschau- und Aufnahmedatenströme unabhängig sind

Auf einigen Geräten wird der gleiche Hardware-Pin sowohl für Vorschau- als auch für Aufnahmedatenströme verwendet. Auf diesen Geräten wird durch Festlegen der Codierungseigenschaften eines geräts auch die andere festgelegt. Auf Geräten, die unterschiedliche Hardware-Pins für die Aufnahme und Vorschau verwenden, können die Eigenschaften für jeden Datenstrom unabhängig voneinander festgelegt werden. Verwenden Sie den folgenden Code, um zu ermitteln, ob die Vorschau- und Aufnahmedatenströme unabhängig sind. Sie sollten Die Benutzeroberfläche anpassen, um die Einstellung der Datenströme unabhängig vom Ergebnis dieses Tests zu aktivieren oder zu deaktivieren.

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");
    }
}

Abrufen einer Liste der verfügbaren Datenstromeigenschaften

Rufen Sie eine Liste der verfügbaren Streameigenschaften für ein Aufnahmegerät ab, indem Sie das MediaCapture-Objekt Ihrer App abrufen und dann GetAvailableMediaStreamProperties aufrufen und einen der MediaStreamType-Werte, VideoPreview, VideoRecord oder Photo übergeben. In diesem Beispiel wird linq-Syntax verwendet, um eine Liste von StreamPropertiesHelper-Objekten zu erstellen, die zuvor in diesem Artikel definiert wurden, für jeden der IMediaEncodingProperties-Werte, die von GetAvailableMediaStreamProperties zurückgegeben werden. In diesem Beispiel werden zunächst Linq-Erweiterungsmethoden verwendet, um die zurückgegebenen Eigenschaften basierend auf der Auflösung und dann auf der Framerate zu ordnen.

Wenn Ihre App bestimmte Auflösungs- oder Bildfrequenzanforderungen erfüllt, können Sie programmgesteuert eine Reihe von Mediencodierungseigenschaften auswählen. Eine typische Kamera-App macht stattdessen die Liste der verfügbaren Eigenschaften auf der Benutzeroberfläche verfügbar und ermöglicht es dem Benutzer, seine gewünschten Einstellungen auszuwählen. Für jedes Element in der Liste der StreamPropertiesHelper-Objekte in der Liste wird ein ComboBoxItem-Objekt erstellt. Der Inhalt wird auf den von der Hilfsklasse zurückgegebenen Anzeigenamen festgelegt, und das Tag wird auf die Hilfsklasse selbst festgelegt, sodass sie später zum Abrufen der zugehörigen Codierungseigenschaften verwendet werden kann. Jedes ComboBoxItem-Objekt wird dann dem comboBox-Objekt hinzugefügt, das an die Methode übergeben wird.

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);
    }
}

Festlegen der gewünschten Datenstromeigenschaften

Weisen Sie den Videogerätecontroller an, ihre gewünschten Codierungseigenschaften zu verwenden, indem Sie SetMediaStreamPropertiesAsync aufrufen und den MediaStreamType-Wert übergeben, der angibt, ob die Foto-, Video- oder Vorschaueigenschaften festgelegt werden sollen. In diesem Beispiel werden die angeforderten Codierungseigenschaften festgelegt, wenn der Benutzer ein Element in einem der ComboBox-Objekte auswählt, das mit der PopulateStreamPropertiesUI-Hilfsmethode aufgefüllt wird.

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);
    }
}

Anpassen des Seitenverhältnisses der Vorschau- und Aufnahmedatenströme

Eine typische Kamera-App stellt dem Benutzer eine Benutzeroberfläche bereit, um die Video- oder Fotoaufnahmeauflösung auszuwählen, legt jedoch die Vorschauauflösung programmgesteuert fest. Es gibt einige verschiedene Strategien für die Auswahl der besten Vorschaudatenstromauflösung für Ihre App:

  • Wählen Sie die höchste verfügbare Vorschauauflösung aus, sodass das UI-Framework alle erforderlichen Skalierungen der Vorschau ausführen kann.

  • Wählen Sie die Vorschauauflösung aus, die der Aufnahmeauflösung am nächsten kommt, sodass die Vorschau die nächste Darstellung des endgültig aufgenommenen Mediums anzeigt.

  • Wählen Sie die Vorschauauflösung aus, die der Größe des CaptureElement am nächsten kommt, sodass nicht mehr Pixel als erforderlich durch die Vorschaustreampipeline durchlaufen werden.

Wichtig : Auf einigen Geräten ist es möglich, ein anderes Seitenverhältnis für den Vorschaudatenstrom und den Aufnahmedatenstrom der Kamera festzulegen. Durch diesen Konflikt verursachtes Framezuschneiden kann dazu führen, dass Inhalte in den aufgenommenen Medien vorhanden sind, die in der Vorschau nicht sichtbar waren, was zu einer negativen Benutzererfahrung führen kann. Es wird dringend empfohlen, dasselbe Seitenverhältnis innerhalb eines kleinen Toleranzfensters für die Vorschau- und Aufnahmedatenströme zu verwenden. Es ist in Ordnung, dass völlig unterschiedliche Auflösungen für die Aufnahme und Vorschau aktiviert sind, solange das Seitenverhältnis eng übereinstimmt.

Um sicherzustellen, dass die Foto- oder Videoaufnahmedatenströme mit dem Seitenverhältnis des Vorschaudatenstroms übereinstimmen, ruft dieses Beispiel VideoDeviceController.GetMediaStreamProperties auf und übergibt den Enumerationswert "VideoPreview ", um die aktuellen Streameigenschaften für den Vorschaudatenstrom anzufordern. Als Nächstes wird ein kleines Seitenverhältnis-Toleranzfenster definiert, sodass wir Seitenverhältnisse einbeziehen können, die nicht genau mit dem Vorschaudatenstrom identisch sind, solange sie geschlossen sind. Als Nächstes wird eine Linq-Erweiterungsmethode verwendet, um nur die StreamPropertiesHelper-Objekte auszuwählen, bei denen sich das Seitenverhältnis innerhalb des definierten Toleranzbereichs des Vorschaudatenstroms befindet.

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;
}