DShow中实现抓图的几种方法.docx
- 文档编号:23333207
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:11
- 大小:19.11KB
DShow中实现抓图的几种方法.docx
《DShow中实现抓图的几种方法.docx》由会员分享,可在线阅读,更多相关《DShow中实现抓图的几种方法.docx(11页珍藏版)》请在冰豆网上搜索。
DShow中实现抓图的几种方法
DShow中实现抓图的几种方法
1.加入SampleGrabberFilter
当我们加入SampleGrabberFilter的时候,我们可以直接调用其接口(interface)ISampleGrabber。
该接口可以获取经过该Filter的单独的MediaSamples。
详情请参见DXSDK。
1.1派生出自己的SampleGrabber
从ISampleGrabberCB中派生出自己的类,然后实现其虚函数,详情请参见SDK中的示例程序(DXSDKROOT\Samples\C++\DirectShow\Editing\GrabBitmaps)。
1.2直接调用SampleGrabberFilter的接口
如果我们在播放的过程中动态的加入Filter的话,操作和效率都不乐观。
所以我采用下面的方法:
该方法传递的是时间,不是在播放的时候动态加入Filter然后截图,而是另外打开源文件进行操作。
A)。
申明以下接口:
A)。
申明以下接口:
#001IGraphBuilder*pGraph=NULL;//forgraphbuilder
#002IMediaControl*pControl=NULL;//mediacontrol
#003IMediaSeeking*pSeeking=NULL;//mediaseeking
#004IMediaEventEx*pEvent=NULL;//mediaenvent
#005IBaseFilter*pNullFilter=NULL;//forholdingtheSamplegrabberFilter
B)。
初始化接口:
#001JIF(CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,
#002IID_IGraphBuilder,(void**)&pGraph));
#003
#004JIF(CoCreateInstance(CLSID_NullRenderer,NULL,CLSCTX_INPROC,
#005IID_IBaseFilter,(void**)&pNullFilter));
#006JIF(pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl));
#007JIF(pGraph->QueryInterface(IID_IMediaSeeking,(void**)&pSeeking));
#008JIF(pGraph->QueryInterface(IID_IMediaEvent,(void**)&pEvent));
C)。
创建SampleGrabber
#001//CreatetheSampleGrabber.
#002IBaseFilter*pGrabberF=NULL;
#003JIF(CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,
#004IID_IBaseFilter,(void**)&pGrabberF));
#005
#006JIF(pGraph->AddFilter(pGrabberF,L"SampleGrabber"));
#007JIF(pGraph->AddFilter(pNullFilter,L"NullRenderFilter"));
#008
#009ISampleGrabber*pGrabber;
#010JIF(pGrabberF->QueryInterface(IID_ISampleGrabber,(void**)&pGrabber));
设置SampleGrabber的媒体格式:
调用SetMediaType,该函数接受一个AM_MEDIA_TYPE的结构,主要是设置该结构中的majortype,和subtype域。
D)。
添加SourceFilter:
#001IBaseFilter*pSrc;
#002JIF(pGraph->AddSourceFilter(T2W(m_szFile),L"Source",&pSrc));
E)。
连接Grabber和NullRender两个Filter:
#001IPin*pOutPin;
#002hr=GetPin(pGrabberF,PINDIR_OUTPUT,&pOutPin);
#003
#004IPin*pInPin;
#005hr=GetPin(pNullFilter,PINDIR_INPUT,&pInPin);
#006
#007pGraph->Connect(pOutPin,pInPin);
F)。
取得当前所连接媒体的类型
#001AM_MEDIA_TYPEmt;
#002hr=pGrabber->GetConnectedMediaType(&mt);
#003//Examinetheformatblock.
#004VIDEOINFOHEADER*pVih;
#005if((mt.formattype==FORMAT_VideoInfo)&&
#006(mt.cbFormat>=sizeof(VIDEOINFOHEADER))&&
#007(mt.pbFormat!
=NULL))
#008{
#009pVih=(VIDEOINFOHEADER*)mt.pbFormat;
#010}
#011else
#012{
#013//Wrongformat.Freetheformatblockandreturnanerror.
#014FreeMediaType(mt);
#015returnVFW_E_INVALIDMEDIATYPE;
#016}
#017
#018//Dobufferthesamplesastheypassthrough
#019//
#020hr=pGrabber->SetBufferSamples(TRUE);
#021
#022//Onlygraboneatatime,stopstreamafter
#023//grabbingonesample
#024//
#025hr=pGrabber->SetOneShot(TRUE);
G)。
Seeking文件,使其到达要截图的时间帧
#001pSeeking->SetPositions(pCurrentPos,
#002AM_SEEKING_AbsolutePositioning,
#003NULL,AM_SEEKING_NoPositioning);
#004
#005pControl->Run();
#006
#007longEvCode=0;
#008
#009hr=pEvent->WaitForCompletion(INFINITE,&EvCode);
H)。
取得当前的buffer数据
#001//Findtherequiredbuffersize.
#002longcbBuffer=0;
#003hr=pGrabber->GetCurrentBuffer(&cbBuffer,NULL);
#004LONGLONGcurrentPos;
#005pSeeking->GetCurrentPosition(¤tPos);
#006BYTE*pBuffer=newBYTE[cbBuffer];
#007if(!
pBuffer)
#008{
#009//Outofmemory.Returnanerrorcode.
#010Msg("OutofMemory");
#011}
#012hr=pGrabber->GetCurrentBuffer(&cbBuffer,(long*)pBuffer);
I)。
写入文件
#001//Createafiletoholdthebitmap
#002HANDLEhf=CreateFile(szFilename,GENERIC_WRITE,FILE_SHARE_READ,
#003NULL,CREATE_ALWAYS,NULL,NULL);
#004
#005if(hf==INVALID_HANDLE_VALUE)
#006{
#007//Failedtocreatefile
#008return0;
#009}
#010
#011//Writeoutthefileheader
#012//
#013BITMAPFILEHEADERbfh;
#014memset(&bfh,0,sizeof(bfh));
#015bfh.bfType='MB';
#016bfh.bfSize=sizeof(bfh)+cbBuffer+sizeof(BITMAPINFOHEADER);
#017bfh.bfOffBits=sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER);
#018
#019DWORDWritten=0;
#020WriteFile(hf,&bfh,sizeof(bfh),&Written,NULL);
#021
#022//Writethebitmapformat
#023//
#024BITMAPINFOHEADERbih;
#025memset(&bih,0,sizeof(bih));
#026bih.biSize=sizeof(bih);
#027bih.biWidth=pVih->bmiHeader.biWidth;
#028bih.biHeight=pVih->bmiHeader.biHeight;
#029bih.biPlanes=pVih->bmiHeader.biPlanes;
#030bih.biBitCount=pVih->bmiHeader.biBitCount;
#031
#032Written=0;
#033
#034WriteFile(hf,&bih,sizeof(bih),&Written,NULL);
#035
#036//Writethebitmapbits
#037//
#038Written=0;
#039WriteFile(hf,pBuffer,cbBuffer,&Written,NULL);
#040FreeMediaType(mt);
#041CloseHandle(hf);
J)。
释放资源
#001pControl->Stop();
#002SAFE_RELEASE(pControl);
#003SAFE_RELEASE(pSeeking);
#004SAFE_RELEASE(pEvent);
#005SAFE_RELEASE(pSrc);
#006SAFE_RELEASE(pNullFilter);
#007SAFE_RELEASE(pGrabber);
#008SAFE_RELEASE(pGrabberF);
#009SAFE_RELEASE(pGraph);
K)。
其实我们可以不用NullRender,而是用IVideoWindow接口来实现。
如果是那样的话,首先申明IVideoWindow*pVideo=NULL;将pVideo加入到FilterGraph中
#001JIF(pGraph->QueryInterface(IID_IVideoWindow,(void**)&pVideo));
#002hr=pGraph->Render(pOutPin);
#003if(pVideo)
#004{
#005hr=pVideo->put_AutoShow(OAFALSE);
#006}
通过IBasicVideo:
:
GetCurrentImage接口
对于该接口,VideoRenderer和VideoMixingRenderer(VMR)有不同的实现。
A)。
VideoRenderer
如果该Renderer使用了DDraw加速的话,该调用会失败。
在调用该接口的时候,必须首先暂停Renderer(可以通过IMediaControl:
:
Pause()暂停,如果不能确信该操作是否成功,应该调用IMediaControl:
:
GetState()判断状态)。
B)。
VideoMixingRenderer
对于VMR,该方法都会成功(不管是否运用了DDraw加速,也不管是否是暂停状态),此时对于它所有的状态(running,stopped,orpaused)都适用。
函数Grabber代码如下(调用该函数的时候应该先将媒体文件暂停,原因上面已经说了):
#001boolGrabber(IBasicVideomBasicVideo,TCHAR*szFilename)
#002{
#003if(mBasicVideo)
#004{
#005longbitmapSize=0;
#006if(SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize,0)))
#007{
#008//if语句里面的操作时取得buffer的size。
#009//当我们在布确定imagebuffer的大小的情况下,我们给
#010//GetCurrentImage的第二个参数传递0或者NULL,取得buffer的
#011//大小供以后使用。
#012boolpass=false;
#013unsignedchar*buffer=newunsignedchar[bitmapSize];
#014if(SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize,(long*)buffer)))
#015{
#016//此时已经用到刚才所取得的大小(分配空间)
#017BITMAPFILEHEADERhdr;//Bitmap的头信息
#018LPBITMAPINFOHEADERlpbi;//Bitmap的文件信息(包括数据)
#019
#020lpbi=(LPBITMAPINFOHEADER)buffer;
#021
#022intnColors=1<
#023if(nColors>256)
#024nColors=0;
#025
#026hdr.bfType=((WORD)('M'<<8)|'B');//alwaysis"BM"
#027hdr.bfSize=bitmapSize+sizeof(hdr);
#028hdr.bfReserved1=0;
#029hdr.bfReserved2=0;
#030hdr.bfOffBits=(DWORD)(sizeof(BITMAPFILEHEADER)+lpbi->biSize
#031CFilebitmapFile(outFile,CFile:
:
modeReadWrite|CFile:
:
modeCreate|CFile:
:
typeBinary);
#032bitmapFile.Write(&hdr,sizeof(BITMAPFILEHEADER));
#033bitmapFile.Write(buffer,bitmapSize);
#034bitmapFile.Close();
#035pass=true;
#036}
#037delete[]buffer;//数据用过之后记得要释放空间
#038returntrue;
#039}
#040}
#041
#042returnfalse;
#043}
IMediaDet接口
IMediaDet接口可以取得媒体文件的信息。
SDK里面的示例代码(没有写入文件):
#001longsize;
#002//取得图像帧的大小,给GetBitmapBits的第三个参数传递0orNULL
#003hr=pDet->GetBitmapBits(0,&size,0,width,height);
#004if(SUCCEEDED(hr))
#005{
#006char*pBuffer=newchar[size];
#007if(!
pBuffer)
#008{
#009returnE_OUTOFMEMORY;
#010}
#011
#012try
#013{
#014hr=pDet->GetbitmapsBits(0,0,pBuffer,width,height);
#015}
#016catch(...)
#017{
#018delete[]pBuffer;
#019throw;
#020}
#021
#022if(SUCCEEDED(hr))
#023{
#024BITMAPINFOHEADER*bmih=(BITMAPINFOHEADER*)pBuffer;
#025HDChdcDest=GetDC(0);
#026
#027//Findtheaddressofthestartoftheimagedata
#028void*pData=pBuffer+sizeof(BITMAPINFOHEADER);
#029
#030//Note:
IngeneralaBITMAPINFOHEADERcanincludeextracolor
#031//informationattheend,socalculatingtheoffsettotheimage
#032//dataisnotgenerallycorrect.However,theIMediaDetinterface
#033//alwaysreturnsanRGB-24imagewithnoextracolorinformation
#034
#035BITMAPINFObmi;
#036ZeroMemory(&bmi,sizeof(BITMAPINFO));
#037CopyMemory(&(bmi.bmiHeader),bmih,sizeof(BITMAPINFOHEADER));
#038HBITMAPhBitmap=CreateDIBitmap(hdcDect,bmih,CBM_INIT,
#039pData,&bmi,DIB_RGB_COLORS);
#040}
#041
#042delete[]pBuffer;
#043}
该方法并没有写入bitmap,具体的写入过程可以参加上面的几种方法。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DShow 实现 方法