如何在WPF或Windows Forms中使用UWP的MediaCapture API?
在Windows Forms/WPF中使用UWP MediaCapture API的实现方案
从Windows 10 1803(Build 17134)开始,UWP的MediaCapture API可通过WinRT互操作在Windows Forms或WPF应用中使用,前提是应用目标框架为.NET Framework 4.6.1+、.NET Core 3.0+或.NET 5+,且运行在符合版本的Windows系统上。
一、项目前置配置
- 右键项目 → 属性 → 应用程序,将目标框架设置为.NET Framework 4.6.1及以上(或.NET 5+更推荐)
- 添加WinRT引用:右键项目 → 添加 → 引用 → 浏览,找到路径
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.xxx.0\Windows.winmd(替换xxx为你安装的SDK版本),添加该文件 - 启用不安全代码:在项目属性的生成选项卡,勾选“允许不安全代码”(WinRT互操作部分场景需要)
二、Windows Forms实现步骤
1. 界面准备
在窗体上添加一个PictureBox控件,用于显示摄像头预览画面。
2. 核心代码实现
using Windows.Media.Capture; using Windows.Media.Devices; using Windows.Media.MediaProperties; using Windows.UI.Xaml.Media.Imaging; using System.Threading.Tasks; using System.Linq; private MediaCapture _mediaCapture; private bool _isCapturing = false; // 初始化MediaCapture并启动预览 private async Task InitializeMediaCaptureAsync() { _mediaCapture = new MediaCapture(); var videoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); if (!videoDevices.Any()) { MessageBox.Show("未检测到摄像头设备"); return; } var initSettings = new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Video, VideoDeviceId = videoDevices.First().Id }; await _mediaCapture.InitializeAsync(initSettings); // 设置预览分辨率 var previewProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga); await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync( MediaStreamType.VideoPreview, previewProfile.Video); // 启动预览并定时更新PictureBox var previewSink = new Windows.UI.Xaml.Controls.CaptureElement { Source = _mediaCapture }; await _mediaCapture.StartPreviewAsync(); var renderBitmap = new RenderTargetBitmap(); var updateTimer = new System.Windows.Forms.Timer { Interval = 33 }; // 约30帧/秒 updateTimer.Tick += async (s, e) => { if (!_isCapturing) return; await renderBitmap.RenderAsync(previewSink); var pixelBuffer = await renderBitmap.GetPixelsAsync(); // 转换为WinForms Bitmap并更新控件 pictureBox1.Image?.Dispose(); using (var stream = new System.IO.MemoryStream(pixelBuffer.ToArray())) { pictureBox1.Image = System.Drawing.Bitmap.FromStream(stream); } }; updateTimer.Start(); } // 窗体加载时初始化 private async void Form1_Load(object sender, EventArgs e) { // 请求摄像头权限 var accessStatus = await DeviceAccessInformation.CreateFromDeviceClass(DeviceClass.VideoCapture).RequestAccessAsync(); if (accessStatus != DeviceAccessStatus.Allowed) { MessageBox.Show("需要授予摄像头权限才能使用"); return; } try { await InitializeMediaCaptureAsync(); _isCapturing = true; } catch (Exception ex) { MessageBox.Show($"初始化失败: {ex.Message}"); } } // 窗体关闭时清理资源 private async void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (_isCapturing && _mediaCapture != null) { await _mediaCapture.StopPreviewAsync(); _mediaCapture.Dispose(); _isCapturing = false; } }
三、WPF实现步骤
1. 界面准备
在XAML窗口中添加一个Image控件,用于显示摄像头预览:
<Image x:Name="imgPreview" Stretch="Uniform" />
2. 核心代码实现
using Windows.Media.Capture; using Windows.Media.Devices; using Windows.Media.MediaProperties; using Windows.Graphics.Imaging; using System.Windows.Media.Imaging; using System.Linq; private MediaCapture _mediaCapture; private bool _isCapturing = false; // 初始化MediaCapture并启动预览 private async Task InitializeMediaCaptureAsync() { _mediaCapture = new MediaCapture(); var videoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); if (!videoDevices.Any()) { MessageBox.Show("未检测到摄像头设备"); return; } var initSettings = new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Video, VideoDeviceId = videoDevices.First().Id }; await _mediaCapture.InitializeAsync(initSettings); // 设置预览分辨率 var previewProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga); await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync( MediaStreamType.VideoPreview, previewProfile.Video); await _mediaCapture.StartPreviewAsync(); // 定时获取预览帧并更新Image控件 var updateTimer = new System.Timers.Timer(33); updateTimer.Elapsed += async (s, e) => { if (!_isCapturing) return; using (var previewFrame = await _mediaCapture.GetPreviewFrameAsync()) using (var softwareBitmap = previewFrame.SoftwareBitmap) { if (softwareBitmap == null) return; // 转换为WPF支持的像素格式 using (var convertedBitmap = SoftwareBitmap.Convert( softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied)) { var bitmapSource = new SoftwareBitmapSource(); await bitmapSource.SetBitmapAsync(convertedBitmap); // 切换到UI线程更新控件 Application.Current.Dispatcher.Invoke(() => { imgPreview.Source = bitmapSource; }); } } }; updateTimer.Start(); } // 窗口加载时初始化 private async void Window_Loaded(object sender, RoutedEventArgs e) { // 请求摄像头权限 var accessStatus = await DeviceAccessInformation.CreateFromDeviceClass(DeviceClass.VideoCapture).RequestAccessAsync(); if (accessStatus != DeviceAccessStatus.Allowed) { MessageBox.Show("需要授予摄像头权限才能使用"); return; } try { await InitializeMediaCaptureAsync(); _isCapturing = true; } catch (Exception ex) { MessageBox.Show($"初始化失败: {ex.Message}"); } } // 窗口关闭时清理资源 private async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (_isCapturing && _mediaCapture != null) { await _mediaCapture.StopPreviewAsync(); _mediaCapture.Dispose(); _isCapturing = false; } }
四、关键注意事项
- 系统版本限制:必须运行在Windows 10 1803(Build 17134)及以上版本,否则WinRT互操作不支持MediaCapture API
- 权限处理:必须获取摄像头访问权限,代码中已包含权限请求逻辑;若将应用打包为MSIX,需在
Package.appxmanifest中添加摄像头权限声明 - 内存管理:务必在应用关闭时释放MediaCapture资源,避免内存泄漏
- 异步操作:WinRT API多为异步实现,需正确使用
async/await,避免阻塞UI线程
内容的提问来源于stack exchange,提问作者Riz
相关产品推荐
相关产品推荐

