Nastavení formátu, rozlišení a frekvence snímků pro MediaCapture v aplikaci WinUI

V tomto článku se dozvíte, jak pomocí rozhraní IMediaEncodingProperties nastavit rozlišení a frekvenci snímků streamu náhledu fotoaparátu a zachycených fotek a videa. Také ukazuje, jak zajistit, aby poměr stran streamu náhledu odpovídal poměru stran zachyceného média.

Profily fotoaparátu nabízejí jednodušší, vyšší úroveň mechanismu pro zjišťování a nastavení vlastností datového proudu fotoaparátu, ale nejsou podporovány pro všechna zařízení. Další informace naleznete v tématu Profily fotoaparátu.

Zjistěte, jestli jsou streamy náhledu a zachycení nezávislé

Na některých zařízeních se stejný hardwarový pin používá pro náhledový a záznamový stream. Na těchto zařízeních nastavení vlastností kódování, jako je formát, rozlišení a frekvence snímkování, na jednom ovlivní obě. Na zařízeních, která používají různé hardwarové piny pro zachycení a náhled, je možné nastavit vlastnosti pro každý datový proud nezávisle. Pomocí následujícího kódu určete, jestli jsou streamy náhledu a zachycení nezávislé. Tento příklad nastaví logickou globální proměnnou, která se dá použít k přepnutí chování aplikace, pokud jsou datové proudy sdílené nebo nezávislé.

if (m_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.AllStreamsIdentical ||
    m_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.PreviewRecordStreamsIdentical)
{
    m_captureAndPreviewStreamsIdentical = true;
}

Pomocná třída vlastností kódování médií

Vytvoření jednoduché pomocné třídy pro zabalení funkcí IMediaEncodingProperties rozhraní usnadňuje výběr sady vlastností kódování, které splňují konkrétní kritéria. Tato pomocná třída je zvláště užitečná z důvodu následujícího chování funkce vlastností kódování:

Poznámka:

Metoda VideoDeviceController.GetAvailableMediaStreamProperties přebírá člena výčtu MediaStreamType , například VideoRecord nebo Photo, a vrátí seznam objektů ImageEncodingProperties nebo VideoEncodingProperties , které vyjadřují nastavení kódování streamu, jako je rozlišení zachycené fotky nebo videa. Výsledky volání GetAvailableMediaStreamProperties mohou zahrnovat ImageEncodingProperties nebo VideoEncodingProperties bez ohledu na to, jaká hodnota MediaStreamType je zadána. Z tohoto důvodu byste měli vždy zkontrolovat typ každé z vrácených hodnot a než se pokusíte o přístup k některékoli z hodnot vlastností, ji přetypovat na příslušný datový typ.

Pomocná třída definovaná níže zpracovává kontrolu typů a přetypování pro ImageEncodingProperties nebo VideoEncodingProperties , aby kód aplikace nemusel rozlišovat mezi těmito dvěma typy. Kromě toho pomocná třída zveřejňuje vlastnosti pro poměr stran vlastností, snímkovou frekvenci (pouze pro vlastnosti kódování videa) a popisný název, který usnadňuje zobrazení vlastností kódování ve vašem uživatelském rozhraní.

class StreamPropertiesHelper
{
    private IMediaEncodingProperties _properties;

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

        // This helper class only uses ImageEncodingProperties 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;
    }

}

Získání seznamu dostupných vlastností streamu

Získejte seznam dostupných vlastností streamu pro zařízení zachycení získáním objektu VideoDeviceController pro objekt MediaCapture vaší aplikace a následným voláním GetAvailableMediaStreamProperties a předáním jedné z hodnot MediaStreamType, VideoPreview, VideoRecord nebo Photo. V tomto příkladu se vytvoří seznam Objektů StreamPropertiesHelper definovaných dříve v tomto článku pro každou z hodnot IMediaEncodingProperties vrácených z GetAvailableMediaStreamProperties. Tento příklad objednává vrácené vlastnosti nejprve na základě rozlišení a pak podle frekvence snímků.

Pokud má vaše aplikace specifické požadavky na rozlišení nebo snímkovou frekvenci, můžete programově vybrat sadu vlastností kódování médií. Typická aplikace fotoaparátu místo toho zveřejní seznam dostupných vlastností v uživatelském rozhraní a umožní uživateli vybrat požadované nastavení. Pro každou položku v seznamu Objektů StreamPropertiesHelper v seznamu je vytvořena ComboBoxItem. Obsah je nastaven na popisný název, který vrací pomocná třída, a značka je nastavena na tuto pomocnou třídu samotnou, aby ji bylo možné později použít k načtení přidružených vlastností kódování. Každý ComboBoxItem se pak přidá do pole ComboBox definovaného v uživatelském rozhraní.

private void bGetStreamProperties_Click(object sender, RoutedEventArgs e)
{
    // Query all properties of the specified stream type 
    IEnumerable<StreamPropertiesHelper> allStreamProperties =
        m_mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoRecord).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();
        comboBoxItem.Tag = property;
        cbStreamProperties.Items.Add(comboBoxItem);
    }
}

Nastavení požadovaných vlastností datového proudu

Sdělte řadiči videozařízení, aby používal požadované vlastnosti kódování voláním SetMediaStreamPropertiesAsync, předáním hodnoty MediaStreamType určující, zda má být nastavena fotografie, video nebo náhled vlastnosti. Tento příklad používá pole ComboBox vyplněné v příkladu z předchozí části, kde vlastnosti datového proudu médií jsou načteny z vlastnosti značky z vybrané položky.

private async void bSetStreamProperties_Click(object sender, RoutedEventArgs e)
{

    if (m_exclusiveCameraAccess)
    {
        var selectedItem = cbStreamProperties.SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await m_mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
    }
}

Upozorňujeme, že aplikace musí mít výhradní kontrolu nad zařízením pro zachytávání, aby mohla změnit vlastnosti datového proudu médií.

Porovná poměr stran náhledu a zachytávání datových proudů.

Typická aplikace fotoaparátu poskytne uživateli uživatelské rozhraní pro výběr rozlišení videa nebo snímku fotek, ale programově nastaví rozlišení náhledu. Existuje několik různých strategií pro výběr nejlepšího rozlišení streamu ve verzi Preview pro vaši aplikaci:

  • Vyberte nejvyšší dostupné rozlišení ve verzi Preview a nechte architekturu uživatelského rozhraní provádět potřebné škálování verze Preview.

  • Vyberte rozlišení náhledu co nejbližší rozlišení zachycení, aby náhled zobrazoval nejvěrnější reprezentaci finálním zachyceným médiím.

  • Vyberte rozlišení náhledu, které se nejvíce blíží velikosti CaptureElement, aby skrz streamovací kanál náhledu neprošlo více pixelů, než je potřeba.

Poznámka:

Na některých zařízeních je možné nastavit jiný poměr stran pro stream náhledu fotoaparátu a stream zachycení. Oříznutí rámečku způsobené touto neshodou může vést k tomu, že se obsah zobrazuje na zachycených médiích, které nebyly viditelné v náhledu, což může vést k negativnímu uživatelskému zážitku. Důrazně doporučujeme použít stejný poměr stran v malém okně tolerance pro náhled a zachytávání datových proudů. Pro zachytávání a náhledu je vhodné povolit úplně jiná rozlišení, pokud se poměr stran přesně shoduje.

Aby se zajistilo, že streamy zachycení fotek nebo videa odpovídají poměru stran streamu ve verzi Preview, tento příklad volá VideoDeviceController.GetMediaStreamProperties a předává hodnotu výčtu VideoPreview k vyžádání aktuálních vlastností streamu pro stream ve verzi Preview. Dále je definováno malé okno tolerance poměru stran, abychom mohli zahrnout poměry stran, které nejsou úplně stejné jako náhledový stream, pokud jsou blízké. Dále jsou vybrány objekty StreamPropertiesHelper, ve kterých je poměr stran v rámci definovaného rozsahu tolerance náhledového streamu.

// Query all properties of the specified stream type
IEnumerable<StreamPropertiesHelper> allVideoProperties =
    m_mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoRecord).Select(x => new StreamPropertiesHelper(x));

// Query the current preview settings
StreamPropertiesHelper previewProperties = new StreamPropertiesHelper(m_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
cbStreamProperties.Items.Clear();
foreach (var property in allVideoProperties)
{
    ComboBoxItem comboBoxItem = new ComboBoxItem();
    comboBoxItem.Content = property.GetFriendlyName();
    comboBoxItem.Tag = property;
    cbStreamProperties.Items.Add(comboBoxItem);
}

Poměr stran náhledu útržku kódu