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

 

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

你可能感兴趣的:(Dshow)