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 Microsot.UI.Xaml.Controls namnområde 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. För mer information, se Aktivera enheten för utveckling.
- Visual Studio 2022 eller senare med Windows-programutveckling arbetsbelastning.
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 MediaCapture-klassen, 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 standardkontrollen StackPanel 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 klassdefinitionen MainWindow 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. Objektet DeviceInformation 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 ComboBox- 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 objektet MediaCapture genom att anropa InitializeAsyncoch 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 DeviceInformationCollectionmed 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 vi specifikt använder CPU-minne för videorutor. Med värdet Automatisk kan systemet använda GPU-minne om det är tillgängligt.
Innan vi initierar MediaCapture--objektet anropar vi AppCapability.CheckAccess--metod 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 appen Windows-inställningar under Sekretess & 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ök-block så att vi kan återhämta oss 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 bildkälla med färgvideodata, i motsats till en djupkamera till exempel, letar vi efter en bildkälla med en SourceKind av 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 fånga 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 ställer in egenskapen Source för MediaPlayer till ett nytt MediaSource objekt som vi skapar från vår valda MediaFrameSource.
Anropa Play på MediaPlayer--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 händelsen MediaFailed så att du kan hantera fel vid visning av förhandsvisningen.
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 Pausa på objektet MediaPlayer.
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();
}
Windows developer