This article explains a method to perform previewing and grabbing simultaneously from a Webcam using DirectShow. Rather than using the conventional ISampleGrabber interface, this application used Directshow VMR filters & IPin interfaces.
There are many solutions for capturing and previewing, but only a few combine both. I tried to make an application that serves this purpose by using the ISampleGrabber and IVideoWindow interfaces. In this this article, I will discuss the "VMR filters & IPin interfaces" method, which worked on Win2000 and WinXP.
Using the Code
I had created a class named CVMR_Capture, and then inserted the VMR_Capture.h and VMR_Capture.cpp files into project.
Link strmiids.lib quartz.lib in VC++ Project Settings. Add a static control into your dialog resource. Add a member variable for that static control. Declare a member variable of CVMR_Capture.
Functions and Explanation
The public interfaces provided are:
int EnumDevices(HWND hList); HRESULT Init(int iDeviceID,HWND hWnd,int iWidth,int iHeight); DWORD GetFrame(BYTE ** pFrame); BOOL StopVMR(); BOOL Pause(); DWORD ImageCapture(LPCTSTR szFile); DWORD GrabFrame();
int EnumDevices(HWND hList); (Optional)
Enumerate the available devices connected to the computer. HWND is the HANDLE to a combo box that displays the connected Devices.
HRESULT Init(int iDeviceID,HWND hWnd,int iWidth,int iHeight);
Intitializing, "iDeviceID" is the selected device index (from the combo box) and "hWnd" is the handle of the display window. iWidth and iHeight are the expected resolution (eg 320/240). The display will adjust iteself to the size of the window.
DWORD GrabFrame(); DWORD GetFrame(BYTE ** pFrame);
Call this function to get the captured buffer. GrabFrame(); will grab the image, store it in a buffer, and return the value that is the size of the buffer. The user can get the buffer pointer by calling GetFrame(BYTE ** pFrame), whichs return the size of the buffer.
Note: DONT DELETE the "pFrame" BUFFER VALUE, which the class destructor will delete. Use the Pointer(pFrame) for processing or copying the memory to a user-allocated Buffer.
Pause capturing. Call this method again to restart capturing.
DWORD ImageCapture(LPCTSTR szFile);
Capture and write the raw image BYTES (RGB) to a file provided.
Special Functions and Explanation
bool BindFilter(int deviceId, IBaseFilter **pFilter); HRESULT InitializeWindowlessVMR(HWND hWnd); HRESULT InitVideoWindow(HWND hWnd,int width, int height); void StopCapture(); void CloseInterfaces(void); void DeleteMediaType(AM_MEDIA_TYPE *pmt); bool Convert24Image(BYTE *p32Img,BYTE *p24Img,DWORD dwSize32);
bool BindFilter(int deviceId, IBaseFilter **pFilter);
Bind the filter to the given device ID.
HRESULT InitializeWindowlessVMR(HWND hWnd);
VMR intialization to the HWND provided.
HRESULT InitVideoWindow(HWND hWnd,int width, int height);
Adjusts the display video size according to the size of display window.
Release & delete the interfaces/allocated memory.
void DeleteMediaType(AM_MEDIA_TYPE *pmt);
Delete media type object.
bool Convert24Image(BYTE *p32Img,BYTE *p24Img,DWORD dwSize32);
The captured image using VMR is a 32-bit RGB. This function will convert the 32-bit RGB to a 24-bit RGB.
Points of Interest
This class has been tested on Windows 2000 & Windows XP with DirectX9.0. Both VMR7 & VMR9 are supported. I haven't included the DirectShow Event Handling part in this sample. Please attach the required exception/error handling mechanism when you use it.
Please drop me an e-mail about any bugs or suggestions to enhance the class. Your suggestions and guidance will be most valuable.