Introduction
This article explains how to use the ISampleGrabber
interface to grab a frame from a movie. We'll add the SampleGrabber filter to the graphbuilders
filter list and use it to extract the bitmap. It'll show the necessary steps
how to create the filter, create the graph, start it upp and grab the frame.
Setup the enviroment, we are using ATL
smartpointers and DirectShow
#include "AtlBase.h" // For atl smart pointers
#include "dShow.h" // DirectShow header
#include "Qedit.h" // SampleGrabber filter
The project has to be linked with Strmbase.lib
Since we're using COM
we have to call CoInitialize()
and
CoUninitialize()
in InitInstance, make sure the dialog destructor is called
before CoUninitialize
is called.
BOOL CFrameGrabberApp::InitInstance()
{
...
...
CoInitialize(NULL);
{
CFrameGrabberDemoDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
}
CoUninitialize();
...
...
}
Step 1: Create the GraphBuilder
CComPtr<IGraphBuilder> pGraphBuilder;
HRESULT hr = ::CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGraphBuilder);
Step 2: Create the Grabber filter and add it to the graph builder
CComPtr<IBaseFilter> pGrabberBaseFilter;
CComPtr<ISampleGrabber> pSampleGrabber;
AM_MEDIA_TYPE mt;
hr = ::CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (LPVOID *)&pGrabberBaseFilter);
if (FAILED(hr))
return hr;
pGrabberBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
if (pSampleGrabber == NULL)
return E_NOINTERFACE;
hr = pGraphBuilder->AddFilter(pGrabberBaseFilter,L"Grabber");
if (FAILED(hr))
return hr;
Step 3: Setup the media type we're interrested in and
render the file. The graph builder will now setup all the filters it needs to
render the movie including the sample grabber we added.
ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
mt.formattype = FORMAT_VideoInfo;
hr = pSampleGrabber->SetMediaType(&mt);
if (FAILED(hr))
return hr;
hr = pGraphBuilder->RenderFile(wFile,NULL);
if (FAILED(hr))
return hr;
Now when the graph is created we need to tell the sample
grabber to stop the graph after receiving one sample, we also tell it to copy
the sample data into it's internal buffer.
hr = pSampleGrabber->SetBufferSamples(TRUE);
if (FAILED(hr))
return hr;
hr = pSampleGrabber->SetOneShot(TRUE);
if (FAILED(hr))
return hr;
Step 4: Now we run the graph and collects the data from the sample grabber.
hr = pMediaControl->Run();
if (FAILED(hr))
return hr;
long evCode;
hr = pMediaEventEx->WaitForCompletion(INFINITE, &evCode);
if (FAILED(hr))
return hr;
AM_MEDIA_TYPE MediaType;
ZeroMemory(&MediaType,sizeof(MediaType));
hr = pSampleGrabber->GetConnectedMediaType(&MediaType);
if (FAILED(hr))
return hr;
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)MediaType.pbFormat;
if (pVideoHeader == NULL)
return E_FAIL;
BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BitmapInfo));
CopyMemory(&BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader),
sizeof(BITMAPINFOHEADER));
void *buffer = NULL;
HBITMAP hBitmap = ::CreateDIBSection(0, &BitmapInfo, DIB_RGB_COLORS, &buffer,
NULL, 0);
GdiFlush();
long size = 0;
hr = pSampleGrabber->GetCurrentBuffer(&size,(long *)buffer);
if (FAILED(hr))
return hr;
Now we have the bitmap handle, the demo program takes the sample one second in the movie and displays it to the user using an picture box.