DShow中实现抓图的几种方法

Solumate凉生

Solumate凉生

2016-02-19 21:34

下面图老师小编跟大家分享DShow中实现抓图的几种方法,一起来学习下过程究竟如何进行吧!喜欢就赶紧收藏起来哦~
1.加入Sample Grabber Filter  当我们加入Sample Grabber Filter的时候,我们可以直接调用其接口(interface)ISampleGrabber。该接口可以获取经过该Filter的单独的Media Samples。详情请参见DXSDK。   1.1 派生出自己的Sample Grabber  从ISampleGrabberCB中派生出自己的类,然后实现其虚函数,详情请参见SDK中的示例程序(DXSDK ROOTSamplesC++DirectShowEditingGrabBitmaps)。   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)取得当前所连接媒体的类型 !-- frame contents --!-- /frame contents -- #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接口 !-- frame contents --!-- /frame contents --   对于该接口,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,具体的写入过程可以参加上面的几种方法。

展开更多 50%)
分享

猜你喜欢

DShow中实现抓图的几种方法

编程语言 网络编程
DShow中实现抓图的几种方法

保存CSS中的图片的几种方法

Web开发
保存CSS中的图片的几种方法

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

保存Word中的图片的几种方法

电脑入门
保存Word中的图片的几种方法

在ASP中调用存储过程的几种方法

Web开发
在ASP中调用存储过程的几种方法

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

实现页面中按钮刷新的N种方法

Html CSS布局 Div+CSS XHTML
实现页面中按钮刷新的N种方法

在word文档中打"√“的几种方法介绍

word
在word文档中打

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

一分钟制作一个垃圾清除系统

一分钟制作一个垃圾清除系统

Word的主控文档设置

Word的主控文档设置
下拉加载更多内容 ↓