0

I was using a callback mechanism to grab the webcam frames in my media application. It worked, but was slow due to certain additional buffer functions that were performed within the callback itself.

Now I am trying the other way to get frames. That is, call a method and grab the frame (instead of callback). I used a sample in CodeProject which makes use of IVMRWindowlessControl9::GetCurrentImage.

I encountered the following issues.

  1. In a Microsoft webcam, the Preview didn't render (only black screen) on Windows 7. But the same camera rendered Preview on XP.

Here my doubt is, will the VMR specific functionalities be dependent on camera drivers on different platforms? Otherwise, how could this difference happen?

  1. Wherever the sample application worked, I observed that the biBitCount member of the resulting BITMAPINFOHEADER structure is 32.

Is this a value set by application or a driver setting for VMR operations? How is this configured? Finally, which is the best method to grab the webcam frames? A callback approach? Or a Direct approach?

Thanks in advance,

Jo Bell
  • 11
  • 5

1 Answers1

2

IVMRWindowlessControl9::GetCurrentImage is intended for occasional snapshots, not for regular image grabbing.

Quote from MSDN:

This method can be called at any time, no matter what state the filter is in, whether running, stopped or paused. However, frequent calls to this method will degrade video playback performance.

This methods reads back from video memory which is slow in first place. This methods does conversion (that is, slow again) to RGB color space because this format is most suitable for for non-streaming apps and gives less compatibility issues.

All in all, you can use it for periodic image grabbing, however this is not what you are supposed to do. To capture at streaming rate you need you use a filter in the pipeline, or Sample Grabber with callback.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Thank you Roman. Let me try and I will get back in case of issues. – Jo Bell May 17 '12 at 08:46
  • Hi, after running the graph, I tried the following. hr = g_pGrabber->GetCurrentBuffer(&cbBuffer, NULL); But here I get hr as -2147220953. I got the corresponding COM error string as IDispatch error #39. What is this error? – Jo Bell May 17 '12 at 09:51
  • `-2147220953` is `VFW_E_WRONG_STATE` http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/21091ecb-ad42-4533-b877-4467895641aa – Roman R. May 17 '12 at 09:57
  • Hi Roman, I did g_pGrabber->SetBufferSamples(TRUE); Then I called RenderStream twice - once for Capture (with Sample grabber and Null renderer) and then for preview. Then I run the graph. Then called GetCurrentBuffer twice, first to get the size and then with the actual buffer. But I dont see any change occuring to the actual buffer. Only the first frame seems to be captured. I havent set the One Shot either. By Default, one shot is disabled right? Please clarify. – Jo Bell May 17 '12 at 10:17
  • By using buffering of Sample Grabber you are being caught into the same trap as in case of `GetCurrentImage` in original question. You need to implement SampleCB function/callback and have your function called for every frame passing by. There is a multitude of code snippets and samples featuring this. If you still want to go with `GetCurrentBuffer`, MSDN has sample code for you: http://msdn.microsoft.com/en-us/library/windows/desktop/dd407288%28v=vs.85%29.aspx#example_code – Roman R. May 17 '12 at 10:28
  • Thanks Roman. By the way, if there is any code sample in MSDN for the SampleCB implementation of ISampleGrabber, it would be great. – Jo Bell May 17 '12 at 11:04
  • @RomanR. I have successfully completed the example you mentioned 3 comments above. I managed to extract the first frame (it is because of `pGrabber->SetOneShot(TRUE)` ). Is there an easy way to configure the code so we can take data from all frames? I tried to add `IVideoFrameStep` interface to my graph but the test `CanStep(0L, NULL)` returned False for me. – mbaros Aug 09 '17 at 14:33
  • 1
    @mbaros: SetOneShot, BufferCB, GetCurrentBuffer, SetBufferSamples are there in order to get you single frame. To get all frames you do a similar logic setting up the graph. You don't do SetOneShot and SetBufferSamples. You similarly Run and wait until completion. What you do additionally, is `ISampleGrabber::SetCallback` and provide your callback interface. It will be called for every frame processed, esp. via SampleCB call. Inside the call you can save or process the individual frames. This way you get ALL frames of the video file. – Roman R. Aug 09 '17 at 21:38
  • Thanks again @RomanR. I think you gave me enough material to complete the task. First thing I have to do is to get familiar what is a callback function and how it works. – mbaros Aug 09 '17 at 22:00