[转]directshow:图片的抓取

<p>本文转自:<font>http://blog.chinaunix.net/u2/63021/showart_492136.html</font></p><p>原文如下:</p><p>在播放媒体文件的过程中,有一个很有用的功能,就是在当前播放的位置抓取图,实现这种图片抓取功能的方法很多,我们这里只介绍常用的两种。<font size="2"> </font></p><p><br><strong>第1种</strong>方法最简单,它使用1basicvideo::getcurrentimage接口方法,代码如下。<br> heel snapshotbitmap(ibasicvideo*pba8icvideo, const char*outfile)<br> if (pbasicvldeo)<br> {<br> long bitmapsize=0;<br> //首先获得图像大小<br> if(succeeded(peasicvidee->getcurrentimage(&bitmapsize,0)))<br> {<br> bool pass=false;<br> //分配图像帧内存<br> unsigned char*buffer=new unsigned char[bitmapsize];<br> //获取图像帧数据<br> if(succeeded(pbasicvideo->getcurrentimage(&bitmapsize,(long*)buffer)))<br> {<br> bitmapfileheader hdr;<br> lpbitmapinfoheader ipbi;<br> ipbi=(lpbitmapinfoheader)buffer;<br> int ncolors=1<<ipbi->bibitcount;<br> if(ncolors>256)<br> //always is”bm”<br> hdr.bftype =((word)(‘m’<<8)|’b’);<br> hdr.bfsize =bitmapsize+sizeof(hdr);<br> hdr.bfreservedl =0;<br> hdr.bfreserved2 =0;<br> hdr.bfoffbits =(dword)<br> (sizeof(bitmapfileheader)+lpbi->bisize+ncolors*sizeof(rgbquad));<br> cfile bitmapfile(outfile,cfile::modereadwrite |<br> cfile::modecreate | cfile::typebinary);<br> //写入位图文件头<br> bitmapfile.write{&hdr,sizeof【bitmapfileheader));<br> //写入图像帧数据(包括bitmapinfoheader信息)<br> bitmapfile.write(buffer,bitmapsize);<br> bitmapfile.close();<br> pas8=true;<br>}<br> delete[]burfer;<br> return pass;<br> }<br> return false ;</p><p>值得注意的是,ibasievideo接口应该从filtergraphmanager上获得,但真正实现在 <br>rendererfilter上。如果我们使用的是传统的videorenderer,那么使用getcurrentlmage 抓图将是不可靠的。因为如果videorenderer使用了directdraw加速,这个函数调用会失 败;而且调用这个函数,videorenderer必须处于暂停状态。但如果我们使用的是vmr, 则没有上述这些限制。 </p><p><br><strong>第2种</strong>方法比较复杂.它使用samplegrabberfilter。它其实是一个trans-in-place <br>filter,在sdk安装目录下的samples\c++\directshow’filters\grabber提供了源代码。实际 上,samplegrabber可以抓取任何类型的sample。但在这里,我们只介绍使用它抓取视频 帧的方法。步骤如下: <br><br><strong>(1)创建samplegrabber,并将之加入到filtergraph中。</strong> <br>//createthesamplegrabber <br>ibasefilter*pgrabberf=null; <br>hr=cocreateinstanee(clsid_samplegrabber,null,clsctx_inproc_server, <br>iidibasefilter,(void**)&pgrabberf); <br>if(failed(hr)) <br>{<br>//returnanerror<br>}<br>hr=pgraph->addfilter(pgrabberf,l"samplegrabber"); <br>if(failed(hr) <br>{ <br>//returnanerror <br>} <br>isamplegrabber*pgrabber=null; <br>pgrabberf->queryinterface(iid_isamplegrabber,(void**)&pgrabber);<br><br><strong>(2)给samplegrabber设置pin上连接用的媒体类型。 <br></strong> 如果我们想抓取24位的rgb图片,如下设置媒体类型: <br>am_media_typemt; <br>zeromemory(&mt,sizeof(am_media_type)); <br>mt.malortype=mediatypevideo; <br>mt.subtype=me:diasubtypergb24; <br>hr=pgrabber->setmediatype(&mt); <br>也可以根据当前显示器的配置来设置samplegrabber接受的rgb类型,代码如下:<br>//findthecurrentbitdepth <br>hdchdc=getdc(null); <br>intibitdepth=getdevicecaps(hdc,bitspixel); <br>releasedc(null,hdc); <br>//setthemediatype <br>mt.majortype=mediatypevideo; <br>switch(ibitdepth) <br>{ <br>case8: <br>mt.subtype=mediasubtypergb8; <br>break; <br>case16: <br>mt.subtype=mediasubtype_rgb555; <br>break; <br>case24: <br>mt.subtype=mediasubtype_rgb24; <br>break; <br>case32: <br>mt.subtype=mediasubtype_rgb32; <br>break; <br>default: <br>returne_fail; <br>} <br>hr=pgrabber->setmediatype(&mt);<br><br><strong>(3)完成filtergraph的构建。</strong> <br>因为samplegrabber上已经设置了一个媒体类型,则其他filter必须以这种媒 <br>才能与samplegrabber相连。我们可以使用dimctshow的“智能连接”机制,来 <br>个fitlergraph的创建过程,代码如下。 <br>ibasefiiter*psrc; <br>hr=pgraph->addsourcefilter(wszfilename,l"source",&psrc};<br>if(failed(hr)) <br>{ <br>//returnanerrorcode <br>} <br>hr=connectfiiters(pgraph,psrc,pgrabberf); <br>其中,connectfilters是我们在5.3节中介绍的自定义函数。 <br>如果我们只是想抓图(不需要对视频预览),则samplegrabber后面可以连接一个null rendererfilter(它的clsid为clsidnullrenderer)。如果要filtergraph中的数据流以最快的速度传送,则filtergraph不要使用参考时钟(调用imediafitter::setsyncsource,参数为null)。 </p><p><font size="2"><strong>(4)运行filtergraph。 <br></strong>samplegrabber可以有如下两种工作模式: <br>缓冲模式将输入的sample进行缓存后,再往下传送。 <br>回调模式当有输入的sample时,调用应用程序设置进来的回调函数。 <br>因为回调模式会影响整个filtergraph的效率,并且容易引起死锁,所以我们推荐使用缓冲模式。另外,我们可以设置isamplegrabber::setoneshot,使得samplegrabber获取一个sample以后,就让filtergraph停止,代码如下:<br>//setone-shotmodeandbuffering. <br>hr=pgrabber->setoneshot(true); <br>hr=pgrabber->setbuffersamples(true); <br>pcontrol->run();//runthegraph. <br>pevent->waitforcompletion(infinite,&evcode),//waittillit’sdone.<br><br></font><font size="2"><strong>(5)获取抓到的sample数据</strong>。<br></font><font size="2">缓冲模式下,我们可以调用isamplegrabber::getcurrentbuffer来获取sample数据,代码如下: <br>//findtherequiredbuffersize <br>longcbbuffer=0; <br>hr=pgrabber->getcurrentbuffer(&cbbuffer,null); <br>char*pbuffer=newchar[cbbuffer]; <br>if(!pbuffer) <br>//outofmemory.returnanerrorcode <br>} <br>hr=pgrabber->getcurrentbuffer(&cbbuffer,(long*)pbuffer); <br>我们也可以将获取的数据使用gdi函数显示出来,代码如下: <br>am_media_typemt; <br>hr=pgrabber->getconnectedmediatype(&rot); <br>if(failed(hr)) <br>{ <br>//returnerr05code <br>} <br>//examinetheformatblock <br>videoinfoheader*pvih; <br>if((mt.formattype==format_videoinfo)&& <br>(mt.cbformat>=sizeof(videoinfoheader))&& <br>(mt.pbformat!=null)) <br>pvih={videoinfoheader*)mt·pbformat; <br>} <br>else <br>{ <br>//wrongformat.freetheformatblockandreturnanerror‘ <br>freemedlatype(mt); <br>returnvfw_e_invalidmediatype; <br>//youcanusethemediatypetoaccessthebitmapinfoheafreinformation, <br>//forexample,thefollowingcodedrawsthebitmapusinggdi <br>setdibitstodevice( <br>hdc,0,0, <br>pvih->bmiheader.biwidth, <br>pvih->bmiheader.biheight, <br>o,o, <br>0, <br>pvih->bmiheader.biheight, <br>pbuffer, <br>(bitmapinfo*)&pvih->bmiheader, <br>dibrgbcolors <br>), <br>//freetheformatblockwhenyouaredone: <br>freemediatype(mt);<br></font></p>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值