怎么样在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(&currentPos);

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::EnterBitmapGrabModeIMediaDet::get_CurrentStreamIMediaDet::GetBitmapBitsIMediaDet::WriteBitmapBits源代码

5运用DDraw技术,用surface的拷贝就行了。