Delen via


Het cameravoorbeeld weergeven in een WinUI 3-app

In deze quickstart leert u hoe u een eenvoudige WinUI 3-camera-app maakt waarin het cameravoorbeeld wordt weergegeven. In een WinUI 3-app gebruikt u het besturingselement MediaPlayerElement in de naamruimte Microsoft.UI.Xaml.Controls om het cameravoorbeeld en de WinRT-klasse MediaCapture weer te geven voor toegang tot de stream cameravoorbeeld van het apparaat. MediaCapture biedt API's voor het uitvoeren van een breed scala aan camera-gerelateerde taken, zoals het vastleggen van foto's en video's en het configureren van het apparaatstuurprogramma van de camera. Zie de andere artikelen in deze sectie voor meer informatie over andere MediaCapture-functies .

De code in deze walkthrough is aangepast vanuit het MediaCapture WinUI 3-voorbeeld op github.

Aanbeveling

Zie De cameravoorbeeld weergeven in de UWP-documentatie voor de UWP-versie van dit artikel.

Vereiste voorwaarden

  • Op uw apparaat moet de ontwikkelaarsmodus zijn ingeschakeld. Zie Instellingen voor ontwikkelaars voor meer informatie.
  • Visual Studio 2022 of hoger met de winUI-toepassingsontwikkelingsworkload .

Een nieuwe WinUI 3-app maken

Maak in Visual Studio een nieuw project. Stel in het dialoogvenster Een nieuw project maken het taalfilter in op 'C#' en het platformfilter op 'Windows', selecteer vervolgens de projectsjabloon 'Blank App, Packaged (WinUI 3 in desktop)'.

De gebruikersinterface maken

De eenvoudige gebruikersinterface voor dit voorbeeld bevat een MediaPlayerElement-besturingselement voor het weergeven van het cameravoorbeeld, een ComboBox waarmee u een keuze kunt maken uit de camera's van het apparaat en knoppen voor het initialiseren van de MediaCapture-klasse , het starten en stoppen van het cameravoorbeeld en het opnieuw instellen van het voorbeeld. We bevatten ook een TextBlock voor het weergeven van statusberichten.

Vervang in het MainWindow.xml-bestand van uw project het standaard besturingselement StackPanel door de volgende XAML.

<Grid ColumnDefinitions="4*,*" ColumnSpacing="4">
    <MediaPlayerElement x:Name="mpePreview" Grid.Row="0" Grid.Column="0"  AreTransportControlsEnabled="False" ManipulationMode="None"/>
    <StackPanel Orientation="Vertical"  Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch"  VerticalAlignment="Top">
        <TextBlock Text="Status:" Margin="0,0,10,0"/>
        <TextBlock x:Name="tbStatus" Text=""/>
        <TextBlock Text="Preview Source:" Margin="0,0,10,0"/>
        <ComboBox x:Name="cbDeviceList" HorizontalAlignment="Stretch" SelectionChanged="cbDeviceList_SelectionChanged"></ComboBox>
        <Button x:Name="bStartMediaCapture" Content="Initialize MediaCapture" IsEnabled="False" Click="bStartMediaCapture_Click"/>
        <Button x:Name="bStartPreview" Content="Start preview" IsEnabled="False" Click="bStartPreview_Click"/>
        <Button x:Name="bStopPreview" Content="Stop preview" IsEnabled="False" Click="bStopPreview_Click"/>
        <Button x:Name="bReset" Content="Reset" Click="bReset_Click" />
    </StackPanel>
</Grid>

De mainWindow-klassedefinitie bijwerken

De rest van de code in dit artikel wordt toegevoegd aan de klassedefinitie MainWindow in het MainWindow.xaml.cs-bestand van uw project. Voeg eerst enkele klassevariabelen toe die gedurende de levensduur van het venster behouden blijven. Deze variabelen zijn onder andere:

  • Een DeviceInformationCollection waarmee een DeviceInformation-object wordt opgeslagen voor elke beschikbare camera. Het DeviceInformation-object bevat informatie zoals de unieke identifier en de gebruiksvriendelijke naam voor de camera.
  • Een MediaCapture-object dat interacties verwerkt met het stuurprogramma van de geselecteerde camera en waarmee u de videostream van de camera kunt ophalen.
  • Een MediaFrameSource-object dat een bron van mediaframes vertegenwoordigt, zoals een videostream.
  • Een Booleaanse waarde die moet worden bijgehouden wanneer het cameravoorbeeld wordt uitgevoerd. Sommige camera-instellingen kunnen niet worden gewijzigd terwijl de voorvertoning draait, dus het is een goede gewoonte om de status van de cameravoorvertoning in de gaten te houden.
private DeviceInformationCollection m_deviceList;
private MediaCapture m_mediaCapture;
private MediaFrameSource m_frameSource;
private MediaPlayer m_mediaPlayer;
private bool m_isPreviewing;

De lijst met beschikbare camera's vullen

Vervolgens maken we een helpermethode voor het detecteren van de camera's die aanwezig zijn op het huidige apparaat en vullen we de Keuzelijst met invoervak in de gebruikersinterface met de cameranamen, zodat de gebruiker een camera kan selecteren om een voorbeeld te bekijken. Met DeviceInformation.FindAllAsync kunt u query's uitvoeren op veel verschillende soorten apparaten. We gebruiken MediaDevice.GetVideoCaptureSelector om de id op te halen die aangeeft dat we alleen videoopnameapparaten willen ophalen.

private async void PopulateCameraList()
{
    cbDeviceList.Items.Clear();

    m_deviceList = await DeviceInformation.FindAllAsync(MediaDevice.GetVideoCaptureSelector());

    if(m_deviceList.Count == 0)
    {
        tbStatus.Text = "No video capture devices found.";
        return;
    } 

    foreach (var device in m_deviceList)
    {
        cbDeviceList.Items.Add(device.Name);
        bStartMediaCapture.IsEnabled = true;
    }
}

Voeg een aanroep aan deze helpermethode toe aan de constructor van de MainWindow-klasse, zodat de ComboBox wordt gevuld wanneer het venster wordt geladen.

public MainWindow()
{
    this.InitializeComponent();

    PopulateCameraList();
    
}

Het MediaCapture-object initialiseren

Initialiseer het MediaCapture-object door InitializeAsync aan te roepen, waarbij een MediaCaptureInitializationSettings-object wordt doorgegeven met de aangevraagde initialisatieparameters. Er zijn veel optionele initialisatieparameters die verschillende scenario's mogelijk maken. Zie de API-referentiepagina voor de volledige lijst. In dit eenvoudige voorbeeld geven we enkele basisinstellingen op, waaronder:

  • De eigenschap VideoDeviceId geeft de unieke id op van de camera waaraan de MediaCapture wordt gekoppeld. We halen de apparaat-id op uit de DeviceInformationCollection, met behulp van de geselecteerde index van de ComboBox.
  • De eigenschap SharingMode geeft aan of de app gedeelde, alleen-lezentoegang tot de camera aanvraagt, waarmee u de videostream kunt bekijken en vastleggen, of exclusief beheer van de camera, waarmee u de cameraconfiguratie kunt wijzigen. Meerdere apps kunnen tegelijkertijd van een camera lezen, maar slechts één app tegelijk kan exclusief beheer hebben.
  • De eigenschap StreamingCaptureMode geeft aan of we video, audio of audio en video willen vastleggen.
  • Met de MediaCaptureMemoryPreference kunnen we aanvragen om specifiek CPU-geheugen voor videoframes te gebruiken. Met de waarde Auto kan het systeem GPU-geheugen gebruiken als deze beschikbaar is.

Voordat het MediaCapture-object wordt geïnitialiseerd, wordt de methode AppCapability.CheckAccess aangeroepen om te bepalen of de gebruiker de toegang tot de app heeft geweigerd tot de camera in Windows-instellingen.

Opmerking

Met Windows kunnen gebruikers toegang verlenen of weigeren tot de camera van het apparaat in Windows-instellingen, onder Privacy en beveiliging -> Camera. Bij het initialiseren van het opnameapparaat moeten apps controleren of ze toegang hebben tot de camera en het geval afhandelen waarbij de toegang wordt geweigerd door de gebruiker. Zie De privacy-instelling van de Windows-camera afhandelen voor meer informatie.

De aanroep InitializeAsync wordt uitgevoerd vanuit een try-blok , zodat we kunnen herstellen als de initialisatie mislukt. Apps moeten de initialisatiefout probleemloos afhandelen. In dit eenvoudige voorbeeld geven we alleen een foutbericht weer bij een fout.

private async void bStartMediaCapture_Click(object sender, RoutedEventArgs e)
{
    if (m_mediaCapture != null)
    {
        tbStatus.Text = "MediaCapture already initialized.";
        return;
    }

    // Supported in Windows Build 18362 and later
    if(AppCapability.Create("Webcam").CheckAccess() != AppCapabilityAccessStatus.Allowed)
    {
        tbStatus.Text = "Camera access denied. Launching settings.";

        bool result = await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-webcam"));

        if (AppCapability.Create("Webcam").CheckAccess() != AppCapabilityAccessStatus.Allowed)
        {
            tbStatus.Text = "Camera access denied in privacy settings.";
            return;
        }
    }

    try
    {  
        m_mediaCapture = new MediaCapture();
        var mediaCaptureInitializationSettings = new MediaCaptureInitializationSettings()
        {
            VideoDeviceId = m_deviceList[cbDeviceList.SelectedIndex].Id,
            SharingMode = MediaCaptureSharingMode.ExclusiveControl,
            StreamingCaptureMode = StreamingCaptureMode.Video,
            MemoryPreference = MediaCaptureMemoryPreference.Auto
        };

        await m_mediaCapture.InitializeAsync(mediaCaptureInitializationSettings);

        tbStatus.Text = "MediaCapture initialized successfully.";

        bStartPreview.IsEnabled = true;
    }
    catch (Exception ex)
    {
        tbStatus.Text = "Initialize media capture failed: " + ex.Message;
    }
}

Het cameravoorbeeld initialiseren

Wanneer de gebruiker op de knop Startvoorbeeld klikt, proberen we een MediaFrameSource te maken voor een videostream vanaf het cameraapparaat waarmee het MediaCapture-object is geïnitialiseerd. De beschikbare framebronnen worden weergegeven door de eigenschap MediaCapture.FrameSources .

Als u een framebron wilt zoeken met kleurvideogegevens, in plaats van een dieptecamera, zoeken we bijvoorbeeld naar een framebron met een SourceKind of Color. Sommige camerastuurprogramma's bieden een speciale preview-stream die losstaat van de recordstream. Als we de voorbeeldvideostream willen ophalen, proberen we een framebron te selecteren met een MediaStreamType van VideoPreview. Als er geen voorbeeldstreams worden gevonden, kunnen we de videostream opnemen door een MediaStreamType van VideoRecord te selecteren. Als geen van deze framebronnen beschikbaar is, kan dit opnameapparaat niet worden gebruikt voor videovoorbeelden.

Zodra we een framebron hebben geselecteerd, maken we een nieuw MediaPlayer-object dat wordt weergegeven door het MediaPlayerElement in onze gebruikersinterface. We stellen de eigenschap Source van de MediaPlayer in op een nieuw MediaSource-object dat we maken op basis van onze geselecteerde MediaFrameSource.

Roep Afspelen aan op het MediaPlayer-object om de videostream weer te geven.

private void bStartPreview_Click(object sender, RoutedEventArgs e)
{
    
    m_frameSource = null;

    // Find preview source.
    // The preferred preview stream from a camera is defined by MediaStreamType.VideoPreview on the RGB camera (SourceKind == color).
    var previewSource = m_mediaCapture.FrameSources.FirstOrDefault(source => source.Value.Info.MediaStreamType == MediaStreamType.VideoPreview
                                                                                && source.Value.Info.SourceKind == MediaFrameSourceKind.Color).Value;

    if (previewSource != null)
    {
        m_frameSource = previewSource;
    }
    else
    {
        var recordSource = m_mediaCapture.FrameSources.FirstOrDefault(source => source.Value.Info.MediaStreamType == MediaStreamType.VideoRecord
                                                                                   && source.Value.Info.SourceKind == MediaFrameSourceKind.Color).Value;
        if (recordSource != null)
        {
            m_frameSource = recordSource;
        }
    }

    if (m_frameSource == null)
    {
        tbStatus.Text = "No video preview or record stream found.";
        return;
    }



    // Create MediaPlayer with the preview source
    m_mediaPlayer = new MediaPlayer();
    m_mediaPlayer.RealTimePlayback = true;
    m_mediaPlayer.AutoPlay = false;
    m_mediaPlayer.Source = MediaSource.CreateFromMediaFrameSource(m_frameSource);
    m_mediaPlayer.MediaFailed += MediaPlayer_MediaFailed; ;

    // Set the mediaPlayer on the MediaPlayerElement
    mpePreview.SetMediaPlayer(m_mediaPlayer);

    // Start preview
    m_mediaPlayer.Play();


    tbStatus.Text = "Start preview succeeded!";
    m_isPreviewing = true;
    bStartPreview.IsEnabled = false;
    bStopPreview.IsEnabled = true;
}

Implementeer een handler voor de MediaFailed-gebeurtenis , zodat u fouten kunt afhandelen die de preview weergeven.

private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
{
    tbStatus.Text = "MediaPlayer error: " + args.ErrorMessage;
}

Het cameravoorbeeld stoppen

Als u het cameravoorbeeld wilt stoppen, roept u Onderbreken aan op het MediaPlayer-object .

private void bStopPreview_Click(object sender, RoutedEventArgs e)
{
    // Stop preview
    m_mediaPlayer.Pause();
    m_isPreviewing = false;
    bStartPreview.IsEnabled = true;
    bStopPreview.IsEnabled = false;
}

De app opnieuw instellen

Als u de voorbeeld-app gemakkelijker wilt testen, voegt u een methode toe om de status van de app opnieuw in te stellen. Camera-apps moeten altijd de camera en bijbehorende bronnen verwijderen wanneer de camera niet meer nodig is.

private void bReset_Click(object sender, RoutedEventArgs e)
{
    if (m_mediaCapture != null)
    {
        m_mediaCapture.Dispose();
        m_mediaCapture = null;
    }

    if(m_mediaPlayer != null)
    {
        m_mediaPlayer.Dispose();
        m_mediaPlayer = null;
    }
    
    m_frameSource = null;
    

    bStartMediaCapture.IsEnabled = false;
    bStartPreview.IsEnabled = false;
    bStopPreview.IsEnabled = false;

    PopulateCameraList();

}