I am writing directshow application. Below is the code that works fine but crashes with the error message "App.exe has stopped working". The entire code is written below. Please note that I am using Windows SDK 7.0 which does not have atlbase.h
and hence I cannot use CComPtr<IBaseFilter> myFilter;
type of pointer declaration which is supposed to clear memory at exit.
EDIT: The application crashes only if I connect all filters explicitly. In this case, the destructor of my filter is not called. If I just connect source filter to renderer (which will internally connect my filter and a demux filter), the destructor of my filter is called and there is no crash. I have put the macro MANUAL_CONNECT
over the code which causes the crash. I have removed RemoveFilter
call and replaced it with Release
call.
I am writing the application code here:
void main(WORD32 argc, CHAR *argv[])
{
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
{
IGraphBuilder *pGraph = NULL;
IFileSourceFilter *pFileSourceFilter = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
IBaseFilter *pSource = NULL;
IBaseFilter *pVideoDecode = NULL;
IBaseFilter *pVideoRenderer = NULL;
IEnumPins *pEnumPins = NULL;
IPin *pPinIn = NULL;
IPin *pPinOut = NULL;
ULONG fetched;
PIN_INFO PinInfo;
IEnumFilters *pEnum = NULL;
BOOL stop = FALSE;
int i;
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pSource);
hr = pGraph->AddFilter(pSource, NULL);
hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSourceFilter);
hr = pFileSourceFilter->Load(L"input.mp4", NULL);
// Create Ittiam HEVC Decoder instance
hr = CoCreateInstance(CLSID_ivdec, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoDecode);
// Create Video Renderer instance. We have used default video renderer
hr = CoCreateInstance(CLSID_VideoRendererDefault, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoRenderer);
// Add decoder filter to the filter graph
hr = pGraph->AddFilter(pVideoDecode, NULL);
// Add renderer filter to the filter graph
hr = pGraph->AddFilter(pVideoRenderer, NULL);
/**************************************************************/
/* -- Connecting source filter to demux filter starts here -- */
/**************************************************************/
// Enumerate pins of the source filter
hr = pSource->EnumPins(&pEnumPins);
hr = pEnumPins->Reset();
// Get pin of source filter. Source filter has only output pin, so no check required
hr = pEnumPins->Next(1, &pPinOut, &fetched);
hr = pEnumPins->Release();
#if MANUAL_CONNECT
// Enumerate pins of the decoder filter
hr = pVideoDecode->EnumPins(&pEnumPins);
hr = pEnumPins->Reset();
// Get pin of decoder filter. Decoder filter has 2 pins, so ensure the selected pin is input pin.
// If not, get another pin
hr = pEnumPins->Next(1, &pPinIn, &fetched);
hr = pPinIn->QueryPinInfo(&PinInfo);
if(PINDIR_OUTPUT == PinInfo.dir)
{
hr = pPinIn->Release();
hr = pEnumPins->Next(1, &pPinIn, &fetched);
}
// Connect output pin of demux filter to input pin of decoder filter
hr = pGraph->Connect(pPinOut, pPinIn);
/*************************************************************/
/* -- Connecting demux filter to decoder filter ends here -- */
/*************************************************************/
/******************************************************************/
/* -- Connecting decoder filter to renderer filter starts here -- */
/******************************************************************/
// Enumerate pins of the decoder filter
hr = pVideoDecode->EnumPins(&pEnumPins);
hr = pEnumPins->Reset();
// Get pin of decoder filter. Decoder filter has 2 pins, so ensure the selected pin is output pin.
// If not, get another pin
hr = pEnumPins->Next(1, &pPinOut, &fetched);
hr = pPinOut->QueryPinInfo(&PinInfo);
if(PINDIR_INPUT == PinInfo.dir)
{
hr = pPinOut->Release();
hr = pEnumPins->Next(1, &pPinOut, &fetched);
}
hr = pEnumPins->Release();
#endif
// Enumerate pins of the renderer filter
hr = pVideoRenderer->EnumPins(&pEnumPins);
hr = pEnumPins->Reset();
// Get pin of renderer filter. Renderer filter has only input pin, so no check required
hr = pEnumPins->Next(1, &pPinIn, &fetched);
hr = pPinIn->QueryPinInfo(&PinInfo);
// Connect output pin of decoder filter to input pin of renderer filter
hr = pGraph->Connect(pPinOut, pPinIn);
/****************************************************************/
/* -- Connecting decoder filter to renderer filter ends here -- */
/****************************************************************/
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
hr = pControl->Stop();
hr = pSource->Release();
hr = pVideoDecode->Release();
hr = pControl->Release();
hr = pEvent->Release();
hr = pGraph->Release();
}
CoUninitialize();
printf("Exiting main!!\n");
}
I have removed error checks from the post but I have all error checks in my code. I can see the Exiting main!!
print but than the application crashes. Any suggestions on how to debug this? Please let me know if any information is missing. I am using Microsoft Visual C++ 2010 Express for my development.
You must terminate all COM activity (specifically: release all COM interface pointers) on the thread before calling CoUninitialize
, you don't do it.
See, for example, this code and its Release
calls at the _tmain
bottom.
It makes sense to use more recent version of Visual Studio (2013, 2015), where free community edition already includes ATL and you can enjoy automatic COM interface reference management using CComPtr
and friends. This is the first advise to those who uses raw COM interface pointers and experience issues managing them incorrectly.
See also:
UPDATE: Using raw pointers inaccurately, you keep having leaks:
hr = pGraph->Connect(pPinOut, pPinIn);
// ...
hr = pEnumPins->Next(1, &pPinOut, &fetched);
IEnumPin::Next
call overwrites pPinOut
pointer and leaks a reference.