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

如何在.NET 7 WinForms应用中使用MediaCapture.StartPreviewAsync()?

在.NET 7 WinForms中使用MediaCapture.StartPreviewAsync()的解决方案

你遇到的0xC00D36BB错误确实是因为WinForms没有UWP的CaptureElement控件——UWP中该控件会自动关联MediaCapture的预览输出目标,而WinForms缺少这个绑定机制,直接调用StartPreviewAsync()会因为没有预览目标而报错。

下面给出具体实现方案,核心思路是通过MediaFrameReader手动捕获预览帧,再将帧转换为WinForms可用的Bitmap显示在PictureBox控件中:

步骤1:准备项目与权限

  • 确保项目已引用Windows Runtime相关组件(.NET 7 WinForms默认已包含,若缺失可安装Microsoft.Windows.SDK.Contracts NuGet包)
  • 添加摄像头权限:
    • 若使用MSIX打包,在Package.appxmanifest中添加摄像头能力:
      <Capabilities>
        <DeviceCapability Name="webcam" />
      </Capabilities>
      
    • 若为非打包应用,在app.manifest中添加:
      <deviceCapability xmlns="http://schemas.microsoft.com/appx/2013/manifest">
        <Device Name="webcam" />
      </deviceCapability>
      

步骤2:实现核心代码

在WinForms窗体中添加一个PictureBox控件(命名为pictureBoxPreview),然后编写以下代码:

类级变量定义

using Windows.Media.Capture;
using Windows.Media.Frames;
using Windows.Media.MediaProperties;
using Windows.Graphics.Imaging;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

public partial class MainForm : Form
{
    private MediaCapture _mediaCapture;
    private MediaFrameReader _frameReader;
    private readonly object _lockObj = new object();
    private Bitmap _currentBitmap;

初始化MediaCapture与预览

private async Task InitializeMediaCaptureAsync()
{
    _mediaCapture = new MediaCapture();
    var initSettings = new MediaCaptureInitializationSettings
    {
        StreamingCaptureMode = StreamingCaptureMode.Video,
        PhotoCaptureSource = PhotoCaptureSource.VideoPreview
    };

    // 初始化MediaCapture
    await _mediaCapture.InitializeAsync(initSettings);

    // 获取视频预览的帧源
    var previewFrameSource = _mediaCapture.FrameSources
        .Where(f => f.Value.Info.MediaStreamType == MediaStreamType.VideoPreview)
        .First().Value;

    // 选择支持的BGRA8格式(方便转WinForms Bitmap)
    var preferredFormat = previewFrameSource.SupportedFormats
        .FirstOrDefault(f => f.Subtype == MediaEncodingSubtypes.Bgra8)
        ?? previewFrameSource.SupportedFormats.First();

    await previewFrameSource.SetFormatAsync(preferredFormat);

    // 创建帧读取器并绑定帧到达事件
    _frameReader = await _mediaCapture.CreateFrameReaderAsync(previewFrameSource);
    _frameReader.FrameArrived += OnPreviewFrameArrived;

    // 启动帧读取器和预览
    await _frameReader.StartAsync();
    await _mediaCapture.StartPreviewAsync();
}

处理预览帧并更新UI

private void OnPreviewFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
    // 获取最新帧
    using var frame = sender.TryAcquireLatestFrame();
    if (frame == null) return;

    using var softwareBitmap = frame.VideoMediaFrame.SoftwareBitmap;
    if (softwareBitmap == null) return;

    // 转换为BGRA8格式(忽略Alpha通道)
    using var convertedBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore);

    // 线程安全更新Bitmap
    lock (_lockObj)
    {
        _currentBitmap?.Dispose();
        _currentBitmap = ConvertSoftwareBitmapToBitmap(convertedBitmap);
    }

    // 跨线程更新PictureBox
    pictureBoxPreview.Invoke((Action)(() =>
    {
        pictureBoxPreview.Image?.Dispose();
        pictureBoxPreview.Image = _currentBitmap;
    }));
}

private Bitmap ConvertSoftwareBitmapToBitmap(SoftwareBitmap softwareBitmap)
{
    var bitmap = new Bitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight, PixelFormat.Format32bppArgb);
    var bitmapData = bitmap.LockBits(
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
        ImageLockMode.WriteOnly,
        bitmap.PixelFormat);

    // 将SoftwareBitmap数据复制到Bitmap内存
    softwareBitmap.CopyToBuffer(Windows.Storage.Streams.Buffer.CreateFromMemory(bitmapData.Scan0, bitmapData.Stride * bitmapData.Height));

    bitmap.UnlockBits(bitmapData);
    return bitmap;
}

资源清理

private async void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // 停止并清理帧读取器
    if (_frameReader != null)
    {
        await _frameReader.StopAsync();
        _frameReader.FrameArrived -= OnPreviewFrameArrived;
        _frameReader.Dispose();
    }

    // 停止预览并清理MediaCapture
    if (_mediaCapture != null)
    {
        await _mediaCapture.StopPreviewAsync();
        _mediaCapture.Dispose();
    }

    // 释放Bitmap资源
    lock (_lockObj)
    {
        _currentBitmap?.Dispose();
    }
}

步骤3:启动预览

在窗体加载事件中调用初始化方法:

private async void MainForm_Load(object sender, EventArgs e)
{
    try
    {
        await InitializeMediaCaptureAsync();
    }
    catch (Exception ex)
    {
        MessageBox.Show($"初始化失败:{ex.Message}");
    }
}

关键说明

  • 不再依赖CaptureElement,而是通过MediaFrameReader直接捕获预览帧,这样MediaCapture.StartPreviewAsync()就有了合法的输出目标,不会再报0xC00D36BB错误。
  • 必须保证UI更新在主线程执行,所以用Control.Invoke跨线程更新PictureBox。
  • 所有非托管资源(如MediaCapture、Bitmap)必须在窗体关闭时正确释放,避免内存泄漏。

内容的提问来源于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 12:25:14