Dela via


Visa kameraförhandsgranskningen i en WinUI 3-app

I den här snabbstarten får du lära dig hur du skapar en grundläggande WinUI 3-kameraapp som visar kameraförhandsgranskningen. I en WinUI 3-app använder du MediaPlayerElement-kontrollen i namnområdet Microsoft.UI.Xaml.Controls för att återge kameraförhandsgranskningen och WinRT-klassen MediaCapture för att få åtkomst till enhetens kameraförhandsgranskningsström. MediaCapture tillhandahåller API:er för att utföra en mängd olika kamerarelaterade uppgifter, till exempel att ta foton och videor och konfigurera kamerans enhetsdrivrutin. Mer information om andra MediaCapture-funktioner finns i de andra artiklarna i det här avsnittet.

Koden i den här genomgången är anpassad från Exemplet MediaCapture WinUI 3 på github.

Tips

UWP-versionen av den här artikeln finns i Visa kameraförhandsgranskningen i UWP-dokumentationen.

Förutsättningar

  • Enheten måste ha aktiverat utvecklarläge. Mer information finns i Inställningar för utvecklare.
  • Visual Studio 2022 eller senare med arbetsbelastningen WinUI-programutveckling .

Skapa en ny WinUI 3-app

Skapa ett nytt projekt i Visual Studio. I dialogrutan Skapa ett nytt projekt anger du språkfiltret till "C#" och plattformsfiltret till "Windows" och väljer sedan projektmallen "Tom app, paketerad (WinUI 3 på skrivbordet)".

Skapa användargränssnittet

Det enkla användargränssnittet för det här exemplet innehåller en MediaPlayerElement-kontroll för att visa kameraförhandsgranskningen, en ComboBox som gör att du kan välja bland enhetens kameror och knappar för att initiera Klassen MediaCapture , starta och stoppa kameraförhandsgranskningen och återställa exemplet. Vi inkluderar även en TextBlock för att visa statusmeddelanden.

I projektets MainWindow.xml-fil ersätter du stackPanel-standardkontrollen med följande 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>

Uppdatera mainwindow-klassdefinitionen

Resten av koden i den här artikeln läggs till i mainwindow-klassdefinitionen i projektets MainWindow.xaml.cs-fil. Lägg först till några klassvariabler som bevaras under hela fönstrets livslängd. Dessa variabler omfattar:

  • En DeviceInformationCollection som lagrar ett DeviceInformation-objekt för varje tillgänglig kamera. DeviceInformation-objektet förmedlar information som den unika identifieraren och kamerans eget namn.
  • Ett MediaCapture-objekt som hanterar interaktioner med den valda kamerans drivrutin och gör att du kan hämta kamerans videoström.
  • Ett MediaFrameSource-objekt som representerar en källa med medieramar, till exempel en videoström.
  • Ett booleskt värde för att hålla reda på när kameraförhandsgranskningen körs. Vissa kamerainställningar kan inte ändras när förhandsversionen körs, så det är en bra idé att spåra tillståndet för kameraförhandsgranskningen.
private DeviceInformationCollection m_deviceList;
private MediaCapture m_mediaCapture;
private MediaFrameSource m_frameSource;
private MediaPlayer m_mediaPlayer;
private bool m_isPreviewing;

Fyll i listan över tillgängliga kameror

Nu ska vi skapa en hjälpmetod för att identifiera de kameror som finns på den aktuella enheten och fylla i Kombinationsrutan i användargränssnittet med kameranamnen, så att användaren kan välja en kamera som ska förhandsgranskas. Med DeviceInformation.FindAllAsync kan du fråga efter många olika typer av enheter. Vi använder MediaDevice.GetVideoCaptureSelector för att hämta identifieraren som anger att vi bara vill hämta videoinspelningsenheter.

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

Lägg till ett anrop till den här hjälpmetoden i MainWindow-klasskonstruktorn så att ComboBox fylls i när fönstret läses in.

public MainWindow()
{
    this.InitializeComponent();

    PopulateCameraList();
    
}

Initiera MediaCapture-objektet

Initiera MediaCapture-objektet genom att anropa InitializeAsync och skicka in ett MediaCaptureInitializationSettings-objekt som innehåller de begärda initieringsparametrarna. Det finns många valfria initieringsparametrar som möjliggör olika scenarier. Se API-referenssidan för den fullständiga listan. I det här enkla exemplet anger vi några grundläggande inställningar, bland annat:

  • Egenskapen VideoDeviceId anger den unika identifieraren för kameran som MediaCapture ansluter till. Vi hämtar enhets-ID:t från DeviceInformationCollection med hjälp av det valda indexet för ComboBox.
  • Egenskapen SharingMode anger om appen begär delad, skrivskyddad åtkomst till kameran, vilket gör att du kan visa och fånga från videoströmmen eller exklusiv kontroll över kameran, vilket gör att du kan ändra kamerakonfigurationen. Flera appar kan läsas från en kamera samtidigt, men endast en app i taget kan ha exklusiv kontroll.
  • Egenskapen StreamingCaptureMode anger om vi vill spela in video, ljud eller ljud och video.
  • Med MediaCaptureMemoryPreference kan vi begära att specifikt använda CPU-minne för videorutor. Med värdet Auto kan systemet använda GPU-minne om det är tillgängligt.

Innan vi initierar MediaCapture-objektet anropar vi metoden AppCapability.CheckAccess för att avgöra om användaren har nekat vår app åtkomst till kameran i Windows-inställningar.

Not

Med Windows kan användare bevilja eller neka åtkomst till enhetens kamera i Windows-inställningar, under Sekretess och säkerhet –> Kamera. När du initierar avbildningsenheten bör appar kontrollera om de har åtkomst till kameran och hantera fallet där åtkomst nekas av användaren. Mer information finns i Hantera sekretessinställningen för Windows-kameran.

Anropet InitializeAsync görs inifrån ett försöksblock så att vi kan återställa om initieringen misslyckas. Appar bör hantera initieringsfel på ett korrekt sätt. I det här enkla exemplet visar vi bara ett felmeddelande om fel.

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

Initiera kameraförhandsgranskningen

När användaren klickar på knappen Starta förhandsversion försöker vi skapa en MediaFrameSource för en videoström från kameraenheten som MediaCapture-objektet initierades med. Tillgängliga ramkällor exponeras av egenskapen MediaCapture.FrameSources .

För att hitta en ramkälla som är färgvideodata, till skillnad från en djupkamera till exempel, letar vi efter en ramkälla som har en SourceKind of Color. Vissa kameradrivrutiner tillhandahåller en dedikerad förhandsgranskningsström som är separat från inspelningsströmmen. För att hämta förhandsgranskningsvideoströmmen försöker vi välja en ramkälla som har en MediaStreamType av VideoPreview. Om inga förhandsgranskningsströmmar hittas kan vi hämta inspelningsvideoströmmen genom att välja en MediaStreamType av VideoRecord. Om ingen av dessa ramkällor är tillgängliga kan den här avbildningsenheten inte användas för videoförhandsgranskning.

När vi har valt en ramkälla skapar vi ett nytt MediaPlayer-objekt som återges av MediaPlayerElement i vårt användargränssnitt. Vi anger egenskapen Source för MediaPlayer till ett nytt MediaSource-objekt som vi skapar från vår valda MediaFrameSource.

Anropa Spela uppMediaPlayer-objektet för att börja återge videoströmmen.

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

Implementera en hanterare för MediaFailed-händelsen så att du kan hantera fel vid rendering av förhandsgranskningen.

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

Stoppa kameraförhandsgranskningen

Om du vill stoppa kameraförhandsgranskningen anropar du PausaMediaPlayer-objektet .

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

Återställa appen

För att göra det enklare att testa exempelappen lägger du till en metod för att återställa appens tillstånd. Kameraappar bör alltid ta bort kameran och tillhörande resurser när kameran inte längre behövs.

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

}