怎么样在Dshow播放过程中实现抓图?
怎么样在Dshow播放过程中实现抓图?
Dshow播放过程中实现抓图的方法
1:加入Simple Grabber Filter,
a): 从ISampleGrabberCB中派生出自己的类,然后实现其虚函数,详情请参见SDK中的示例程序(DXSDK ROOT/Samples/C++/DirectShow/Editing/GrabBitmaps)
b): 而在加入Filter的时候,因为这样可能减慢效率,所以可以采用下面的方法:
该方法需传递的是时间,而且不是在播放的时候加入Filter然后截图,而是另外打开原文件进行。
申明以下接口:
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaSeeking *pSeeking = NULL;
IMediaEventEx *pEvent = NULL;
IBaseFilter *pNullFilter = NULL;
初始化这些接口:
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&pGraph));
JIF(CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void **)&pNullFilter));
JIF(pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl));
JIF(pGraph->QueryInterface(IID_IMediaSeeking, (void **)&pSeeking));
JIF(pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent));
创建Sample Grabber
// Create the Sample Grabber.
IBaseFilter *pGrabberF = NULL;
JIF(CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pGrabberF));
JIF(pGraph->AddFilter(pGrabberF, L"Sample Grabber"));
JIF(pGraph->AddFilter(pNullFilter, L"Null Render Filter"));
ISampleGrabber *pGrabber;
JIF(pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber));
设置Grabber的媒体格式:
调用SetMediaType,该函数接受一个AM_MEDIA_TYPE的结构,主要是设置该结构中的majortype,和subtype域。
添加Source Filter:
IBaseFilter *pSrc;
JIF(pGraph->AddSourceFilter(T2W(m_szFile), L"Source", &pSrc));
连接Grabber 和 NullRender两个Filter
IPin *pOutPin;
hr = GetPin(pGrabberF, PINDIR_OUTPUT, &pOutPin);
IPin *pInPin;
hr = GetPin(pNullFilter, PINDIR_INPUT, &pInPin);
pGraph->Connect(pOutPin, pInPin);
连接后的grf图如下:
一个假想图, 源代码
取得当前所连接媒体的类型
AM_MEDIA_TYPE mt;
hr = pGrabber->GetConnectedMediaType(&mt);
// Examine the format block.
VIDEOINFOHEADER *pVih;
if ((mt.formattype == FORMAT_VideoInfo) &&
(mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
(mt.pbFormat != NULL) )
{
pVih = (VIDEOINFOHEADER*)mt.pbFormat;
}
else
{
// Wrong format. Free the format block and return an error.
FreeMediaType(mt);
return VFW_E_INVALIDMEDIATYPE;
}
// Do buffer the samples as they pass through
//
hr = pGrabber->SetBufferSamples(TRUE);
// Only grab one at a time, stop stream after
// grabbing one sample
//
hr = pGrabber->SetOneShot( TRUE );
Seeking文件,使其到达要截图的时间帧
pSeeking->SetPositions(pCurrentPos, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning );
pControl->Run();
long EvCode = 0;
hr = pEvent->WaitForCompletion( INFINITE, &EvCode );
取得当前的buffer数据
// Find the required buffer size.
long cbBuffer = 0;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
LONGLONG currentPos;
pSeeking->GetCurrentPosition(¤tPos);
BYTE *pBuffer = new BYTE[cbBuffer];
if (!pBuffer)
{
// Out of memory. Return an error code.
Msg("Out of Memory");
}
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
释放资源
pControl->Stop();
SAFE_RELEASE(pControl);
SAFE_RELEASE(pSeeking);
SAFE_RELEASE(pEvent);
SAFE_RELEASE(pSrc);
SAFE_RELEASE(pNullFilter);
SAFE_RELEASE(pGrabber);
SAFE_RELEASE(pGrabberF);
SAFE_RELEASE(pGraph);
写入文件
// Create a file to hold the bitmap
HANDLE hf = CreateFile(szFilename, GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, NULL, NULL );
if( hf == INVALID_HANDLE_VALUE )
{
// Failed to create file
return 0;
}
// Write out the file header
//
BITMAPFILEHEADER bfh;
memset( &bfh, 0, sizeof( bfh ) );
bfh.bfType = 'MB';
bfh.bfSize = sizeof( bfh ) + cbBuffer + sizeof( BITMAPINFOHEADER );
bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER );
DWORD Written = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &Written, NULL );
// Write the bitmap format
//
BITMAPINFOHEADER bih;
memset( &bih, 0, sizeof( bih ) );
bih.biSize = sizeof( bih );
bih.biWidth = pVih->bmiHeader.biWidth;
bih.biHeight = pVih->bmiHeader.biHeight;
bih.biPlanes = pVih->bmiHeader.biPlanes;
bih.biBitCount = pVih->bmiHeader.biBitCount;
Written = 0;
WriteFile( hf, &bih, sizeof( bih ), &Written, NULL );
// Write the bitmap bits
//
Written = 0;
WriteFile( hf, pBuffer, cbBuffer, &Written, NULL );
FreeMediaType(mt);
CloseHandle(hf);
其实我们可以不用NullRender,而是用IVideoWindow接口来实现。
如果是那样的话,首先申明IVideoWindow *pVideo = NULL;
将pVideo加入到Filter Graph中
JIF(pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideo));
hr = pGraph->Render(pOutPin);
if (pVideo)
{
hr = pVideo->put_AutoShow(OAFALSE);
}
取得数据和写文件的方法都是一样的。
其建立的grf图为:pVideo所建立的grf图,其源代码
3:通过IBasicVideo接口,调用IBasicVideo:: GetCurrentImage, 源文件
4:通过IMediaDet接口,调用IMediaDet::EnterBitmapGrabMode,IMediaDet::get_CurrentStream,IMediaDet::GetBitmapBits或IMediaDet::WriteBitmapBits,源代码
5:运用DDraw技术,用surface的拷贝就行了。