You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:20:55