none
每次打开一个新文件,发现多出4个线程 RRS feed

  • 问题

  • hi,程序使用一个派生于CBaseVideoRenderer的一个类,若在CheckMediaType中强制使用MEDIASUBTYPE_RGB32或MEDIASUBTYPE_RGB24时,每次打开一个新文件,就发现多出四个左右线程,而使用缺省的MEDIASUBTYPE_YV12或MEDIASUBTYPE_YUYV等就没有问题,这是为什么???
    2011年11月3日 10:02

答案

  • 非常感谢各位的回复,我调试时发现是Graph Connect时产生的,应该是系统产生的或Decoder产生的,decoder用的是ffdshow,打开的文件是mpeg2文件,关键是多次打开文件产生的线程数太多,会导致程序崩溃啊!我的程序是不允许关机的。

    • 已标记为答案 Rob Pan 2011年11月16日 8:47
    2011年11月16日 1:28

全部回复

  • 下面是部分代码
    //
    // CDXGraph.h
    //
    
    #ifndef __H_CDXGraph__
    #define __H_CDXGraph__
    
    // Filter graph notification to the specified window
    #define WM_GRAPHNOTIFY  (WM_USER+20)
    
    class CDXGraph
    {
    private:
    	IGraphBuilder *     mGraph;  
    	IMediaControl *		mMediaControl;
    	IMediaEventEx *		mEvent;
    	IBasicVideo *		mBasicVideo;
    	IBasicAudio *		mBasicAudio;
    	IVideoWindow  *		mVideoWindow;
    	IMediaSeeking *		mSeeking;
    
    	DWORD				mObjectTableEntry; 
    
    public:
    	CDXGraph();
    	virtual ~CDXGraph();
    
    public:
    	virtual bool Create(void);
    	virtual void Release(void);
    	virtual bool Attach(IGraphBuilder * inGraphBuilder);
    
    	IGraphBuilder * GetGraph(void); // Not outstanding reference count
    	IMediaEventEx * GetEventHandle(void);
    
    	bool ConnectFilters(IPin * inOutputPin, IPin * inInputPin, const AM_MEDIA_TYPE * inMediaType = 0);
    	void DisconnectFilters(IPin * inOutputPin);
    
    	bool SetDisplayWindow(HWND inWindow);
    	bool SetNotifyWindow(HWND inWindow);
    	bool ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight);
    	void HandleEvent(WPARAM inWParam, LPARAM inLParam);
    
    	bool Run(void);        // Control filter graph
    	bool Stop(void);
    	bool Pause(void);
    	bool IsRunning(void);  // Filter graph status
    	bool IsStopped(void);
    	bool IsPaused(void);
    
    	bool SetFullScreen(BOOL inEnabled);
    	bool GetFullScreen(void);
    
    	// IMediaSeeking
    	bool GetCurrentPosition(double * outPosition);
    	bool GetStopPosition(double * outPosition);
    	bool SetCurrentPosition(double inPosition);
    	bool SetStartStopPosition(double inStart, double inStop);
    	bool GetDuration(double * outDuration);
    	bool SetPlaybackRate(double inRate);
    
    	// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
    	bool SetAudioVolume(long inVolume);
    	long GetAudioVolume(void);
    	// Attention: range from -10000(left) to 10000(right), and 0 is both.
    	bool SetAudioBalance(long inBalance);
    	long GetAudioBalance(void);
    
    	bool RenderFile(const char * inFile);
    	bool SnapshotBitmap(const char * outFile);
    
    private:
    	void AddToObjectTable(void) ;
    	void RemoveFromObjectTable(void);
    	
    	bool QueryInterfaces(void);
    };
    
    #endif // __H_CDXGraph__
    //
    // CDXGraph.cpp
    //
    
    #include "stdafx.h"
    #include <streams.h>
    #include "CDXGraph.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    ////////////////////////////////////////////////////////////////////////////////
    CDXGraph::CDXGraph()
    {
    	mGraph        = NULL;
    	mMediaControl = NULL;
    	mEvent        = NULL;
    	mBasicVideo   = NULL;
    	mBasicAudio   = NULL;
    	mVideoWindow  = NULL;
    	mSeeking      = NULL;
    
    	mObjectTableEntry = 0;
    }
    
    CDXGraph::~CDXGraph()
    {
    	Release();
    }
    
    bool CDXGraph::Create(void)
    {
    	if (!mGraph)
    	{
    		if (SUCCEEDED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
    			IID_IGraphBuilder, (void **)&mGraph)))
    		{
    			AddToObjectTable();
    
    			return QueryInterfaces();
    		}
    		mGraph = 0;
    	}
    	return false;
    }
    
    bool CDXGraph::QueryInterfaces(void)
    {
    	if (mGraph)
    	{
    		HRESULT hr = NOERROR;
    		hr |= mGraph->QueryInterface(IID_IMediaControl, (void **)&mMediaControl);
    		hr |= mGraph->QueryInterface(IID_IMediaEventEx, (void **)&mEvent);
    		hr |= mGraph->QueryInterface(IID_IBasicVideo, (void **)&mBasicVideo);
    		hr |= mGraph->QueryInterface(IID_IBasicAudio, (void **)&mBasicAudio);
    		hr |= mGraph->QueryInterface(IID_IVideoWindow, (void **)&mVideoWindow);
    		hr |= mGraph->QueryInterface(IID_IMediaSeeking, (void **)&mSeeking);
    		if (mSeeking)
    		{
    			mSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
    		}
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    void CDXGraph::Release(void)
    {
    	if (mSeeking)
    	{
    		mSeeking->Release();
    		mSeeking = NULL;
    	}
    	if (mMediaControl)
    	{
    		mMediaControl->Release();
    		mMediaControl = NULL;
    	}
    	if (mEvent)
    	{
    		mEvent->Release();
    		mEvent = NULL;
    	}
    	if (mBasicVideo)
    	{
    		mBasicVideo->Release();
    		mBasicVideo = NULL;
    	}
    	if (mBasicAudio)
    	{
    		mBasicAudio->Release();
    		mBasicAudio = NULL;
    	}
    	if (mVideoWindow)
    	{
    		mVideoWindow->put_Visible(OAFALSE);
    		mVideoWindow->put_MessageDrain((OAHWND)NULL);
    		mVideoWindow->put_Owner(OAHWND(0));
    		mVideoWindow->Release();
    		mVideoWindow = NULL;
    	}
    	RemoveFromObjectTable();
    	if (mGraph) 
    	{
    		int nn=mGraph->Release(); 
    		ASSERT(nn==0);
    		mGraph = NULL;
    	}
    }
    
    bool CDXGraph::Attach(IGraphBuilder * inGraphBuilder)
    {
    	Release();
    
    	if (inGraphBuilder)
    	{
    		inGraphBuilder->AddRef();
    		mGraph = inGraphBuilder;
    
    		AddToObjectTable();
    		return QueryInterfaces();
    	}
    	return true;
    }
    
    IGraphBuilder * CDXGraph::GetGraph(void)
    {
    	return mGraph;
    }
    
    IMediaEventEx * CDXGraph::GetEventHandle(void)
    {
    	return mEvent;
    }
    
    // Connect filter from the upstream output pin to the downstream input pin
    bool CDXGraph::ConnectFilters(IPin * inOutputPin, IPin * inInputPin, 
    							  const AM_MEDIA_TYPE * inMediaType)
    {
    	if (mGraph && inOutputPin && inInputPin)
    	{
    		HRESULT hr = mGraph->ConnectDirect(inOutputPin, inInputPin, inMediaType);
    		return SUCCEEDED(hr) ? true : false;
    	}
    	return false;
    }
    
    void CDXGraph::DisconnectFilters(IPin * inOutputPin)
    {
    	if (mGraph && inOutputPin)
    	{
    		HRESULT hr = mGraph->Disconnect(inOutputPin);
    	}
    }
    
    bool CDXGraph::SetDisplayWindow(HWND inWindow)
    {	
    	if (mVideoWindow)
    	{
    	//	long lVisible;
    	//	mVideoWindow->get_Visible(&lVisible);
    		// Hide the video window first
    		mVideoWindow->put_Visible(OAFALSE);
    		mVideoWindow->put_Owner((OAHWND)inWindow);
    
    		RECT windowRect;
    		::GetClientRect(inWindow, &windowRect);
    		mVideoWindow->put_Left(0);
    		mVideoWindow->put_Top(0);
    		mVideoWindow->put_Width(windowRect.right - windowRect.left);
    		mVideoWindow->put_Height(windowRect.bottom - windowRect.top);
    		mVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
    
    		mVideoWindow->put_MessageDrain((OAHWND) inWindow);
    		// Restore the video window
    		if (inWindow != NULL)
    		{
    		//	mVideoWindow->put_Visible(lVisible);
    			mVideoWindow->put_Visible(OATRUE);
    		}
    		else
    		{
    			mVideoWindow->put_Visible(OAFALSE);
    		}
    		return true;
    	}
    	return false;
    }
    
    bool CDXGraph::ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight)
    {
    	if (mVideoWindow)
    	{
    		long lVisible = OATRUE;
    		mVideoWindow->get_Visible(&lVisible);
    		// Hide the video window first
    		mVideoWindow->put_Visible(OAFALSE);
    
    		mVideoWindow->put_Left(inLeft);
    		mVideoWindow->put_Top(inTop);
    		mVideoWindow->put_Width(inWidth);
    		mVideoWindow->put_Height(inHeight);
    	
    		// Restore the video window
    		mVideoWindow->put_Visible(lVisible);
    		return true;
    	}
    	return false;
    }
    
    bool CDXGraph::SetNotifyWindow(HWND inWindow)
    {
    	if (mEvent)
    	{
    		mEvent->SetNotifyWindow((OAHWND)inWindow, WM_GRAPHNOTIFY, 0);
    		return true;
    	}
    	return false;
    }
    
    void CDXGraph::HandleEvent(WPARAM inWParam, LPARAM inLParam)
    {
    	if (mEvent)
    	{
    		LONG eventCode = 0, eventParam1 = 0, eventParam2 = 0;
    		while (SUCCEEDED(mEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
    		{
    			mEvent->FreeEventParams(eventCode, eventParam1, eventParam2);
    			switch (eventCode)
    			{
    			case EC_COMPLETE:
    				break;
    
    			case EC_USERABORT:
    			case EC_ERRORABORT:
    				break;
    
    			default:
    				break;
    			}
    		}
    	}
    }
    
    bool CDXGraph::Run(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		if (!IsRunning())
    		{
    			if (SUCCEEDED(mMediaControl->Run()))
    			{
    				return true;
    			}
    		}
    		else
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::Stop(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		if (!IsStopped())
    		{	
    			if (SUCCEEDED(mMediaControl->Stop()))
    			{
    				return true;
    			}
    		}
    		else
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::Pause(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		if (!IsPaused())
    		{	
    			if (SUCCEEDED(mMediaControl->Pause()))
    			{
    				return true;
    			}
    		}
    		else
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::IsRunning(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		OAFilterState state = State_Stopped;
    		if (SUCCEEDED(mMediaControl->GetState(10, &state)))
    		{
    			return state == State_Running;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::IsStopped(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		OAFilterState state = State_Stopped;
    		if (SUCCEEDED(mMediaControl->GetState(10, &state)))
    		{
    			return state == State_Stopped;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::IsPaused(void)
    {
    	if (mGraph && mMediaControl)
    	{
    		OAFilterState state = State_Stopped;
    		if (SUCCEEDED(mMediaControl->GetState(10, &state)))
    		{
    			return state == State_Paused;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::SetFullScreen(BOOL inEnabled)
    {
    	if (mVideoWindow)
    	{
    		HRESULT hr = mVideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE);
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    bool CDXGraph::GetFullScreen(void)
    {
    	if (mVideoWindow)
    	{
    		long  fullScreenMode = OAFALSE;
    		mVideoWindow->get_FullScreenMode(&fullScreenMode);
    		return (fullScreenMode == OATRUE);
    	}
    	return false;
    }
    
    // IMediaSeeking features
    bool CDXGraph::GetCurrentPosition(double * outPosition)
    {
    	if (mSeeking)
    	{
    		__int64 position = 0;
    		if (SUCCEEDED(mSeeking->GetCurrentPosition(&position)))
    		{
    			*outPosition = ((double)position) / 10000000.;
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::GetStopPosition(double * outPosition)
    {
    	if (mSeeking)
    	{
    		__int64 position = 0;
    		if (SUCCEEDED(mSeeking->GetStopPosition(&position)))
    		{
    			*outPosition = ((double)position) / 10000000.;
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::SetCurrentPosition(double inPosition)
    {
    	if (mSeeking)
    	{
    		__int64 one = 10000000;
    		__int64 position = (__int64)(one * inPosition);
    		HRESULT hr = mSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
    			0, AM_SEEKING_NoPositioning);
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    bool CDXGraph::SetStartStopPosition(double inStart, double inStop)
    {
    	if (mSeeking)
    	{
    		__int64 one = 10000000;
    		__int64 startPos = (__int64)(one * inStart);
    		__int64 stopPos  = (__int64)(one * inStop);
    		HRESULT hr = mSeeking->SetPositions(&startPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 
    			&stopPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame);
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    bool CDXGraph::GetDuration(double * outDuration)
    {
    	if (mSeeking)
    	{
    		__int64 length = 0;
    		if (SUCCEEDED(mSeeking->GetDuration(&length)))
    		{
    			*outDuration = ((double)length) / 10000000.;
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::SetPlaybackRate(double inRate)
    {
    	if (mSeeking)
    	{
    		if (SUCCEEDED(mSeeking->SetRate(inRate)))
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    // Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
    bool CDXGraph::SetAudioVolume(long inVolume)
    {
    	if (mBasicAudio)
    	{
    		HRESULT hr = mBasicAudio->put_Volume(inVolume);
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    long CDXGraph::GetAudioVolume(void)
    {
    	long volume = 0;
    	if (mBasicAudio)
    	{
    		mBasicAudio->get_Volume(&volume);
    	}
    	return volume;
    }
    
    // Attention: range from -10000(left) to 10000(right), and 0 is both.
    bool CDXGraph::SetAudioBalance(long inBalance)
    {
    	if (mBasicAudio)
    	{
    		HRESULT hr = mBasicAudio->put_Balance(inBalance);
    		return SUCCEEDED(hr);
    	}
    	return false;
    }
    
    long CDXGraph::GetAudioBalance(void)
    {
    	long balance = 0;
    	if (mBasicAudio)
    	{
    		mBasicAudio->get_Balance(&balance);
    	}
    	return balance;
    }
    
    bool CDXGraph::RenderFile(const char * inFile)
    {
    	if (mGraph)
    	{
    		WCHAR    szFilePath[MAX_PATH];
    		MultiByteToWideChar(CP_ACP, 0, inFile, -1, szFilePath, MAX_PATH);
    		if (SUCCEEDED(mGraph->RenderFile(szFilePath, NULL)))
    		{
    			return true;
    		}
    	}
    	return false;
    }
    
    bool CDXGraph::SnapshotBitmap(const char * outFile)
    {
    	if (mBasicVideo)
    	{
    		long bitmapSize = 0;
    		if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
    		{
    			bool pass = false;
    			unsigned char * buffer = new unsigned char[bitmapSize];
    			if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
    			{
    				BITMAPFILEHEADER	hdr;
    				LPBITMAPINFOHEADER	lpbi;
    
    				lpbi = (LPBITMAPINFOHEADER)buffer;
    
    				int nColors = 1 << lpbi->biBitCount;
    				if (nColors > 256)
    					nColors = 0;
    
    				hdr.bfType		= ((WORD) ('M' << 8) | 'B');	//always is "BM"
    				hdr.bfSize		= bitmapSize + sizeof( hdr );
    				hdr.bfReserved1 	= 0;
    				hdr.bfReserved2 	= 0;
    				hdr.bfOffBits		= (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize +
    						nColors * sizeof(RGBQUAD));
    
    				CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
    				bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
    				bitmapFile.Write(buffer, bitmapSize);
    				bitmapFile.Close();
    				pass = true;
    			}
    			delete [] buffer;
    			return pass;
    		}
    	}
    	return false;
    }
    
    
    
    //////////////////////// For GraphEdit Dubug purpose /////////////////////////////
    void CDXGraph::AddToObjectTable(void)
    {
    	IMoniker * pMoniker = 0;
        IRunningObjectTable * objectTable = 0;
        if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
    	{
    		WCHAR wsz[256];
    		wsprintfW(wsz, L"FilterGraph %08p pid %08x", (DWORD_PTR)mGraph, GetCurrentProcessId());
    		HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
    		if (SUCCEEDED(hr)) 
    		{
    			hr = objectTable->Register(0, mGraph, pMoniker, &mObjectTableEntry);
    			pMoniker->Release();
    		}
    		objectTable->Release();
    	}
    }
    
    void CDXGraph::RemoveFromObjectTable(void)
    {
    	IRunningObjectTable * objectTable = 0;
        if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) 
    	{
            objectTable->Revoke(mObjectTableEntry);
            objectTable->Release();
    		mObjectTableEntry = 0;
        }
    }
    
    
    
    这是使用的函数
    void CSimplePlayerDlg::OnButtonOpen() 
    {
    	// TODO: Add your control notification handler code here
    	CString    strFilter = "AVI File (*.avi)|*.avi|";
    	strFilter += "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|";
    	strFilter += "Mp3 File (*.mp3)|*.mp3|";
    	strFilter += "Wave File (*.wav)|*.wav|";
    	strFilter += "All Files (*.*)|*.*|";
    	CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, 
    		strFilter, this);
    	if (IDOK == dlgOpen.DoModal()) 
    	{
    		mSourceFile = dlgOpen.GetPathName();
    		// Rebuild the file playback filter graph
    		CreateGraph();
    	}
    }
    
    void CSimplePlayerDlg::CreateGraph(void)
    {
    	DestroyGraph();
    
    	mFilterGraph = new CDXGraph();
    	if (mFilterGraph->Create())
    	{
    		// Render the source clip
    		mFilterGraph->RenderFile(mSourceFile);
    
    		////////// Add Samle render filter ////////
    		AddSampleRenderFilter();
    		////////////////////////////////////////////
    
    		// Set video window and notification window
    		mFilterGraph->SetDisplayWindow(mVideoWindow.GetSafeHwnd());
    		mFilterGraph->SetNotifyWindow(this->GetSafeHwnd());
    		// Show the first frame
    		mFilterGraph->Pause();
    	}
    }
    
    //CLSID_SampleRenderer是DxSDK例子中的Filter,我注册了
    void CSimplePlayerDlg::AddSampleRenderFilter(void)
    {
    	// Create sample render overlay filter
    	CComPtr<IBaseFilter> pFilter = NULL;
    
    
    		HRESULT hr = CoCreateInstance(CLSID_SampleRenderer, NULL, 
    			CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void **)&pFilter);
    		if (SUCCEEDED(hr))
    		{
    			IPin * pOut = FindPin_ConnectedToVideoRenderer();//这个函数是去掉缺省的Video Render,找到decoder filter的输出pin
    
    		
    		// Add to filter graph
    		hr=mFilterGraph->GetGraph()->AddFilter(pFilter, L"Sample Render");
    
    
    		// Connect renderfilter
    		
    		CComPtr<IPin>           pFTRPinIn;      // Sample Renderer Input Pin
    	
    		if (FAILED(hr = pFilter->FindPin(L"In", &pFTRPinIn)))
    		{
    			return;
    		} 
    		BOOL pass = mFilterGraph->ConnectFilters(pOut, pFTRPinIn);
    
    		if (!pass)
    		{
    			// Build the original filter graph
    			mFilterGraph->GetGraph()->Render(pOut);
    			AfxMessageBox("Sample Render filter connection failed!");
                                          return;
    		}
    	}
    }
    
    有没有牛人能帮我看看到底是啥问题,有没有解决方法?????????
    2011年11月4日 1:41
  • 你也可以一步一步调试啊 F11或者F10 看看有什么地方开始产生的

    2011年11月8日 9:12
  • 你用debug模式中断下,在调试的Thread框看看多出来的4,5个线程是哪的,要是系统的就不用管了,要是你自己代码里的,可以从该窗口跳到对应线程代码部分,看看为什么要启动那么多线程
    0xBAADF00D
    2011年11月14日 16:23
    版主
  • 非常感谢各位的回复,我调试时发现是Graph Connect时产生的,应该是系统产生的或Decoder产生的,decoder用的是ffdshow,打开的文件是mpeg2文件,关键是多次打开文件产生的线程数太多,会导致程序崩溃啊!我的程序是不允许关机的。

    • 已标记为答案 Rob Pan 2011年11月16日 8:47
    2011年11月16日 1:28