Freigeben über


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 Bildrate des Kameravorschaustreams und der aufgenommenen 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, sie werden jedoch nicht für alle Geräte unterstützt. Weitere Informationen finden Sie unter Kameraprofile.

Der Code in diesem Artikel wurde aus dem CameraResolution-Beispiel übernommen und angepasst. Sie können das Beispiel herunterladen, um den verwendeten Code im Kontext anzuzeigen oder das Beispiel als Ausgangspunkt für Ihre eigene App 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.

Eine Hilfsklasse mit Mediencodierungseigenschaften

Durch das Erstellen einer einfachen Hilfsklasse zum Umschließen der Funktionalität der IMediaEncodingProperties-Schnittstelle ist es einfacher, eine Reihe von Codierungseigenschaften auszuwählen, die bestimmte Kriterien erfüllen. Aufgrund des folgenden Verhaltens des Codierungseigenschaftenfeatures ist diese Hilfsklasse besonders hilfreich:

Warnung Die VideoDeviceController.GetAvailableMediaStreamProperties-Methode übernimmt ein Element der MediaStreamType-Enumeration , z. B . VideoRecord oder Photo, und gibt eine Liste der ImageEncodingProperties - oder VideoEncodingProperties-Objekte zurück, die die Einstellungen für die Streamcodierung übermitteln, z. B. die Auflösung des aufgenommenen Fotos oder Videos. Die Ergebnisse des Aufrufs von GetAvailableMediaStreamProperties können ImageEncodingProperties oder VideoEncodingProperties enthalten, unabhängig vom angegebenen MediaStreamType-Wert. Aus diesem Grund sollten Sie vor dem Zugriff auf die Eigenschaftswerte immer den Typ jedes zurückgegebenen Werts überprüfen und ihn in den entsprechenden Typ umwandeln.

Die nachfolgend definierte Hilfsklasse behandelt die Typüberprüfung und -umwandlung für ImageEncodingProperties oder VideoEncodingProperties, damit der 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, der das Anzeigen der Codierungseigenschaften auf der App-UI erleichtert.

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

Bestimmen, ob der Vorschau- und Aufnahmedatenstrom voneinander unabhängig sind

Auf einigen Geräten wird für den Vorschau- und Aufnahmedatenstrom der gleiche Hardwarekontakt verwendet. Bei diesen Geräten werden durch Festlegen der Codierungseigenschaften eines Datenstroms auch die Codierungseigenschaften des anderen Datenstroms festgelegt. Für Geräte, die unterschiedliche Hardwarekontakte für die Aufnahme und Vorschau verwenden, können die Eigenschaften für jeden Datenstrom unabhängig voneinander festgelegt werden. Mit dem folgenden Code können Sie bestimmen, ob der Vorschau- und Aufnahmedatenstrom unabhängig voneinander sind. Sie sollten die Benutzeroberfläche anpassen, um abhängig vom Ergebnis dieses Tests das eigenständige Festlegen der Datenströme 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 Datenstromeigenschaften für ein Aufnahmegerät ab. Hierzu rufen Sie den VideoDeviceController für das MediaCapture-Objekt der App ab, rufen GetAvailableMediaStreamProperties auf und übergeben einen der MediaStreamType-Werte, d. h. VideoPreview, VideoRecord oder Photo In diesem Beispiel wird für jeden der von GetAvailableMediaStreamProperties zurückgegebenen IMediaEncodingProperties-Werte unter Verwendung von Linq-Syntax eine Liste von StreamPropertiesHelper-Objekten erstellt, die zuvor in diesem Artikel definiert wurden. In diesem Beispiel werden Linq-Erweiterungsmethoden verwendet, um die zurückgegebenen Eigenschaften zunächst nach Auflösung und dann nach Bildfrequenz zu sortieren.

Wenn für die App bestimmte Anforderungen an die Auflösung oder Bildfrequenz gelten, können Sie programmgesteuert eine Reihe von Mediencodierungseigenschaften auswählen. Eine Kamera-App macht stattdessen die Liste der verfügbaren Eigenschaften auf der Benutzeroberfläche verfügbar und ermöglicht es dem Benutzer, die gewünschten Einstellungen auszuwählen. Für jedes Listenelement von StreamPropertiesHelper-Objekten in der Liste wird ein ComboBoxItem erstellt. Der Inhalt wird auf den von der Hilfsklasse zurückgegebenen Anzeigenamen festgelegt, und das Tag wird auf die Hilfsklasse selbst festgelegt, sodass es später zum Abrufen der zugeordneten Codierungseigenschaften verwendet werden kann. Anschließend werden dem an die Methode übergebenen ComboBox-Element die einzelnen ComboBoxItem-Elemente hinzugefügt.

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, die gewünschten Codierungseigenschaften zu verwenden, indem Sie SetMediaStreamPropertiesAsync aufrufen und den MediaStreamType-Wert übergeben, der angibt, ob 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, die mithilfe der PopulateStreamPropertiesUI-Hilfsmethode aufgefüllt wurden.

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

Abgleichen des Seitenverhältnisses von Vorschau- und Aufnahmedatenstrom

Eine typische Kamera-App stellt zwar UI-Elemente bereit, mit denen der Benutzer die Auflösung für Video- oder Fotoaufnahmen festlegen kann, die Auflösung der Vorschau wird jedoch üblicherweise programmgesteuert festgelegt. Für die Wahl der optimalen Auflösung für den Vorschaudatenstrom Ihrer App gibt es unterschiedliche Strategien:

  • Wählen Sie die höchste verfügbare Vorschauauflösung aus, und überlassen Sie jegliche erforderliche Vorschauskalierung dem Benutzeroberflächenframework.

  • Wählen Sie die Vorschauauflösung aus, die der Aufnahmeauflösung am nächsten kommt, um eine möglichst geringe Diskrepanz zwischen Vorschau und tatsächlicher Medienaufnahme zu erreichen.

  • Wählen Sie die Vorschauauflösung aus, die möglichst genau der Größe des CaptureElement-Elements entspricht, damit nicht mehr Pixel als nötig die Pipeline für den Vorschaudatenstrom durchlaufen.

Wichtig Auf einigen Geräten ist es möglich, ein anderes Seitenverhältnis für den Vorschau- und Aufnahmestream der Kamera festzulegen. Durch diese Abweichung verursachtes Zuschneiden von Frames kann dazu führen, dass in den aufgenommenen Medien Inhalt vorhanden ist, der in der Vorschau nicht sichtbar war, sodass eine negative Benutzererfahrung die Folge ist. Es wird dringend empfohlen, für den Vorschau- und Aufnahmedatenstrom das gleiche Seitenverhältnis innerhalb eines kleinen Toleranzfensters zu verwenden. Solange das Seitenverhältnis nahezu übereinstimmt, können für Aufnahme und Vorschau vollkommen unterschiedliche Auflösungen aktiviert sein.

Um sicherzustellen, dass das Seitenverhältnis des Foto- oder Videoaufnahme-Datenstroms mit dem Seitenverhältnis des Vorschaudatenstroms übereinstimmt, wird in diesem Beispiel VideoDeviceController.GetMediaStreamProperties aufgerufen und der VideoPreview-Enumerationswert übergeben, um die aktuellen Datenstromeigenschaften des Vorschaudatenstroms anzufordern. Anschließend wird ein kleines Toleranzfenster für das Seitenverhältnis definiert, damit Seitenverhältnisse eingeschlossen werden können, die nicht genau mit dem Seitenverhältnis des Vorschaudatenstroms übereinstimmen, solange die Abweichung nicht groß ist. Dann werden mithilfe einer Linq-Erweiterungsmethode nur die StreamPropertiesHelper-Objekte ausgewählt, in denen das Seitenverhältnis im definierten Toleranzbereich des Vorschaudatenstroms liegt.

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