SampleGrabber开发问题与解决方案_ICTwangbiao的博客-程序员宝宝

技术标签: filter  SampleGrabber  内存泄露  callback  buffer  DirectShow  BUFFER  

这篇文章主要针对《DirectShow中利用SampleGrabber捕获摄像头每一帧图像,并转为BMP文件信息写入内存》所写,记录了开发过程中遇到的比较深刻的问题。文中代码均来自上文。欢迎大家交流斧正。

P1:如何合理放置SampleGrabber在Filter Graph中的位置?

S1:在放置SampleGrabber位置时应该很小心,因为SampleGrabber通常是作为一个TransformFilter存在的,而不是一个RendererFilter存在。当然,它也能作为一个RendererFilter存在,但是这样一来就不能实现通常所要求的预览功能了。写法如下:
hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,m_pBF, NULL, pGrabBase);  


   那么应该怎样使得SampleGrabber和RendererFilter都得到Media Sample数据呢?容易发现,对于ICaptureGraphBuilder2::RenderStream(const GUID *pCategory,const GUID *pType,IUnknown *pSource,IBaseFilter *pIntermediate,IBaseFilter*pSink)的最后三个参数,pSource指向一个作为源头的SourceFilter或者输出Pin;pIntermediate指向一个中间Filter或者一个解压缩Filter(当然TransformFilter包括在内),可以为NULL;pSink指向一个RendererFilter或者一个MuxFilter,如果为空,将使用默认Filter。
   有了以上信息,我们不难把pIntermediate和我们的SampleGrabber Filter联系起来。所以可以如下写法:
 
 hr = m_pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pBF, pGrabBase, m_pVMR);


   这样一来,就能实现捕获和预览功能了。
  
P2: 如何合理copy回调函数BufferCB得到的内存数据,比如大小?
S2:
在FormatImage函数中,我们需要copy回调函数BufferCB得到的内存数据到一块内存中,进行处理。但是这个时候copy的大小就很重要了。不能大也不能小。这个地方其实不难想到大小是多少,但是容易犯“想当然”的错误。比如如下写法:
memset( m_pImgFileData, 0, nDataWidth*nImgHeight ) ;
memcpy( m_pImgFileData, lpImageData, nImgWidth*nImgHeight) ;


注意了,很多时候可能会想当然地认为nImgWidth*nImgHeight就是buffer的大小,其实不然。如果想如上写法,能得到一定的图片的信息,但是不完整。我当时就只能看到图片的下半部分。其实,在回调函数BufferCB中我们已经保存了这块buffer的大小:
if (!cb.pBuffer)
{
cb.pBuffer = new BYTE[lBufferSize];
cb.lBufferSize = lBufferSize;
}


正确的方法应该是直接使用已经保存起来的buffer大小去copy,如下:
memset( m_pImgFileData, 0, nDataWidth*nImgHeight ) ;
memcpy( m_pImgFileData, lpImageData, cb.lBufferSize) ;



P3:关于可能出现的内存泄露问题,比如BufferCB的内存管理问题?
S3:
之前在没有使用SampleGrabber时,程序不存在内存泄露的问题。但是用了之后就出现了泄露问题。说实话,我当时是一头雾水,就拼命地寻找哪块buffer或者哪个filter没有及时释放。在可能的地方都加上释放语句。结果最终证明这样做是错的,即是弄巧成拙。我的愚蠢做法如下:
BYTE* pImageData = new BYTE[cb.lBufferSize];
CopyMemory(pImageData, cb.pBuffer, cb.lBufferSize);
if (mCB.FormatImage(pImageData, 24,  cb.bih.biWidth, cb.bih.biHeight))
{
ScaleRgb24BmpData(TransformBuffer, 320, 240,( mCB.GetImgFileData()),cb.bih.biWidth, cb.bih.biHeight);
ZeroMemory(m_pData, BUFFER_SIZE);
CopyMemory(m_pData, TransformBuffer, BUFFER_SIZE);
}
//to free memory
cb.pBuffer = NULL;
delete pImageData;


看似没问题的代码,其实有一个很大的泄漏问题。我们注意到,在BufferCB中有这样的语句:
if (!cb.pBuffer)
{
cb.pBuffer = new BYTE[lBufferSize];
cb.lBufferSize = lBufferSize;
}


这就是说,如果cb.pBuffer为空的话,就会重新new一次,就会重新分配一块IBufferSize大小的内存。与此同时,你别以为之前那个cb.pBuffer所分配的内存已经回收了,它只是被只设置为NULL了而已!接着,你就会使用new出来的内存,之前的cb.pBuffer内存就泄露了。事实上,BufferCB函数会自己处理内存释放的问题,你不用瞎操心,要不然就画蛇添足了。所以做法应该是删除cb.pBuffer = NULL;这句。

//END ICTwangbiao


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ICTwangbiao/article/details/8181832

智能推荐

ridge regression岭回归_gaochao1995的博客-程序员宝宝

岭回归用于处理下面两类问题:1.数据点少于变量个数2.变量间存在共线性岭回归的原理岭回归是一种专用于共线性数据分析的有偏估计回归方法,实质上是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价,获得回归系数更为符合实际、更可靠的回归方法,对病态数据的耐受性远远强于最小二乘法。岭回归的原理较为复杂。根据高斯马尔科夫定力,多重相关性并不

「miRNA系列」植物如何进行miRNA靶基因预测_徐洲更hoptop的博客-程序员宝宝

本科时便接触过miRNA,那个时候还查过一些关于miRNA相关的内容,准备在一个学习小组中讲讲,可惜的是,当时的自己也没有搞懂。而最近一次的miRNA-seq数据分析,终于让自己对它有一些理解。miRNA的长度一般在20~24 nt 之间,通过调节下游靶基因来调控生物的发育,抗逆等。2002年的一篇Cell中指出[1],动物的miRNA和mRNA并没有非常严格的碱基配对,因...

SpringCloud Fegin CircuitBreaker (原hystrix) 熔断失效原因_feign:circuitbreaker_程序一逸的博客-程序员宝宝

今天想着给自己的微服务项目添加一个熔断的功能,正好项目内远程调用是用的feign,那就直接用hystrix好了,也比较方便。然后呢,我以为比较简单的东西,却一直不生效,资料查了个遍,硬是弄了我一上午+一下午的时间,所以记录一下,给大家避坑。

公网Wiki站点搭建全流程攻略·小白向(含Parsoid和VisualEditor)_johnbriton的博客-程序员宝宝

关键词:MediaWiki-1.34.2、Ubuntu 18.04、腾讯云、Wiki、VisualEditor、Parsoid包含:打开VisualEditor时,Parsoid 404的一个解决办法,详见文末。大家好,我是johnbriton。最近我在为学院的一个竞赛团队搭建一个团队wiki,用来储存并分享我们前期调研所收集到的各种信息。作为一种知识管理系统,wiki的内链做的相当方便,而且方便设置权限,便于多人协同工作,适合团队使用。由于本人的专业与计算机完全不相关,所以在搭建站点的时候踩了很多坑

web test LoadRunner xml / webservice / json / MQ / soapUI / baowen / WebService_to better understand the cause of failed steps, yo_可口可乐的围脖的博客-程序员宝宝

转载地址:http://lindows.iteye.com/blog/1725279loadrunner 学习笔记--Web Serviceshttp://www.byywee.com/page/M0/S227/227297.html使用loadrunner测试Web Services的程序http://blog.sina.com.cn/s/blog_7833c845010

随便推点

String与List互转,List<String>转List<Long>_list<string>转list<long>_乐羊子灰的博客-程序员宝宝

String与List互转,List转ListString与List互转List转ListString与List互转 String strs = "1,2"; String str[] = strs.split(","); List&lt;String&gt; list = Arrays.asList(str); String joinStr = Joiner.on(",").join(list); List转List

关于HashMap很好的博文-推荐_hashmap getkey的时间复杂度_静_默的博客-程序员宝宝

摘要 HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型。随着JDK(Java Developmet Kit)版本的更新,JDK1.8对HashMap底层的实现进行了优化,例如引入红黑树的数据结构和扩容的优化等。本文结合JDK1.7和JDK1.8的区别,深入探讨HashMap的结构实现和功能原理。简介 Java为数据结构中的映射定义了一个接口java.util.Map,

pull和sax解析xml文件_uniquemei的博客-程序员宝宝

/*** * pull解析 **/ public void parseXMLWithPull(String xmlData) { try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser par

Java ip地址查询,根据ip接口获得ip所在省市区,邮编,运营商等_宝贝企鹅的博客-程序员宝宝

互联网有很多接口可以实现通过ip查询到具体的位置,如下:通过淘宝IP地址库获取IP位置1. 请求接口(GET):http://ip.taobao.com/service/getIpInfo.php?ip=[ip地址字串]2. 响应信息:(json格式的)国家 、省(自治区或直辖市)、市(县)、运营商3. 返回数据格式:{"code":0,"data":{"ip":"210.75...

成为一名程序员的四个阶段!!!_三木_新浪博客_u6eQK6e3Q26oQzT1的博客-程序员宝宝

通过以下4个阶段的训练, 没有任何编程基础人就可以成为一名普通的程序员。 第一阶段:掌握一种编程语言 学习内容:学习任意一种主流的编程语言。例如C++语言。 学习目标:熟练掌握一种语言的语法和基本的编程技巧。 学习时间:3个月左右 注意事项:编程语言和编程工具是两回事情,编程语言是指C++、Basic、Object P...

推荐文章

热门文章

相关标签