首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在后台运行IVMRWindowlisControl9.GetCurrentImage()

在后台运行IVMRWindowlisControl9.GetCurrentImage()
EN

Stack Overflow用户
提问于 2016-10-05 20:00:35
回答 1查看 532关注 0票数 1

我有一个使用DirectShow.NET的摄像头控件,我创建了一个自定义控件来显示视频并从摄像头中获取图像。我在另一个WPF窗口中使用这个自定义控件。我在自定义控件中有一个函数public Bitmap CaptureImage(),可以抽象出一点DirectShow编程,只返回一个Bitmap。由于图像相对较大(1920x1080),IVMRWindowlessControl9IVMRWindowlessControl9函数需要很长时间才能处理(2-3秒)。我已经完成了我的代码,并且可以确认这个调用是唯一需要很长时间处理的调用。

正因为如此,我的主WPF窗口中的GUI线程挂起,导致它在几秒钟内没有响应,所以如果我想在捕获图像时显示一个进度旋转器,它将保持冻结状态。

以下是CaptureImage()的代码

代码语言:javascript
复制
public Bitmap CaptureImage()
{
  if (!IsCapturing)
    return null;

  this.mediaControl.Stop();
  IntPtr currentImage = IntPtr.Zero;
  Bitmap bmp = null;

  try
  {
    int hr = this.windowlessControl.GetCurrentImage(out currentImage);
    DsError.ThrowExceptionForHR(hr);

    if (currentImage != IntPtr.Zero)
    {
      BitmapInfoHeader bih = new BitmapInfoHeader();
      Marshal.PtrToStructure(currentImage, bih);

      ...
      // Irrelevant code removed 
      ...

      bmp = new Bitmap(bih.Width, bih.Height, stride, pixelFormat, new IntPtr(currentImage.ToInt64() + Marshal.SizeOf(bih)));
      bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show("Failed to capture image:" + ex.Message);
  }
  finally
  {
    Marshal.FreeCoTaskMem(currentImage);
  }

  return bmp;
}

为了解决这个问题,我尝试将其作为后台任务运行,如下所示:

代码语言:javascript
复制
public async void CaptureImageAsync()
{
  try
  {
    await Task.Run(() =>
    {
      CaptureImage();
    });
  }
  catch(Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

我尝试过多种方法来做到这一点,包括使用BackgroundWorker,但似乎每当我异步调用该调用时,它都会创建此错误:

无法将类型为“DirectShowLib.VideoMixingRenderer9”的COM对象转换为接口类型“DirectShowLib.IVMRWindowless cast 9”。此操作失败,因为对IID '{8F537D09-F85E-4414-B23B-502E54C79927}‘接口的COM组件的QueryInterface调用失败:不支持此类接口( HRESULT: 0x80004002 (E_NOINTERFACE)例外)。

此错误总是发生在以下情况:

代码语言:javascript
复制
int hr = this.windowlessControl.GetCurrentImage(out currentImage);

同步调用CaptureImage()将产生正常结果。图像被捕获,一切都按预期工作。但是,切换到使用任何类型的异步功能都会导致错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-05 20:39:55

你在这里有两个问题。首先,API最初的缓慢性是通过设计的行为。MSDN 提到这个为:

然而,频繁调用此方法会降低视频播放性能。

视频内存的读取速度可能很慢--这是2-3秒的处理问题,而不是图像本身的分辨率问题。坏消息是,即使是来自后台线程的轮询快照也很可能会影响可视流。

这个方法过去和现在都是用来拍摄零星的快照的,尤指。由用户交互发起的,而不是自动化的。需要更密集和自动化的应用程序,以及那些不影响可视化提要快照的应用程序,应该在将提要发送到视频内存之前拦截它(有选项可供选择,最流行但笨拙的是使用示例Grabber)。

其次,您可能会碰到.NET线程问题在这个问题中描述,这会触发上述异常。在本机代码开发中很容易使用相同的接口指针,方法是偷偷摸摸地违反COM线程规则,在公寓间传递接口指针。由于CLR在代码和COM对象之间添加了一个中间层以进行额外的安全检查,因此您不能再使用后台线程中的COM对象/接口操作,因为COM线程规则是强制执行的。

我认为您必须继续忍受与直接API调用相关的长期冻结,或者添加有助于绕过冻结的本机代码开发(例如,帮助过滤器在发送到视频内存之前捕获帧,同时为.NET调用方实现助手功能以支持后台线程调用)。想必您也可以在帮助器MTA线程池中完成所有与MTA相关的工作,这些线程解决了后台线程调用者的问题,但在这种情况下,您很可能需要将这段代码从UI线程(也就是STA )中移出--我不认为这是人们经常做的事情。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39882689

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档