<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      DShow中完成抓圖的幾種方法

      [摘要]1.加入Sample Grabber Filter當我們加入Sample Grabber Filter的時候,我們可以直接調用其接口(interface)ISampleGrabber。該接口可以獲取經過該Filter的單獨的Media Samples。詳情請參見DXSDK。 1.1 派生出自己的S...
      1.加入Sample Grabber Filter
      當我們加入Sample Grabber Filter的時候,我們可以直接調用其接口(interface)ISampleGrabber。該接口可以獲取經過該Filter的單獨的Media Samples。詳情請參見DXSDK。

      1.1 派生出自己的Sample Grabber
      從ISampleGrabberCB中派生出自己的類,然后實現其虛函數,詳情請參見SDK中的示例程序(DXSDK ROOT\Samples\C++\DirectShow\Editing\GrabBitmaps)。

      1.2 直接調用Sample Grabber Filter的接口
      如果我們在播放的過程中動態的加入Filter的話,操作和效率都不樂觀。所以我采用下面的方法:

      該方法傳遞的是時間,不是在播放的時候動態加入Filter然后截圖,而是另外打開源文件進行操作。

      A)。申明以下接口:

      #001 IGraphBuilder   *pGraph       = NULL; //for graph builder



      #002 IMediaControl   *pControl     = NULL; //media control



      #003 IMediaSeeking   *pSeeking     = NULL; //media seeking



      #004 IMediaEventEx   *pEvent       = NULL; //media envent



      #005 IBaseFilter      *pNullFilter =NULL;//for holding the Sample grabber Filter



      B)。初始化接口:

      #001 JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,

      #002                  IID_IGraphBuilder, (void **)&pGraph));

      #003

      #004 JIF(CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC,

      #005                 IID_IBaseFilter, (void **)&pNullFilter));

      #006 JIF(pGraph->QueryInterface(IID_IMediaControl,(void                                     **)&pControl));

      #007 JIF(pGraph->QueryInterface(IID_IMediaSeeking, (void                                **)&pSeeking));

      #008 JIF(pGraph->QueryInterface(IID_IMediaEvent, (void                                  **)&pEvent));

      C)。創建Sample Grabber

      #001 // Create the Sample Grabber.



      #002 IBaseFilter *pGrabberF = NULL;

      #003 JIF(CoCreateInstance(CLSID_SampleGrabber,NULL, CLSCTX_INPROC_SERVER,

      #004                             IID_IBaseFilter, (void**)&pGrabberF));

      #005

      #006 JIF(pGraph->AddFilter(pGrabberF, L"Sample Grabber"));

      #007 JIF(pGraph->AddFilter(pNullFilter, L"Null Render Filter"));

      #008

      #009 ISampleGrabber *pGrabber;

      #010 JIF(pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber));

      設置Sample Grabber的媒體格式:調用SetMediaType,該函數接受一個AM_MEDIA_TYPE的結構,主要是設置該結構中的majortype,和subtype域。

      D)。添加Source Filter:

      #001 IBaseFilter *pSrc;

      #002 JIF(pGraph->AddSourceFilter(T2W(m_szFile), L"Source", &pSrc));

      E)。連接Grabber 和 NullRender兩個Filter:

      #001 IPin  *pOutPin;

      #002 hr = GetPin(pGrabberF, PINDIR_OUTPUT, &pOutPin);

      #003

      #004 IPin  *pInPin;

      #005 hr = GetPin(pNullFilter, PINDIR_INPUT, &pInPin);

      #006

      #007 pGraph->Connect(pOutPin, pInPin);

      F)。取得當前所連接媒體的類型

      #001 AM_MEDIA_TYPE mt;

      #002 hr = pGrabber->GetConnectedMediaType(&mt);

      #003 // Examine the format block.



      #004 VIDEOINFOHEADER *pVih;

      #005 if ((mt.formattype == FORMAT_VideoInfo) &&

      #006       (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&

      #007       (mt.pbFormat != NULL) )

      #008 {

      #009       pVih = (VIDEOINFOHEADER*)mt.pbFormat;

      #010 }

      #011 else



      #012 {

      #013       // Wrong format. Free the format block and return an error.



      #014       FreeMediaType(mt);

      #015       return VFW_E_INVALIDMEDIATYPE;

      #016 }

      #017

      #018 // Do buffer the samples as they pass through



      #019 //



      #020 hr = pGrabber->SetBufferSamples(TRUE);

      #021

      #022 // Only grab one at a time, stop stream after



      #023 // grabbing one sample



      #024 //



      #025 hr = pGrabber->SetOneShot( TRUE );

      G)。Seeking文件,使其到達要截圖的時間幀

      #001 pSeeking->SetPositions(pCurrentPos,

      #002                     AM_SEEKING_AbsolutePositioning,

      #003                      NULL, AM_SEEKING_NoPositioning );

      #004

      #005 pControl->Run();

      #006

      #007 long EvCode = 0;

      #008

      #009 hr = pEvent->WaitForCompletion( INFINITE, &EvCode );

      H)。取得當前的buffer數據

      #001 // Find the required buffer size.



      #002 long cbBuffer = 0;

      #003 hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);

      #004 LONGLONG currentPos;

      #005 pSeeking->GetCurrentPosition(&currentPos);

      #006 BYTE *pBuffer = new BYTE[cbBuffer];

      #007 if (!pBuffer)

      #008 {

      #009   // Out of memory. Return an error code.



      #010   Msg("Out of Memory");

      #011 }

      #012 hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);

      I)。寫入文件

      #001 // Create a file to hold the bitmap



      #002 HANDLE hf = CreateFile(szFilename, GENERIC_WRITE, FILE_SHARE_READ,

      #003                                NULL, CREATE_ALWAYS, NULL, NULL );

      #004

      #005 if( hf == INVALID_HANDLE_VALUE )

      #006 {

      #007       // Failed to create file



      #008       return 0;

      #009 }

      #010   

      #011 // Write out the file header



      #012 //



      #013 BITMAPFILEHEADER bfh;

      #014 memset( &bfh, 0, sizeof( bfh ) );

      #015 bfh.bfType = ''MB'';

      #016 bfh.bfSize = sizeof( bfh ) + cbBuffer + sizeof( BITMAPINFOHEADER );

      #017 bfh.bfOffBits =                                 sizeof(BITMAPINFOHEADER)+sizeof( BITMAPFILEHEADER );

      #018   

      #019 DWORD Written = 0;

      #020 WriteFile( hf, &bfh, sizeof( bfh ), &Written, NULL );

      #021   

      #022 // Write the bitmap format



      #023 //



      #024 BITMAPINFOHEADER bih;

      #025 memset( &bih, 0, sizeof( bih ) );

      #026 bih.biSize = sizeof( bih );

      #027 bih.biWidth = pVih->bmiHeader.biWidth;

      #028 bih.biHeight = pVih->bmiHeader.biHeight;

      #029 bih.biPlanes = pVih->bmiHeader.biPlanes;

      #030 bih.biBitCount = pVih->bmiHeader.biBitCount;

      #031

      #032 Written = 0;

      #033

      #034 WriteFile( hf, &bih, sizeof( bih ), &Written, NULL );

      #035

      #036 // Write the bitmap bits



      #037 //



      #038 Written = 0;

      #039 WriteFile( hf, pBuffer, cbBuffer, &Written, NULL );

      #040 FreeMediaType(mt);

      #041 CloseHandle(hf);

      J)。釋放資源

      #001 pControl->Stop();   

      #002 SAFE_RELEASE(pControl);

      #003 SAFE_RELEASE(pSeeking);

      #004 SAFE_RELEASE(pEvent);

      #005 SAFE_RELEASE(pSrc);

      #006 SAFE_RELEASE(pNullFilter);

      #007 SAFE_RELEASE(pGrabber);

      #008 SAFE_RELEASE(pGrabberF);

      #009 SAFE_RELEASE(pGraph);

      K)。其實我們可以不用NullRender,而是用IVideoWindow接口來實現。如果是那樣的話,首先申明IVideoWindow *pVideo = NULL;將pVideo加入到Filter Graph中

      #001 JIF(pGraph->QueryInterface(IID_IVideoWindow,(void**)&pVideo));

      #002 hr = pGraph->Render(pOutPin);

      #003 if (pVideo)

      #004 {

      #005         hr = pVideo->put_AutoShow(OAFALSE);

      #006 }

      通過IBasicVideo::GetCurrentImage接口
      對于該接口,Video Renderer和Video Mixing Renderer(VMR)有不同的實現。

      A)。Video Renderer

      如果該Renderer使用了DDraw加速的話,該調用會失敗。在調用該接口的時候,必須首先暫停Renderer(可以通過IMediaControl::Pause()暫停,如果不能確信該操作是否成功,應該調用IMediaControl::GetState()判斷狀態)。

      B)。Video Mixing Renderer

      對于VMR,該方法都會成功(不管是否運用了DDraw加速,也不管是否是暫停狀態),此時對于它所有的狀態(running, stopped, or paused)都適用。

      函數Grabber代碼如下(調用該函數的時候應該先將媒體文件暫停,原因上面已經說了):

      #001 bool Grabber(IBasicVideo mBasicVideo, TCHAR *szFilename)

      #002 {

      #003   if (mBasicVideo)

      #004   {

      #005       long bitmapSize = 0;

      #006   if(SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))

      #007       {

      #008          //if語句里面的操作時取得buffer的size。



      #009          //當我們在布確定image buffer的大小的情況下,我們給



      #010       //GetCurrentImage的第二個參數傳遞0或者NULL,取得buffer的



      #011          //大小供以后使用。



      #012          bool pass = false;

      #013          unsigned char * buffer = new unsigned char[bitmapSize];

      #014 if(SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize,(long*)buffer)))

      #015          {

      #016              //此時已經用到剛才所取得的大。ǚ峙淇臻g)



      #017              BITMAPFILEHEADER  hdr;    //Bitmap的頭信息



      #018              LPBITMAPINFOHEADER   lpbi; // Bitmap的文件信息(包括數據)



      #019

      #020              lpbi = (LPBITMAPINFOHEADER)buffer;

      #021

      #022              int nColors = 1 << lpbi->biBitCount;

      #023              if (nColors > 256)

      #024                 nColors = 0;

      #025

      #026              hdr.bfType    = ((WORD) (''M'' << 8) ''B'');    //always is "BM"



      #027              hdr.bfSize    = bitmapSize + sizeof( hdr );

      #028              hdr.bfReserved1   = 0;

      #029              hdr.bfReserved2   = 0;

      #030              hdr.bfOffBits     = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize

      #031              CFile bitmapFile(outFile, CFile::modeReadWrite CFile::modeCreate CFile::typeBinary);

      #032              bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));

      #033              bitmapFile.Write(buffer, bitmapSize);

      #034              bitmapFile.Close();

      #035              pass = true;

      #036          }

      #037          delete [] buffer; //數據用過之后記得要釋放空間



      #038          return true;

      #039       }

      #040   }

      #041   

      #042   return false;

      #043 }

      IMediaDet接口
      IMediaDet接口可以取得媒體文件的信息。SDK里面的示例代碼(沒有寫入文件):

      #001 long size;

      #002 //取得圖像幀的大小,給GetBitmapBits的第三個參數傳遞0 or NULL



      #003 hr = pDet->GetBitmapBits(0, &size, 0, width, height);

      #004 if(SUCCEEDED(hr))

      #005 {

      #006   char *pBuffer = new char[size];

      #007   if(!pBuffer)

      #008   {

      #009       return E_OUTOFMEMORY;

      #010   }

      #011   

      #012   try



      #013   {

      #014       hr = pDet->GetbitmapsBits(0, 0, pBuffer, width, height);

      #015   }

      #016   catch(...)

      #017   {

      #018       delete [] pBuffer;

      #019       throw;

      #020   }

      #021   

      #022   if(SUCCEEDED(hr))

      #023   {

      #024       BITMAPINFOHEADER *bmih = (BITMAPINFOHEADER*)pBuffer;

      #025       HDC    hdcDest = GetDC(0);

      #026       

      #027       //Find the address of the start of the image data



      #028       void *pData = pBuffer + sizeof(BITMAPINFOHEADER);

      #029       

      #030       //Note: In general a BITMAPINFOHEADER can include extra color



      #031       //information at the end, so calculating the offset to the image



      #032       //data i snot generally correct. However, the IMediaDet interface



      #033       //always returns an RGB-24 image with no extra color information



      #034          

      #035       BITMAPINFO bmi;

      #036       ZeroMemory(&bmi, sizeof(BITMAPINFO));

      #037       CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));

      #038       HBITMAP hBitmap = CreateDIBitmap(hdcDect, bmih, CBM_INIT,

      #039                     pData, &bmi, DIB_RGB_COLORS);

      #040   }

      #041   

      #042   delete [] pBuffer;

      #043 }

      該方法并沒有寫入bitmap,具體的寫入過程可以參加上面的幾種方法。




      日韩精品一区二区三区高清