2

I am using DirectShow's SampleGrabber to capture an image from a webcam video. Codes are writing in C# and use .NET wrappers of DirectShow's interfaces to do COM communication. The following BufferCB, first, copies image data to a local array variable, disables SampleGrabber callback, processes a received image data, and uses MessageBox to shows a result.

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;
}

Now, if the result = null, hence the MessageBox.Show never runs, both clamping calls sampleGrabber.SetCallback() will run without any issue. Once the result != null, and the MessageBox shows up, the call sampleGrabber.SetCallback(this,1) will throw the InvalidCastException as below:

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)).

If I stop in a VS debugger and add a watch of ((ISampleGrabber)sampleGrabber).SetCallback(sampleGrabber, 1), I will get the ArgumentException with the message of "Cannot find the method on the object instance." instead.

May someone experience the same issue can give me some advise. Thank you.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
Jupiterv
  • 21
  • 1

1 Answers1

2

BufferCB and SampleCB calls take place on worker threads, which typically belong to MTA. Your graph initialization on the other hand typically takes place on STA thread. DirectShow API and filters volantarily ignore COM threading rules while .NET enforces thread checks an raises exception on attempts to use COM interface pointer on a wrong thread. You are hitting exactly this issue.

You don't need to reset callback and then set it back. Use SampleCB callback instead and it happens as a blocking call. Before you complete the processing the rest of the streaming is on hold.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • But it does not explain why the calls only fail after the call to MessageBox.Show returns. Without showing the message box, they work just fine. – Jupiterv Aug 20 '14 at 01:49
  • Use of `sampleGrabber` interface pointer on this thread is a violation (the pointer belongs to different COM apartment). It might or might not fail immediately, or it might depend on external factors. – Roman R. Aug 20 '14 at 05:18