在没有显示的情况下拍摄网络摄像头快照的任务

Task for taking webcam snapshots without display

我想使用 DirectShow 在 windows 上拍摄网络摄像头快照。这些快照将保存到磁盘而不显示这些图像。我想启动每秒拍摄一次快照的快照进程,直到我停止它,而主进程继续。

所以我选择 Yet Another Web Camera Control DirectShow 与 C# 一起使用,并且演示工作正常。
但是当我在自己的任务中使用包装器时遇到问题,出现典型的线程错误 The calling thread cannot access this object because a different thread owns it.

调用代码如下所示:

Task.Run(() =>
{
    using (var cam1 = new SnapshotCam(camList.First(), "person", webCameraControl))
    {
        // Act
        Bitmap image = null;
        if (!cam1._wcc.IsCapturing)
        {
            cam1._wcc.StartCapture(cam1._cameraId);
            Task.Delay(500).Wait();
        }
        image = cam1._wcc.GetCurrentImage();
        // Assert
        Assert.NotNull(image);
    }
}).Wait();

我最难处理的对象是存储在cam1._wcc中的webCameraControl:这个对象继承自System.Windows.Controls.UserControl,可以附加到UI。但就我而言,我没有任何 UI,必须以 "headless" 样式拍摄快照。

因此,当我想使用 _wcc-对象时,麻烦就开始了。我已经尝试为相应的线程调用 _wcc.Dispatcher 但没有成功。

如何独立于其他代码独立于 task/thread 调用上面的代码?

如果您没有 UI,那么您可能不需要将代码包装在 Task.Run 中,除非您尝试在 运行 中同时执行某些操作] - 因为你没有使用 await 它/看起来/不像是这种情况。

如果您想将其保留在 Task.Run 中,那么您可以在表单上使用 Invoke 方法,这将允许您在正确的线程中访问相机控件,但是我看不出它如何异步解决 运行 的问题。

如果您没有将控件用作实际的 UI 元素,我不明白为什么您不能在单独的线程上创建它并在该线程上使用它,尽管它不会听起来这就是它的用途。

您立即遇到的问题与线程相关,但最终它是用于网络摄像头捕获的库的不幸选择。您不需要显示相机帧,但该库正在通过将视频流渲染到 Direct3D 设备(即使它是 "invisible" 也是一种演示)并根据请求复制最后一个已知帧来实现拍摄静止图像。

也许您更喜欢 DirectShow.NET 包中的 DxSnap 示例应用程序。虽然也不理想:

  • 它使用 Sample Grabber 提取帧数据而不需要显示过滤器
  • 展示了如何在线程间准确传递数据,see here
  • 你避免了多层外部控制库的过度复杂化

另请参阅:

  • Efficiently grabbing pixels from video
  • Calling a function in another thread C#