도우미는 현재 컬러 비디오 미리 보기 또는 비디오 레코드 스트림을 지원하는 카메라 프레임 원본을 표시합니다.
Important
앱이 디바이스의 카메라에 액세스할 수 있도록 웹캠 기능을 사용하도록 설정되어 있는지 확인합니다.
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<UserControl x:Class="HelpersExperiment.Samples.CameraHelperSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HelpersExperiment.Samples"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
<StackPanel HorizontalAlignment="Center"
Orientation="Vertical"
Spacing="12">
<ComboBox x:Name="FrameSourceGroupCombo"
MinWidth="200"
HorizontalAlignment="Center"
Header="Frame source group">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<muxc:InfoBar x:Name="ErrorBar"
Title="Error"
IsOpen="False"
Severity="Error" />
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource ControlCornerRadius}">
<Image x:Name="CurrentFrameImage"
Height="300"
MinWidth="360" />
</Border>
<Button x:Name="CaptureButton"
HorizontalAlignment="Center"
Click="CaptureButton_Click"
Content="Capture video frame"
Style="{StaticResource AccentButtonStyle}" />
</StackPanel>
</UserControl>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using CommunityToolkit.WinUI.Helpers;
using Windows.Graphics.Imaging;
using Windows.Media;
using Windows.Media.Capture.Frames;
using Windows.ApplicationModel;
#if WINAPPSDK
using Microsoft.UI.Xaml.Media.Imaging;
#else
using Windows.UI.Xaml.Media.Imaging;
#endif
namespace HelpersExperiment.Samples;
[ToolkitSample(id: nameof(CameraHelperSample), "CameraHelper", description: $"A sample for showing how to use {nameof(CameraHelper)}.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1001:Types that own disposable fields should be disposable", Justification = "Controls dispose resources on unload")]
public sealed partial class CameraHelperSample : UserControl
{
private CameraHelper _cameraHelper;
private VideoFrame _currentVideoFrame;
private SoftwareBitmapSource _softwareBitmapSource;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public CameraHelperSample()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
this.InitializeComponent();
Loaded += CameraHelperSample_Loaded;
Unloaded += CameraHelperSample_Unloaded;
}
private async void CameraHelperSample_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= CameraHelperSample_Loaded;
Setup();
await InitializeAsync();
}
private async void CameraHelperSample_Unloaded(object sender, RoutedEventArgs e)
{
Unloaded -= CameraHelperSample_Unloaded;
#if !WINAPPSDK
Application.Current.Suspending -= Application_Suspending;
Application.Current.Resuming -= Application_Resuming;
#endif
await CleanUpAsync();
}
private void Setup()
{
_softwareBitmapSource = new SoftwareBitmapSource();
CurrentFrameImage.Source = _softwareBitmapSource;
#if !WINAPPSDK
// Application.Current.Suspending += Application_Suspending;
// Application.Current.Resuming += Application_Resuming;
#endif
}
private async void Application_Suspending(object? sender, SuspendingEventArgs e)
{
if (IsLoaded)
{
var deferral = e.SuspendingOperation.GetDeferral();
await CleanUpAsync();
deferral.Complete();
}
}
private async void Application_Resuming(object? sender, object e)
{
await InitializeAsync();
}
private void CameraHelper_FrameArrived(object sender, FrameEventArgs e)
{
_currentVideoFrame = e.VideoFrame;
}
private async Task InitializeAsync()
{
var frameSourceGroups = await CameraHelper.GetFrameSourceGroupsAsync();
if (_cameraHelper == null)
{
_cameraHelper = new CameraHelper();
}
var result = await _cameraHelper.InitializeAndStartCaptureAsync();
if (result == CameraHelperResult.Success)
{
// Subscribe to the video frame as they arrive
_cameraHelper.FrameArrived += CameraHelper_FrameArrived!;
FrameSourceGroupCombo.ItemsSource = frameSourceGroups;
FrameSourceGroupCombo.SelectionChanged += FrameSourceGroupCombo_SelectionChanged;
FrameSourceGroupCombo.SelectedIndex = 0;
}
SetUIControls(result);
}
private async void FrameSourceGroupCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (FrameSourceGroupCombo.SelectedItem is MediaFrameSourceGroup selectedGroup && _cameraHelper != null)
{
_cameraHelper.FrameSourceGroup = selectedGroup;
var result = await _cameraHelper.InitializeAndStartCaptureAsync();
SetUIControls(result);
}
}
private void SetUIControls(CameraHelperResult result)
{
var success = result == CameraHelperResult.Success;
if (!success)
{
_currentVideoFrame = null!;
}
ErrorBar.Title = result.ToString();
ErrorBar.IsOpen = !success;
CaptureButton.IsEnabled = success;
CurrentFrameImage.Opacity = success ? 1 : 0.5;
}
private async void CaptureButton_Click(object sender, RoutedEventArgs e)
{
var softwareBitmap = _currentVideoFrame?.SoftwareBitmap;
if (softwareBitmap != null)
{
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}
if (_softwareBitmapSource != null)
{
await _softwareBitmapSource.SetBitmapAsync(softwareBitmap);
}
}
}
private async Task CleanUpAsync()
{
if (FrameSourceGroupCombo != null)
{
FrameSourceGroupCombo.SelectionChanged -= FrameSourceGroupCombo_SelectionChanged;
}
if (_cameraHelper != null)
{
_cameraHelper.FrameArrived -= CameraHelper_FrameArrived!;
await _cameraHelper.CleanUpAsync();
_cameraHelper = null!;
}
_softwareBitmapSource?.Dispose();
}
}
구문
// Creates a Camera Helper and gets video frames from an available frame source.
using CommunityToolkit.WinUI.Helpers.CameraHelper;
CameraHelper _cameraHelper = new CameraHelper();
var result = await _cameraHelper.InitializeAndStartCaptureAsync();
// Camera Initialization and Capture failed for some reason
if(result != CameraHelperResult.Success)
{
// get error information
var errorMessage = result.ToString();
}
else
{
// Subscribe to get frames as they arrive
_cameraHelper.FrameArrived += CameraHelper_FrameArrived;
}
private void CameraHelper_FrameArrived(object sender, FrameEventArgs e)
{
// Gets the current video frame
VideoFrame currentVideoFrame = e.VideoFrame;
// Gets the software bitmap image
SoftwareBitmap softwareBitmap = currentVideoFrame.SoftwareBitmap;
}
리소스 정리
개발자는 적절한 경우 카메라헬퍼 리소스가 클린 있는지 확인해야 합니다. 예를 들어 카메라Helper가 한 페이지에서만 사용되는 경우 페이지에서 이동할 때 카메라Helper를 클린 합니다.
마찬가지로 앱 일시 중단 및 다시 시작에 대해 처리해야 합니다. 카메라 일시 중단 및 다시 시작 시 다시 초기화할 때 클린.
모든 내부 리소스를 클린 호출 CameraHelper.CleanupAsync()
합니다. 전체 예제는 샘플 앱의 카메라Helper 샘플 페이지를 참조하세요.
예제
카메라 도우미를 사용하여 특정 미디어 프레임 원본 그룹에서 비디오 프레임을 가져오는 방법을 보여 줍니다.
using CommunityToolkit.WinUI.Helpers.CameraHelper;
var availableFrameSourceGroups = await CameraHelper.GetFrameSourceGroupsAsync();
if(availableFrameSourceGroups != null)
{
CameraHelper cameraHelper = new CameraHelper() { FrameSourceGroup = availableFrameSourceGroups.FirstOrDefault() };
var result = await cameraHelper.InitializeAndStartCaptureAsync();
// Camera Initialization succeeded
if(result == CameraHelperResult.Success)
{
// Subscribe to get frames as they arrive
cameraHelper.FrameArrived += CameraHelper_FrameArrived;
// Optionally set a different frame source format
var newFormat = cameraHelper.FrameFormatsAvailable.Find((format) => format.VideoFormat.Width == 640);
if (newFormat != null)
{
await cameraHelper.PreviewFrameSource.SetFormatAsync(newFormat);
}
}
}
GitHub에서 Microsoft와 공동 작업
이 콘텐츠의 원본은 GitHub에서 찾을 수 있으며, 여기서 문제와 끌어오기 요청을 만들고 검토할 수도 있습니다. 자세한 내용은 참여자 가이드를 참조하세요.
Windows Community Toolkit