.NET 7 WinForms中用MediaCapture在PictureBox实现摄像头实时预览
WinForms PictureBox 实现 MediaCapture 实时预览(无需 CaptureElement)
核心思路
由于CaptureElement仅支持UWP环境,我们可以通过订阅MediaCapture.PreviewFrameAvailable事件实时获取摄像头预览帧,将帧转换为WinForms兼容的Bitmap后,线程安全地更新PictureBox控件,从而实现实时预览效果。
实现步骤与代码示例
1. 基础配置与初始化
确保项目已引入net7.0-windows10.0.17763.0,并在Package.appxmanifest中添加摄像头权限:
<Capabilities> <DeviceCapability Name="webcam" /> </Capabilities>
2. 完整Form代码实现
using System; using System.Drawing; using System.Threading.Tasks; using System.Windows.Forms; using Windows.Graphics.Imaging; using Windows.Media.Capture; using Windows.Media.MediaProperties; namespace WinFormsCameraPreview { public partial class CameraPreviewForm : Form { private MediaCapture _mediaCapture; private bool _isPreviewing; public CameraPreviewForm() { InitializeComponent(); FormClosing += CameraPreviewForm_FormClosing; } private async void btnTogglePreview_Click(object sender, EventArgs e) { if (_isPreviewing) { await StopPreview(); btnTogglePreview.Text = "开始预览"; } else { await StartPreview(); btnTogglePreview.Text = "停止预览"; } } private async Task StartPreview() { try { // 初始化MediaCapture,仅捕获视频预览 _mediaCapture = new MediaCapture(); await _mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Video, PhotoCaptureSource = PhotoCaptureSource.VideoPreview }); // 设置预览格式为BGRA8,便于后续转换为Bitmap var previewProps = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga); previewProps.Video.Subtype = MediaEncodingSubtypes.Bgra8; await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync( MediaStreamType.VideoPreview, previewProps.Video); // 订阅预览帧可用事件 _mediaCapture.PreviewFrameAvailable += OnPreviewFrameAvailable; // 启动预览 await _mediaCapture.StartPreviewAsync(); _isPreviewing = true; } catch (Exception ex) { MessageBox.Show($"预览启动失败:{ex.Message}"); await CleanupResources(); } } private void OnPreviewFrameAvailable(MediaCapture sender, object args) { try { // 获取当前预览帧的SoftwareBitmap using var frame = sender.GetPreviewFrameAsync().AsTask().Result; using var softwareBitmap = frame.SoftwareBitmap; if (softwareBitmap == null) return; // 将SoftwareBitmap转换为WinForms Bitmap Bitmap bitmap; using var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream(); var encoder = BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream).AsTask().Result; encoder.SetSoftwareBitmap(softwareBitmap); encoder.FlushAsync().AsTask().Wait(); stream.Seek(0); bitmap = new Bitmap(stream.AsStream()); // 线程安全更新PictureBox(必须在UI线程操作控件) pictureBoxPreview.Invoke(new Action(() => { // 释放旧Bitmap避免内存泄漏 pictureBoxPreview.Image?.Dispose(); pictureBoxPreview.Image = bitmap; })); } catch { // 帧捕获失败时忽略,不影响整体预览 } } private async Task StopPreview() { if (_isPreviewing) { await _mediaCapture.StopPreviewAsync(); _mediaCapture.PreviewFrameAvailable -= OnPreviewFrameAvailable; _isPreviewing = false; } } private async Task CleanupResources() { await StopPreview(); _mediaCapture?.Dispose(); _mediaCapture = null; // 清理PictureBox资源 pictureBoxPreview.Invoke(new Action(() => { pictureBoxPreview.Image?.Dispose(); pictureBoxPreview.Image = null; })); } private async void CameraPreviewForm_FormClosing(object sender, FormClosingEventArgs e) { await CleanupResources(); } } }
关键优化与注意事项
- 性能调优:若预览帧率不足,可降低预览分辨率(如改用
VideoEncodingQuality.Qvga),或匹配PictureBox的实际尺寸,减少帧转换的计算开销。 - 内存管理:每次更新PictureBox时必须释放旧的
Bitmap对象,否则会引发内存泄漏。 - 线程安全:WinForms控件仅允许在UI线程操作,因此必须使用
Invoke方法更新PictureBox的Image属性。 - 权限验证:首次运行时系统会请求摄像头权限,需确保用户授权。
内容的提问来源于stack exchange,提问作者Gabriel Frigo
相关产品推荐
相关产品推荐

