Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym szybkim przewodniku dowiesz się, jak utworzyć podstawową aplikację kamery WinUI 3 wyświetlającą podgląd kamery. W aplikacji WinUI 3 użyjesz kontrolki MediaPlayerElement w przestrzeni nazw Microsoft.UI.Xaml.Controls w celu renderowania podglądu aparatu i klasy WinRT MediaCapture w celu uzyskania dostępu do strumienia podglądu aparatu urządzenia. Aplikacja MediaCapture udostępnia interfejsy API do wykonywania szerokiej gamy zadań związanych z aparatem, takich jak przechwytywanie zdjęć i wideo oraz konfigurowanie sterownika urządzenia aparatu. Zobacz inne artykuły w tej sekcji, aby uzyskać szczegółowe informacje na temat innych funkcji MediaCapture .
Kod w tym przewodniku został dostosowany z przykładu MediaCapture WinUI 3 na GitHubie.
Wskazówka
Aby zapoznać się z wersją artykułu dla platformy UWP, zobacz Wyświetlanie podglądu aparatu w dokumentacji platformy UWP.
Wymagania wstępne
- Urządzenie musi mieć włączony tryb dewelopera. Aby uzyskać więcej informacji, zobacz Ustawienia dla deweloperów.
- Program Visual Studio 2022 lub nowszy z obciążeniem tworzenia aplikacji WinUI .
Tworzenie nowej aplikacji WinUI 3
W programie Visual Studio utwórz nowy projekt. W oknie dialogowym Tworzenie nowego projektu ustaw filtr języka na "C#" i filtr platformy na "Windows", a następnie wybierz szablon projektu "Pusta aplikacja, spakowana (WinUI 3 w komputerze stacjonarnym)."
Tworzenie interfejsu użytkownika
Prosty interfejs użytkownika dla tego przykładu obejmuje kontrolkę MediaPlayerElement do wyświetlania podglądu aparatu, ComboBox umożliwiający wybranie kamery z urządzenia oraz przyciski do inicjowania klasy MediaCapture, uruchamiania i zatrzymywania podglądu aparatu oraz resetowania przykładu. Uwzględniamy również element TextBlock do wyświetlania komunikatów o stanie.
W pliku MainWindow.xml projektu zastąp domyślną kontrolkę StackPanel następującym kodem 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>
Aktualizowanie definicji klasy MainWindow
Pozostała część kodu w tym artykule zostanie dodana do definicji klasy MainWindow w pliku MainWindow.xaml.cs projektu. Najpierw dodaj kilka zmiennych klasy, które będą utrwalane przez cały okres istnienia okna. Te zmienne obejmują:
- DeviceInformationCollection, który będzie przechowywać obiekt DeviceInformation dla każdego dostępnego aparatu. Obiekt DeviceInformation przekazuje informacje, takie jak unikatowy identyfikator i przyjazna nazwa aparatu.
- Obiekt MediaCapture , który obsługuje interakcje ze sterownikiem wybranego aparatu i umożliwia pobranie strumienia wideo aparatu.
- Obiekt MediaFrameSource reprezentujący źródło ramek multimedialnych, takich jak strumień wideo.
- Wartość logiczna do śledzenia, kiedy podgląd aparatu jest włączony. Niektórych ustawień aparatu nie można zmienić podczas uruchamiania podglądu, dlatego dobrym rozwiązaniem jest śledzenie stanu podglądu aparatu.
private DeviceInformationCollection m_deviceList;
private MediaCapture m_mediaCapture;
private MediaFrameSource m_frameSource;
private MediaPlayer m_mediaPlayer;
private bool m_isPreviewing;
Wypełnij listę dostępnych kamer
Następnie utworzymy metodę pomocnika do wykrywania kamer znajdujących się na bieżącym urządzeniu i wypełnienia pola ComboBox w interfejsie użytkownika nazwami aparatów, umożliwiając użytkownikowi wybranie aparatu do podglądu. Funkcja DeviceInformation.FindAllAsync umożliwia wykonywanie zapytań dotyczących wielu różnych rodzajów urządzeń. Używamy elementu MediaDevice.GetVideoCaptureSelector , aby pobrać identyfikator określający, że chcemy pobrać tylko urządzenia do przechwytywania wideo.
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;
}
}
Dodaj wywołanie tej metody pomocniczej do konstruktora klasy MainWindow , aby pole ComboBox było wypełniane po załadowaniu okna.
public MainWindow()
{
this.InitializeComponent();
PopulateCameraList();
}
Inicjowanie obiektu MediaCapture
Zainicjuj obiekt MediaCapture , wywołując metodę InitializeAsync, przekazując obiekt MediaCaptureInitializationSettings zawierający żądane parametry inicjowania. Istnieje wiele opcjonalnych parametrów inicjowania, które umożliwiają różne scenariusze. Aby uzyskać pełną listę, zobacz stronę dokumentacji interfejsu API. W tym prostym przykładzie określimy kilka podstawowych ustawień, w tym:
- Właściwość VideoDeviceId określa unikatowy identyfikator aparatu, do którego zostanie dołączony element MediaCapture . Uzyskujemy identyfikator urządzenia z DeviceInformationCollection, używając wybranego indeksu ComboBox.
- Właściwość SharingMode określa, czy aplikacja żąda udostępnionego, tylko do odczytu dostępu do aparatu, co umożliwia wyświetlanie i przechwytywanie ze strumienia wideo, czy wyłączną kontrolę nad aparatem, co umożliwia zmianę konfiguracji aparatu. Wiele aplikacji może jednocześnie odczytywać z aparatu, ale tylko jedna aplikacja jednocześnie może mieć wyłączną kontrolę.
- Właściwość StreamingCaptureMode określa, czy chcemy przechwytywać wideo, audio, czy audio i wideo.
- MediaCaptureMemoryPreference umożliwia nam zażądanie użycia pamięci CPU na potrzeby klatek wideo. Wartość Auto umożliwia systemowi użycie pamięci procesora GPU, jeśli jest dostępna.
Przed zainicjowaniem obiektu MediaCapture wywołujemy metodę AppCapability.CheckAccess , aby określić, czy użytkownik odmówił dostępu aplikacji do aparatu w ustawieniach systemu Windows.
Uwaga / Notatka
System Windows umożliwia użytkownikom udzielanie lub odmawianie dostępu do aparatu urządzenia w ustawieniach systemu Windows w obszarze Prywatność i zabezpieczenia —> aparat fotograficzny. Podczas inicjowania urządzenia do przechwytywania aplikacje powinny sprawdzać, czy mają dostęp do aparatu, i obsługiwać przypadek odmowy dostępu przez użytkownika. Aby uzyskać więcej informacji, zobacz Handle the Windows camera privacy setting (Obsługa ustawienia prywatności aparatu systemu Windows).
Wywołanie InitializeAsync jest wykonywane z wewnątrz bloku try , abyśmy mogli odzyskać, jeśli inicjowanie zakończy się niepowodzeniem. Aplikacje powinny płynnie obsługiwać niepowodzenie inicjowania. W tym prostym przykładzie po prostu wyświetlimy komunikat o błędzie po niepowodzeniu.
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;
}
}
Inicjowanie podglądu kamery
Gdy użytkownik kliknie przycisk Rozpocznij podgląd, podejmiemy próbę utworzenia elementu MediaFrameSource dla strumienia wideo z urządzenia aparatu, za pomocą którego zainicjowano obiekt MediaCapture . Dostępne źródła ramek są udostępniane przez właściwość MediaCapture.FrameSources .
Aby znaleźć źródło ramki będące kolorowymi danymi wideo, w odróżnieniu od kamery głębi, szukamy źródła ramki o SourceKind jako Color. Niektóre sterowniki kamer zapewniają dedykowany strumień podglądu, który jest oddzielony od strumienia nagrywania. Aby uzyskać podgląd strumienia wideo, spróbujemy wybrać źródło ramki z MediaStreamType ustawionym na VideoPreview. Jeśli nie znaleziono żadnych strumieni podglądu, możemy pobrać strumień wideo nagrywania, wybierając MediaStreamTypeVideoRecord. Jeśli żadne z tych źródeł klatek nie jest dostępne, nie można użyć tego urządzenia przechwytywania do podglądu wideo.
Po wybraniu źródła ramki utworzymy nowy obiekt MediaPlayer , który będzie renderowany przez element MediaPlayerElement w interfejsie użytkownika. Ustawiliśmy właściwość Source elementu MediaPlayer na nowy obiekt MediaSource tworzony na podstawie wybranego elementu MediaFrameSource.
Wywołaj Play na obiekcie MediaPlayer, aby rozpocząć renderowanie strumienia wideo.
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;
}
Zaimplementuj procedurę dla zdarzenia MediaFailed, aby obsłużyć błędy renderowania podglądu.
private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
{
tbStatus.Text = "MediaPlayer error: " + args.ErrorMessage;
}
Zatrzymaj podgląd kamery
Aby zatrzymać podgląd aparatu, wywołaj funkcję Pause w obiekcie MediaPlayer .
private void bStopPreview_Click(object sender, RoutedEventArgs e)
{
// Stop preview
m_mediaPlayer.Pause();
m_isPreviewing = false;
bStartPreview.IsEnabled = true;
bStopPreview.IsEnabled = false;
}
Resetowanie aplikacji
Aby ułatwić testowanie przykładowej aplikacji, dodaj metodę resetowania stanu aplikacji. Aplikacje aparatu fotograficznego powinny zawsze usuwać aparat i skojarzone zasoby, gdy aparat nie jest już potrzebny.
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