이 빠른 시작에서는 카메라 미리 보기를 표시하는 기본 WinUI 3 카메라 앱을 만드는 방법을 알아봅니다. WinUI 3 앱에서는 Microsoft.UI.Xaml.Controls 네임스페이스의 MediaPlayerElement 컨트롤을 사용하여 카메라 미리 보기를 렌더링하고 WinRT 클래스 MediaCapture를 사용하여 디바이스의 카메라 미리 보기 스트림에 액세스합니다. MediaCapture 는 사진 및 비디오 캡처 및 카메라의 디바이스 드라이버 구성과 같은 다양한 카메라 관련 작업을 수행하기 위한 API를 제공합니다. 다른 MediaCapture 기능에 대한 자세한 내용은 이 섹션의 다른 문서를 참조하세요.
이 연습의 코드는 github의 MediaCapture WinUI 3 샘플에서 변형되었습니다.
팁 (조언)
이 문서의 UWP 버전은 UWP 설명서에서 카메라 미리 보기 표시 를 참조하세요.
필수 조건
- 디바이스에 개발자 모드가 설정되어 있어야 합니다. 자세한 내용은 개발자를 위한 설정을 참조하세요.
- WinUI 애플리케이션 개발 워크로드가 있는 Visual Studio 2022 이상.
새 WinUI 3 앱 만들기
Visual Studio에서 새 프로젝트를 만듭니다. 새 프로젝트 만들기 대화 상자에서 언어 필터를 "C#"으로 설정하고 플랫폼 필터를 "Windows"로 설정한 다음, "빈 앱, 패키지됨(데스크톱의 WinUI 3)" 프로젝트 템플릿을 선택합니다.
UI 만들기
이 예제의 간단한 UI에는 카메라 미리 보기를 표시하기 위한 MediaPlayerElement 컨트롤, 장치의 카메라에서 선택할 수 있는 ComboBox , MediaCapture 클래스 초기화, 카메라 미리 보기 시작 및 중지 및 샘플 다시 설정 단추가 포함됩니다. 상태 메시지를 표시하기 위한 TextBlock 도 포함됩니다.
프로젝트의 MainWindow.xml 파일에서 기본 StackPanel 컨트롤을 다음 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>
MainWindow 클래스 정의 업데이트
이 문서의 나머지 코드는 프로젝트의 MainWindow.xaml.cs 파일에서 MainWindow 클래스 정의에 추가됩니다. 먼저 창의 수명 동안 유지되는 몇 가지 클래스 변수를 추가합니다. 이러한 변수는 다음과 같습니다.
- 사용 가능한 각 카메라에 대한 DeviceInformation 개체를 저장할 DeviceInformationCollection입니다. DeviceInformation 개체는 카메라의 고유 식별자 및 친숙한 이름과 같은 정보를 전달합니다.
- 선택한 카메라의 드라이버와의 상호 작용을 처리하고 카메라의 비디오 스트림을 검색할 수 있는 MediaCapture 개체입니다.
- 비디오 스트림과 같은 미디어 프레임의 원본을 나타내는 MediaFrameSource 개체입니다.
- 카메라 미리 보기가 실행되는 시기를 추적하는 불리언입니다. 미리 보기가 실행되는 동안에는 일부 카메라 설정을 변경할 수 없으므로 카메라 미리 보기의 상태를 추적하는 것이 좋습니다.
private DeviceInformationCollection m_deviceList;
private MediaCapture m_mediaCapture;
private MediaFrameSource m_frameSource;
private MediaPlayer m_mediaPlayer;
private bool m_isPreviewing;
사용 가능한 카메라 목록 채우기
다음으로 현재 디바이스에 있는 카메라를 감지하고 UI의 ComboBox 를 카메라 이름으로 채우는 도우미 메서드를 만들어 사용자가 미리 볼 카메라를 선택할 수 있도록 합니다. DeviceInformation.FindAllAsync 를 사용하면 다양한 종류의 디바이스를 쿼리할 수 있습니다. MediaDevice.GetVideoCaptureSelector를 사용하여 비디오 캡처 디바이스만 검색하도록 지정하는 식별자를 검색합니다.
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;
}
}
창이 로드될 때 ComboBox가 채워지도록 MainWindow 클래스 생성자에 이 도우미 메서드에 대한 호출을 추가합니다.
public MainWindow()
{
this.InitializeComponent();
PopulateCameraList();
}
MediaCapture 개체를 초기화합니다.
InitializeAsync를 호출하고 요청된 초기화 매개 변수가 포함된 MediaCaptureInitializationSettings 개체를 전달하여 MediaCapture 개체를 초기화합니다. 다양한 시나리오를 사용하도록 설정하는 많은 선택적 초기화 매개 변수가 있습니다. 전체 목록은 API 참조 페이지를 참조하세요. 이 간단한 예제에서는 다음을 비롯한 몇 가지 기본 설정을 지정합니다.
- VideoDeviceId 속성은 MediaCapture가 연결할 카메라의 고유 식별자를 지정합니다. 선택한 ComboBox 인덱스로 DeviceInformationCollection에서 디바이스 ID를 가져옵니다.
- SharingMode 속성은 앱이 비디오 스트림에서 보고 캡처할 수 있는 카메라에 대한 공유, 읽기 전용 액세스를 요청하는지 또는 카메라 구성을 변경할 수 있는 카메라의 단독 제어를 요청하는지 여부를 지정합니다. 여러 앱은 카메라에서 동시에 읽을 수 있지만 한 번에 하나의 앱만 단독 제어할 수 있습니다.
- StreamingCaptureMode 속성은 비디오, 오디오 또는 오디오 및 비디오를 캡처할지 여부를 지정합니다.
- MediaCaptureMemoryPreference를 사용하면 비디오 프레임에 CPU 메모리를 특별히 사용하도록 요청할 수 있습니다. 자동 값을 사용하면 GPU 메모리가 사용 가능한 경우 시스템에서 이를 사용할 수 있습니다.
MediaCapture 개체를 초기화하기 전에 AppCapability.CheckAccess 메서드를 호출하여 사용자가 Windows 설정에서 카메라에 대한 앱 액세스를 거부했는지 확인합니다.
비고
Windows를 사용하면 사용자가 개인 정보 및 보안 -> 카메라 아래의 Windows 설정에서 디바이스의 카메라에 대한 액세스 권한을 부여하거나 거부할 수 있습니다. 캡처 디바이스를 초기화할 때 앱은 카메라에 대한 액세스 권한이 있는지 확인하고 사용자가 액세스가 거부된 경우를 처리해야 합니다. 자세한 내용은 Windows 카메라 개인 정보 설정 처리를 참조하세요.
InitializeAsync 호출은 초기화가 실패할 경우 복구할 수 있도록 try 블록 내부에서 이루어집니다. 앱은 초기화 실패를 정상적으로 처리해야 합니다. 이 간단한 예제에서는 오류에 대한 오류 메시지만 표시합니다.
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;
}
}
카메라 미리 보기를 초기화
사용자가 미리 보기 시작 단추를 클릭하면 MediaCapture 개체가 초기화된 카메라 디바이스에서 비디오 스트림에 대한 MediaFrameSource를 만들려고 시도합니다. 사용 가능한 프레임 원본은 MediaCapture.FrameSources 속성에 의해 노출됩니다.
예를 들어 깊이 카메라와 달리 색 비디오 데이터인 프레임 원본을 찾기 위해 SourceKind of Color가 있는 프레임 원본을 찾습니다. 일부 카메라 드라이버는 레코드 스트림과 별개의 전용 미리 보기 스트림을 제공합니다. 미리 보기 비디오 스트림을 가져오기 위해 VideoPreview의 MediaStreamType이 있는 프레임 원본을 선택하려고 합니다. 미리 보기 스트림을 찾을 수 없는 경우 VideoRecord의 MediaStreamType을 선택하여 레코드 비디오 스트림을 가져올 수 있습니다. 이러한 프레임 원본 중 어느 것도 사용할 수 없는 경우 이 캡처 디바이스를 비디오 미리 보기에 사용할 수 없습니다.
프레임 원본을 선택하면 UI의 MediaPlayerElement 에서 렌더링할 새 MediaPlayer 개체를 만듭니다. MediaPlayer의 Source 속성을 선택한 MediaFrameSource에서 만든 새 MediaSource 개체로 설정합니다.
MediaPlayer 개체에서 Play를 호출하여 비디오 스트림 렌더링을 시작합니다.
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;
}
미리 보기를 렌더링하는 오류를 처리할 수 있도록 MediaFailed 이벤트에 대한 처리기를 구현합니다.
private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
{
tbStatus.Text = "MediaPlayer error: " + args.ErrorMessage;
}
카메라 미리 보기 중지
카메라 미리 보기를 중지하려면 MediaPlayer 개체에서 Pause를 호출합니다.
private void bStopPreview_Click(object sender, RoutedEventArgs e)
{
// Stop preview
m_mediaPlayer.Pause();
m_isPreviewing = false;
bStartPreview.IsEnabled = true;
bStopPreview.IsEnabled = false;
}
앱 다시 설정
샘플 앱을 더 쉽게 테스트하려면 앱의 상태를 다시 설정하는 메서드를 추가합니다. 카메라 앱은 카메라가 더 이상 필요하지 않을 때 항상 카메라 및 관련 리소스를 삭제해야 합니다.
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