我正在使用DirectShow的SampleGrabber从网络摄像头视频中捕获图像。代码用C#编写,并使用DirectShow接口的.NET包装器进行COM通信。下面的BufferCB首先将图像数据复制到本地数组变量,禁用SampleGrabber回调,处理接收的图像数据,并使用MessageBox显示结果。
public int BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
{
if (Monitor.TryEnter(lockSync))
{
try
{
if ((pBuffer != IntPtr.Zero))
{
this.ImageData = new byte[bufferLen];
Marshal.Copy(pBuffer, this.ImageData, 0, bufferLen);
// Disable callback
sampleGrabber.SetCallback(null, 1);
// Process image data
var result = this.Decode(new Bitmap(this.ImageData));
if (result != null)
{
MessageBox.Show(result.ToString());
}
// Enable callback
sampleGrabber.SetCallback(this,1);
}
}
finally
{
Monitor.Exit(this.parent.lockSync);
}
}
return 0;
}
现在,如果result = null
,因此MessageBox.Show永远不会运行,两个钳位调用sampleGrabber.SetCallback()将运行没有任何问题。一旦result != null
和MessageBox出现,调用sampleGrabber.SetCallback(this,1)将抛出InvalidCastException,如下所示:
Unable to cast COM object of type 'System.__ComObject' to interface type 'DirectShowInterfaces.ISampleGrabber'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{6B652FFF-11FE-4FCE-92AD-0266B5D7C78F}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
如果我在VS调试器中停止并添加((ISampleGrabber)sampleGrabber).SetCallback(sampleGrabber, 1)
的监视,我将得到带有&#34的消息的ArgumentException;无法在对象实例上找到该方法。"代替。
答案 0 :(得分:2)
BufferCB
和SampleCB
调用发生在工作线程上,工作线程通常属于MTA。另一方面,您的图初始化通常发生在STA线程上。 DirectShow API和过滤器挥发性地忽略COM线程规则,而.NET强制执行线程检查尝试在错误的线程上使用COM接口指针时引发异常。你正在解决这个问题。
您无需重置回调,然后将其重新设置。改为使用SampleCB
回调,它会作为阻止调用发生。在您完成处理之前,剩余的流媒体将处于暂停状态。