闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣捣閻棗銆掑锝呬壕濡ょ姷鍋為悧鐘汇€侀弴銏犖ч柛灞剧煯婢规洖鈹戦缁撶細闁告鍐f瀺鐎广儱娲犻崑鎾舵喆閸曨剛顦繝鈷€鍕垫疁妤犵偛妫濆顕€宕煎顏佹櫊閹鏁愭惔婵堝嚬閻庣懓鎲$换鍕閹烘挻缍囬柕濞垮劤閻熴劌顪冮妶搴′簼缂侇喗鎸搁悾鐑藉础閻愬秶鍠栭幃娆撳箣濠靛洤顦╅梺鎶芥敱閸ㄥ湱妲愰幘瀛樺濠殿喗鍩堟禍婵嬪箞閵娾晛鐐婇柕濞垮€楃粻姘渻閵堝棛澧柣鏃戝墴閻擃剟顢楅崒妤€浜鹃悷娆忓绾炬悂鏌涙惔锝嗘毈鐎殿噮鍋婇獮妯肩磼濡粯顏熼梻浣芥硶閸o箓骞忛敓锟�濠电姷鏁告慨鐑藉极閸涘﹥鍙忛柣鎴f閺嬩線鏌熼梻瀵割槮缁炬儳顭烽弻锝夊箛椤掍焦鍎撶紓浣哄С閸楁娊寮婚悢鍏尖拻閻庨潧澹婂Σ顔剧磽娴e搫啸闁哥姵鐗犲濠氬Ω閳哄倸浜滈梺鍛婄箓鐎氬懘濮€閵堝棛鍘遍梺闈浨归崕閬嶅焵椤掆偓濠€閬嶅箲閵忕姭妲堥柕蹇曞Т閼板灝鈹戦埥鍡楃仴妞ゆ泦鍥棄鐎广儱顦伴埛鎴犵磼鐎n偒鍎ラ柛搴㈠姉缁辨帞鎷犻幓鎺撴婵犵绱曢弫璇茬暦閻旂⒈鏁嶆慨妯夸含閺夋悂姊绘担鍝ユ瀮婵℃ぜ鍔庨幏瀣蓟閵夈儳锛涢梺瑙勫礃椤曆囧礃閳ь剟鎮峰⿰鍐炬█鐎殿喗鎮傚顕€宕奸悢鍝勫汲闂備胶绮ú鏍磹閸︻厸鍋撳鐐
开发学院软件开发C++ DShow中实现抓图的几种方法 阅读

DShow中实现抓图的几种方法

 2008-03-08 21:40:47 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣捣閻棗銆掑锝呬壕濡ょ姷鍋涢ˇ鐢稿极閹剧粯鍋愰柟缁樺笧閳ь剦鍙冨鍝勑ч崶褏浠奸梺璇茬箲閼归箖鎮鹃悜钘夎摕闁靛濡囬崢鐢告⒑鐟欏嫷鍟忛柛鐘崇墵閵嗗倹绺介崨濠勫幈闁硅壈鎻槐鏇熺墡闂備線娼уú銈団偓姘嵆閻涱噣骞掑Δ鈧粻锝嗙節闂堟稑鏆欏ù婊堢畺閺岋綁濮€閳惰泛婀辨竟鏇熺節濮橆厾鍘甸梺缁樺姦閸撴岸鎮樻潏銊ょ箚闁圭粯甯炴晶娑氱磼缂佹ḿ娲寸€规洖宕灃闁告劕鍟犻崜婵堟崲濞戞ḿ鏆嗗┑鐘辫兌閺佹牜绱撴担浠嬪摵闁圭懓娲ら悾鐑藉箳閹搭厽鍍甸梺鐟板悁閻掞箓鎮楅幖浣光拻濞达絿鍎ら崵鈧梺鎼炲€栭悧鐘荤嵁韫囨稒鏅搁柨鐕傛嫹婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繑銇勯幘鍗炵仼缂佺媭鍨堕弻娑㈠箛闂堟稒鐏堥悗鐟版啞缁诲啴濡甸崟顖氱閻庨潧鎽滈悾濂告⒑绾拋娼愭繛鑼枎椤繒绱掑Ο鑲╂嚌闂侀€炲苯澧畝锝堝劵椤︽煡鎮¢妶澶嬬厪闁割偅绻冮崑顏呯箾瀹割喕绨婚幆鐔兼⒑鐎圭姵銆冮柤鍐茬埣瀹曟繈鏁冮埀顒勨€旈崘顔嘉ч柛鈩冾殘閻熸劙姊洪悡搴℃毐闁绘牕銈稿畷鐑樼節閸パ冨祮闂侀潧楠忕槐鏇㈠储椤忓牊鈷戦柟鑲╁仜閸旀鏌¢崨顔锯姇缂佸倹甯熼ˇ瀵哥磼鏉堛劌绗氭繛鐓庣箻閸┾剝鎷呴柨瀣垫綗闂傚倷娴囧銊╂倿閿曞倸绠查柛銉墮閺嬩線鏌熼崜褏甯涢柡鍛倐閺屻劑鎮ら崒娑橆伓闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�  闂傚倸鍊搁崐鎼佸磹閹间礁纾归柣鎴eГ閸ゅ嫰鏌ら崫銉︽毄濞寸姵姘ㄧ槐鎾诲磼濞嗘帒鍘$紓渚囧櫘閸ㄥ爼濡撮崘顔煎窛闁哄鍨归崢娲倵楠炲灝鍔氭い锔诲灦瀹曪繝骞庨懞銉у帾闂婎偄娲﹀ú鏍ㄧ墡闂備浇顕х€垫帡宕滈悢濂夋綎闁惧繐婀辩壕鍏间繆椤栨碍鎯堟い顐㈢Т椤啴濡堕崱妤€顫庨梺鍛婎焼閸パ呭弨婵犮垼娉涜癌闁绘柨鍚嬮悡銉╂倵閿濆骸鍘撮柛瀣尰缁绘繂顫濋娑欏闁荤喐绮庢晶妤冩暜閹烘挾顩插ù鐓庣摠閻撴洟鏌熼幆褜鍤熼柍钘夘樀閺屽秶绱掑Ο鑽ゅ弳濡炪値鍋呯换鍫ュ箠濠婂懎鏋堟俊顖濐嚙椤忓綊姊婚崒娆戭槮闁硅绱曠划娆撳箣閿斿搫浜奸梺鍝勵槹閸ㄧ喖寮搁弮鍫熺厸闁告劧绲芥禍鍓х磽娴h櫣甯涚紒瀣尰缁傛帡鏁冮崒姘憋紲濠殿喗锕╅崜锕傛倵閹惰姤鈷掑ù锝呮憸閿涘秶绱掗鍛仸妤犵偞鍨垮畷鍫曨敆閸屾氨銈﹂梺璇插嚱缂嶅棙绂嶉弽顓炵哗濞寸姴顑嗛悡娆撴⒑椤撱劎鐣卞褜鍨遍妵鍕棘閸喒鍋撶憴鍕攳濠电姴娲﹂崐閿嬨亜韫囨挸顏ら柛瀣崌瀵€燁檨婵炲吋鐗曢埞鎴︽偐鐎圭姴顥濋梺绋胯閸斿酣骞夊宀€鐤€婵炴垶岣块悿鍛存⒑閸︻叀妾搁柛鐘愁殜瀵煡骞栨担鍦弳闂佺粯娲栭崐鍦偓姘炬嫹
核心提示:1.加入Sample Grabber Filter当我们加入Sample Grabber Filter的时候,我们可以直接调用其接口(interface)ISampleGrabber,DShow中实现抓图的几种方法,该接口可以获取经过该Filter的单独的Media Samples,详情请参见DXSDK,SDK里面的示

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(¤tPos);
#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        //此时已经用到刚才所取得的大小(分配空间)
#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,具体的写入过程可以参加上面的几种方法。

Tags:DShow 实现 方法

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
赞助商链接