directshow 中 x Objects left active 问题的解决
说明:这篇文章并不具有普遍性,也不涉及深入的com和directshow知识,但如果你也遇到了类似的问题,它可以起一个借鉴作用。
“x Objects left active“这是很多人开发direct show时遇到的一个错误,我也被它困扰过很长一段时间,直到最近才找到解决的办法。假设出错的代码是这样的:
#include " stdafx.h " #include < dshow.h > #include < stdio.h > #include < qedit.h > #include < streams.h > // DirectShow (includes windows.h) void runthread( void ){ IGraphBuilder * pGraph = NULL; IMediaControl * pControl = NULL; IMediaEvent * pEvent = NULL; IBaseFilter * pSampleGrabber1 = NULL, * pSampleGrabber2 = NULL; // Initialize the COM library. HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { printf( " ERROR - Could not initialize COM library " ); return ; } // Create the filter graph manager and query for interfaces. hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, ( void ** ) & pGraph); if (FAILED(hr)) { printf( " ERROR - Could not create the Filter Graph Manager. " ); return ; } hr = pGraph -> QueryInterface(IID_IMediaControl, ( void ** ) & pControl); hr = pGraph -> QueryInterface(IID_IMediaEvent, ( void ** ) & pEvent); hr = pGraph -> RenderFile(L " C:/DXSDK/Samples/Media/CLOCKTXT.avi " ,NULL); // Create Filters hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, ( void ** ) & pSampleGrabber1); hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, ( void ** ) & pSampleGrabber2); // Add filters to Filter Graph hr = pGraph -> AddFilter(pSampleGrabber1,L " filter3 " ); hr = pGraph -> AddFilter(pSampleGrabber2,L " filter4 " ); /// /// { IEnumFilters * pEnumFilter = NULL; IBaseFilter * pFilter = NULL; IEnumPins * pEnumPin = NULL; IPin * pPin = NULL; FILTER_INFO FilterInfo; PIN_INFO PinInfo; pGraph -> EnumFilters( & pEnumFilter); while (pEnumFilter -> Next( 1 , & pFilter,NULL) == S_OK) { pFilter -> QueryFilterInfo( & FilterInfo); printf( " filter name : ws " ,FilterInfo.achName); pFilter -> EnumPins( & pEnumPin); int i = 0 ,j = 0 ; while (pEnumPin -> Next( 1 , & pPin,NULL) == S_OK) { // Check pin info pPin -> QueryPinInfo( & PinInfo); printf( " ..filter pin : ws " ,PinInfo.achName); // printf("..filter pin : ws ",pPin->QueryId); if (PinInfo.dir == PINDIR_INPUT) printf( " ..Pin is Input " ); else printf( " ..Pin is Output " ); // Check Connect AM_MEDIA_TYPE pmt; ZeroMemory( & pmt, sizeof (AM_MEDIA_TYPE)); if (pPin -> ConnectionMediaType( & pmt) != S_OK) printf( " ..this pin is not connected. " ); // Check Render if (PinInfo.dir == PINDIR_INPUT && pmt.majortype == MEDIATYPE_Video) i = 1 ; if (PinInfo.dir == PINDIR_INPUT && pmt.majortype == MEDIATYPE_Audio) i = 2 ; j ++ ; } if (j == 1 && i == 1 ) printf( " ..this is a video render. " ); if (j == 1 && i == 2 ) printf( " ..this is a audio render. " ); pEnumPin -> Release(); } pEnumFilter -> Release();} // return;*/ /// /// /* if (SUCCEEDED(hr)) { // Run the graph. hr = pControl->Run(); if (SUCCEEDED(hr)) { // Wait for completion. long evCode; pEvent->WaitForCompletion(INFINITE, &evCode); } } */ pSampleGrabber1 -> Release(); pSampleGrabber2 -> Release(); pControl -> Release(); pEvent -> Release(); pGraph -> Release(); CoUninitialize();} void main(){ runthread();}
这段程序先建立一个用来渲染文件的filtergraph,然后建立两个SampleGrabber Filter,并将其加入filtergraph。请注意,这两个filter只是加入了filtergraph,而没有于其中任何一个filter连接。接下来,程序例遍整个filtergraph,显示filter的名字、pin的名字、pin的连接情况,并根据filter拥有的已连接的input pin数目和pin的媒体类型来判断该filter是否是一个renderer(尽管这并非十分科学)。
看起来程序并没有错,可我们在调试时却得到了这样的结果:Executable:***.exe Pid *** Tid ***.Module qedit.dll, 6 objects left active!这就是说,我们还有未释放的资源。当然,你可以将这条消息屏蔽掉,而且你的程序也不会出现太大的问题,至少眼前来说是如此。
其实问题个根源在这里:
pGraph -> EnumFilters( & pEnumFilter); while (pEnumFilter -> Next( 1 , & pFilter,NULL) == S_OK){....}pEnumFilter -> Release();看看DirectShow关于Enumerating Filters的说明,你会找到这样一句:“Note the places where the function calls Release on an interface to decrement the reference count.“也就是说,pEnumFilter->Next返回的pFilter指向的接口是一个新申请的接口,而系统并不自己释放它,只就需要我们来做了:
pGraph -> EnumFilters( & pEnumFilter); while (pEnumFilter -> Next( 1 , & pFilter,NULL) == S_OK){.... pFilter -> Release();}pEnumFilter -> Release();类似情况也出现在pFilter->QueryFilterInfo和pEnumPin->Next(1,&pPin,NULL)中。所以我们必须手动释放其中接口指针指向的接口。修改之后的代码:
#include " stdafx.h " #include < dshow.h > #include < stdio.h > #include < qedit.h > #include < streams.h > // DirectShow (includes windows.h) void runthread( void ){ IGraphBuilder * pGraph = NULL; IMediaControl * pControl = NULL; IMediaEvent * pEvent = NULL; IBaseFilter * pSampleGrabber1 = NULL, * pSampleGrabber2 = NULL; // Initialize the COM library. HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { printf( " ERROR - Could not initialize COM library " ); return ; } // Create the filter graph manager and query for interfaces. hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, ( void ** ) & pGraph); if (FAILED(hr)) { printf( " ERROR - Could not create the Filter Graph Manager. " ); return ; } hr = pGraph -> QueryInterface(IID_IMediaControl, ( void ** ) & pControl); hr = pGraph -> QueryInterface(IID_IMediaEvent, ( void ** ) & pEvent); hr = pGraph -> RenderFile(L " C:/DXSDK/Samples/Media/CLOCKTXT.avi " ,NULL); // Create Filters hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, ( void ** ) & pSampleGrabber1); hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, ( void ** ) & pSampleGrabber2); // Add filters to Filter Graph hr = pGraph -> AddFilter(pSampleGrabber1,L " filter3 " ); hr = pGraph -> AddFilter(pSampleGrabber2,L " filter4 " ); /// /// { IEnumFilters * pEnumFilter = NULL; IBaseFilter * pFilter = NULL; IEnumPins * pEnumPin = NULL; IPin * pPin = NULL; FILTER_INFO FilterInfo; PIN_INFO PinInfo; pGraph -> EnumFilters( & pEnumFilter); while (pEnumFilter -> Next( 1 , & pFilter,NULL) == S_OK) { pFilter -> QueryFilterInfo( & FilterInfo); printf( " filter name : ws " ,FilterInfo.achName); pFilter -> EnumPins( & pEnumPin); int i = 0 ,j = 0 ; while (pEnumPin -> Next( 1 , & pPin,NULL) == S_OK) { // Check pin info pPin -> QueryPinInfo( & PinInfo); printf( " ..filter pin : ws " ,PinInfo.achName); // printf("..filter pin : ws ",pPin->QueryId); if (PinInfo.dir == PINDIR_INPUT) printf( " ..Pin is Input " ); else printf( " ..Pin is Output " ); // Check Connect AM_MEDIA_TYPE pmt; ZeroMemory( & pmt, sizeof (AM_MEDIA_TYPE)); if (pPin -> ConnectionMediaType( & pmt) != S_OK) printf( " ..this pin is not connected. " ); // Check Render if (PinInfo.dir == PINDIR_INPUT && pmt.majortype == MEDIATYPE_Video) i = 1 ; if (PinInfo.dir == PINDIR_INPUT && pmt.majortype == MEDIATYPE_Audio) i = 2 ; j ++ ; pPin -> Release(); } if (j == 1 && i == 1 ) printf( " ..this is a video render. " ); if (j == 1 && i == 2 ) printf( " ..this is a audio render. " ); pEnumPin -> Release(); if (FilterInfo.pGraph != NULL) { int k = FilterInfo.pGraph -> Release(); printf( " %d " ,k); } pFilter -> Release(); } pEnumFilter -> Release();} // return;*/ /// /// /* if (SUCCEEDED(hr)) { // Run the graph. hr = pControl->Run(); if (SUCCEEDED(hr)) { // Wait for completion. long evCode; pEvent->WaitForCompletion(INFINITE, &evCode); } } */ pSampleGrabber1 -> Release(); pSampleGrabber2 -> Release(); pControl -> Release(); pEvent -> Release(); pGraph -> Release(); CoUninitialize();} void main(){ runthread();}
转载请注明 “刘佳鹏原创“ 2007-2-6