这篇文章主要针对《DirectShow中利用SampleGrabber捕获摄像头每一帧图像,并转为BMP文件信息写入内存》所写,记录了开发过程中遇到的比较深刻的问题。文中代码均来自上文。欢迎大家交流斧正。
P1:如何合理放置SampleGrabber在Filter Graph中的位置?
S1 :在放置SampleGrabber位置时应该很小心,因为SampleGrabber通常是作为一个TransformFilter存在的,而不是一个RendererFilter存在。当然,它也能作为一个RendererFilter存在,但是这样一来就不能实现通常所要求的预览功能了。写法如下:那么应该怎样使得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联系起来。所以可以如下写法:
这样一来,就能实现捕获和预览功能了。
P2: 如何合理copy回调函数BufferCB得到的内存数据,比如大小?
S2: 在FormatImage函数中,我们需要copy回调函数BufferCB得到的内存数据到一块内存中,进行处理。但是这个时候copy的大小就很重要了。不能大也不能小。这个地方其实不难想到大小是多少,但是容易犯“想当然”的错误。比如如下写法:
注意了,很多时候可能会想当然地认为nImgWidth*nImgHeight就是buffer的大小,其实不然。如果想如上写法,能得到一定的图片的信息,但是不完整。我当时就只能看到图片的下半部分。其实,在回调函数BufferCB中我们已经保存了这块buffer的大小:
正确的方法应该是直接使用已经保存起来的buffer大小去copy,如下:
P3:关于可能出现的内存泄露问题,比如BufferCB的内存管理问题?
S3: 之前在没有使用SampleGrabber时,程序不存在内存泄露的问题。但是用了之后就出现了泄露问题。说实话,我当时是一头雾水,就拼命地寻找哪块buffer或者哪个filter没有及时释放。在可能的地方都加上释放语句。结果最终证明这样做是错的,即是弄巧成拙。我的愚蠢做法如下:
看似没问题的代码,其实有一个很大的泄漏问题。我们注意到,在BufferCB中有这样的语句:
这就是说,如果cb.pBuffer为空的话,就会重新new一次,就会重新分配一块IBufferSize大小的内存。与此同时,你别以为之前那个cb.pBuffer所分配的内存已经回收了,它只是被只设置为NULL了而已!接着,你就会使用new出来的内存,之前的cb.pBuffer内存就泄露了。事实上,BufferCB函数会自己处理内存释放的问题,你不用瞎操心,要不然就画蛇添足了。所以做法应该是删除cb.pBuffer = NULL;这句。
本文探讨了DirectShow中SampleGrabber的应用技巧,包括合理放置SampleGrabber的位置以实现图像捕获与预览功能、如何正确复制回调函数获得的数据以及解决内存泄露问题。
4199

被折叠的 条评论
为什么被折叠?



