協助程式目前顯示支援彩色視訊預覽或視訊錄製串流的相機畫面來源。
重要
請確定您的應用程式 已啟用網路攝影機功能 ,以存取裝置的相機。
<!-- 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 只在單一頁面上使用,請務必在離開頁面時清除 相機 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);
}
}
}