記錄C#在Windows11 下使用原生的UWP的 MediaCapture 捕獲攝像頭畫(huà)面
我們?cè)谧龃笃炼藨?yīng)用,都會(huì)遇到攝像頭畫(huà)面捕獲和顯示的技術(shù)。現(xiàn)在主流的方式大部分都是通過(guò) UVC的方式去捕獲攝像頭的畫(huà)面
比如:AForge.NET 組件庫(kù)。甚至于我們組的大牛還實(shí)現(xiàn)了可以支持播放4K/8K的 攝像頭播放器。
本文記錄一下使用UWP原生的 MediaCapture 捕獲攝像頭,實(shí)現(xiàn)低延遲的攝像頭畫(huà)面播放。
MediaCaptuer是UWP應(yīng)用的API: Basic photo, video, and audio capture with MediaCapture - Windows apps | Microsoft Learn
如果應(yīng)用本身是.NetFramwork 的,需要手動(dòng)引用 Nuget包:Microsoft.Windows.SDK.Contracts
引用:Microsoft.Toolkit.Wpf.UI.XamlHost,讓W(xué)PF 程序支持 使用 UWP 控件
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" /> <PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.26100.1" />
1、首先先獲取設(shè)備,并初始化
public async Task<IList<DeviceInformation>> GetCaptureInfos() { var videos =await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); if (videos.Count >0) { var displayDevices = videos.Where(x => x.Name.Contains(HdmiCaptureName)); return displayDevices.ToList(); } return new List<DeviceInformation>(); } private async Task<bool> InitCaptureInternal(string deviceId) { try { await _semaphoreSlim.WaitAsync(); if (_isCameraRunning) { Log.Info($"Hdmi 已經(jīng)打開(kāi),不重新初始化"); return true; } _isCameraRunning = true; mediaCapture = new MediaCapture(); var settings = new MediaCaptureInitializationSettings() { VideoDeviceId = deviceId, StreamingCaptureMode = StreamingCaptureMode.Video, }; mediaCapture.Failed += MediaCapture_Failed; try { await mediaCapture.InitializeAsync(settings); } catch (UnauthorizedAccessException ex) { Log.Info($"攝像頭沒(méi)權(quán)限:{ex}"); } var frameSource = mediaCapture.FrameSources?.First().Value; if (frameSource != null) { _isFirstFrame = true; _mediaFrameReader = await mediaCapture.CreateFrameReaderAsync(frameSource); _mediaFrameReader.FrameArrived += Reader_FrameArrived; var res = await _mediaFrameReader.StartAsync(); Log.Info($"_mediaFrameReader開(kāi)啟狀態(tài):{res.ToString()}"); } else { Log.Info("mediaCapture.FrameSources為空,不監(jiān)聽(tīng)流數(shù)據(jù)"); } await StartCapturePreview(); return true; } catch (Exception ex) { Log.Info($"初始化MediaCapture異常:{ex}"); return false; } finally { _semaphoreSlim.Release(); } }
2、播放攝像頭畫(huà)面
public async Task<int> StartCameraFrameAsync() { var res = -1; try { var result = await Application.Current.Dispatcher.Invoke(async () => { if (string.IsNullOrWhiteSpace(_deviceId)) { var hdmiDevices = await _devFilterManager.GetCaptureInfos(); var hdmiDevice = hdmiDevices.FirstOrDefault(); if (hdmiDevice == null) { H3CLog.Info($"沒(méi)有捕獲設(shè)備"); return -1; } _deviceId = hdmiDevice.Id; } var result = await InitCaptureInternal(_deviceId); if (!result) { result = await ReConnectAsync(_deviceId); } return result ? 0 : -1; }).TimeOutAsync(6000); if (result.Success) { res = result.Data; } } catch (Exception e) { Log.Error($"StartCameraFrameAsync異常", e); } return res; }
3、在xmal 端,需要定義UWP的控件去承載 攝像頭畫(huà)面
<!--自定義UWP的窗口控件-->
<xamlHost:WindowsXamlHost x:Name="VideoViewHost" Visibility="{Binding ImageVisibility}"/>
private void DrawUwpElement() { Windows.UI.Xaml.Controls.Grid mainGrid = new Windows.UI.Xaml.Controls.Grid(); var imageUri = UwpResourceHelper.NarrowActivateUri; MaximizedImg = new Windows.UI.Xaml.Controls.Image { Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(imageUri), HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Left, VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Bottom, Stretch = Stretch.Fill, Width = 40, Height = 40, Margin = new Windows.UI.Xaml.Thickness(24, 0, 0, 24), Tag = imageUri }; Windows.UI.Xaml.Controls.CaptureElement captureElement = new CaptureElement() { Stretch = Stretch.Fill }; mainGrid.Children.Add(captureElement); mainGrid.Children.Add(MaximizedImg); HdmiProvider.CaptureElement = captureElement; VideoViewHost.Child = mainGrid; _videoViewOperation = new VideoViewOperation(this, captureElement, MaximizedImg, VideoViewHost); _videoViewOperation.VideoViewStatusChanged += _videoViewOperation_VideoViewStatusChanged; }
4、展示畫(huà)面如下圖所示:

之前冬哥有對(duì)比過(guò)各個(gè)組件的延遲差異,延遲相關(guān)的驗(yàn)證可以參考該博客鏈接:.NET 攝像頭采集 - 唐宋元明清2188 - 博客園

浙公網(wǎng)安備 33010602011771號(hào)