记录C#在Windows11 下使用原生的UWP的 MediaCapture 捕获摄像头画面

我们在做大屏端应用,都会遇到摄像头画面捕获和显示的技术。现在主流的方式大部分都是通过 UVC的方式去捕获摄像头的画面

比如:AForge.NET 组件库。甚至于我们组的大牛还实现了可以支持播放4K/8K的 摄像头播放器。

本文记录一下使用UWP原生的 MediaCapture 捕获摄像头,实现低延迟的摄像头画面播放。

 
如果应用本身是.NetFramwork 的,需要手动引用 Nuget包:Microsoft.Windows.SDK.Contracts
引用:Microsoft.Toolkit.Wpf.UI.XamlHost,让WPF 程序支持 使用 UWP 控件
 <PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.26100.1" />

1、首先先获取设备,并初始化

  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 已经打开,不重新初始化");
              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($"摄像头没权限:{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开启状态:{res.ToString()}");
          }
          else
          {
              Log.Info("mediaCapture.FrameSources为空,不监听流数据");
          }
          await StartCapturePreview();
          return true;
      }
      catch (Exception ex)
      {
          Log.Info($"初始化MediaCapture异常:{ex}");
          return false;
      }
      finally
      {
          _semaphoreSlim.Release();
      }
  }

2、播放摄像头画面

  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($"没有捕获设备");
                      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的控件去承载 摄像头画面

        <!--自定义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、展示画面如下图所示:

img_v3_02b4_9090b565-e4db-413c-a2c4-7eaa301a3a4g

 

之前冬哥有对比过各个组件的延迟差异,延迟相关的验证可以参考该博客链接:.NET 摄像头采集 - 唐宋元明清2188 - 博客园 
 
posted @ 2025-08-13 09:20  wuty007  阅读(140)  评论(0)    收藏  举报