现在的位置: 首页 > 综合 > 正文

【视频处理工程】4、DirectShow基本开发过程(二)

2014年09月05日 ⁄ 综合 ⁄ 共 2587字 ⁄ 字号 评论关闭

前文讲了一些开发DirectShow的基本配置方法以及一些基本的开发过程,如如何创造一个filter并加入filter graph中。这里继续上文的步骤讨论如何得到filter的pin,以及如何连接两个filter。

1、如何获取filter的pin

获取filter上的pin是连接filter之前必须的一步。主要思路是枚举filter上所有的pin,并通过QueryDirection检查pin的方向,以及通过connectedTo检查pin是否已经被链接。方法如下:

HRESULT GetUnconectedPin( IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin )
{
	*ppPin = 0;
	IEnumPins *pEnum = 0;
	IPin *pPin = 0;

	HRESULT hr = pFilter->EnumPins(&pEnum);
	if (FAILED(hr))
	{
		return hr;
	}
	hr = pEnum->Reset();
	while (pEnum->Next(1,&pPin,NULL) == S_OK)
	{
		PIN_DIRECTION ThisPinDirection;
		pPin->QueryDirection(&ThisPinDirection);
		if (ThisPinDirection == PinDir)
		{
			IPin *pTemp = 0;
			hr = pPin->ConnectedTo(&pTemp);
			if (SUCCEEDED(hr))
			{
				//当前pin已经连接,无效;
				pTemp->Release();
			} 
			else
			{
				pEnum->Release();
				*ppPin = pPin;
				return S_OK;
			}			
		}
		pPin->Release();
	}
	pEnum->Release();
	return E_FAIL;
}

需要注意的是,有些filter想要检索出其中的pin是有条件的,比如上文中提到的lav splitter source filter,只有在加载了视频文件之后,才可以检索出其pin。


2、连接两个filter

两个filter之间由上一级的输出pin连接到下一级的输入pin,实现的方法有IFilterGraph::ConnectDirect和IGraphBuilder::Connect实现,方法如下:

HRESULT ConnectFilters( IGraphBuilder *pGraph, IPin *pOut, IBaseFilter *pDest )
{
	if ((pGraph == NULL)||(pOut == NULL)||(pDest == NULL))
		return E_POINTER;

#ifdef _DEBUG
	PIN_DIRECTION PinDir;
	pOut->QueryDirection(&PinDir);
	_ASSERT(PinDir == PINDIR_OUTPUT);
#endif // _DEBUG

	//得到下级filter的输入pin
	IPin *pIn = 0;
	HRESULT hr = GetUnconectedPin(pDest,PINDIR_INPUT,&pIn);
	if (FAILED(hr))
		return hr;

	hr = pGraph->Connect(pOut,pIn);
	pIn->Release();
	return hr;
}

HRESULT ConnectFilters( IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest)
{
	if ((pGraph == NULL)||(pOut == NULL)||(pDest == NULL))
		return E_POINTER;

	IPin *pOut = 0;
	HRESULT hr = GetUnconectedPin(pSrc,PINDIR_OUTPUT,&pOut);
	if (FAILED(hr))
		return hr;
	hr = ConnectFilters(pGraph,pOut,pDest);
	pOut->Release();
	return hr;
}

下面我们依样画葫芦,讲lavvideo.ax和lavaudio.ax这两个组件进行注册,并利用相同的方法添加到filter graph中,并与lav splitter source进行连接,代码如下:

int _tmain(int argc, _TCHAR* argv[])
{
//......
 	hr = AddFilterByCLSID(pGraph,CLSID_LavSplitter_Source,L"Lav Splitter Source",&pLavSplitterSource);
	hr = pLavSplitterSource->QueryInterface(IID_IFileSourceFilter,(void **)&pFileSourceFilter);
	hr = pFileSourceFilter->Load(fileName,NULL);//必须loadfile后才能检索pin

	hr = AddFilterByCLSID(pGraph,CLSID_LavVideoDecoder,L"Lav Video Decoder",&pLavVideoDecoder);
	hr = ConnectFilters(pGraph,pLavSplitterSource,pLavVideoDecoder);

	hr = AddFilterByCLSID(pGraph,CLSID_LavAudioDecoder,L"Lav Audio Decoder",&pLavAudioDecoder);
	hr = ConnectFilters(pGraph,pLavSplitterSource,pLavAudioDecoder);
//......
}

上述代码段中CLSID_LavVideoDecoder和CLSID_LavAudioDecoder都是在GraphStudioNext中查找CLSID后定义在头文件中的,分别表示lavfilter的视频和音频解码器组件。用GraphStudioNext查看该进程的Filter Graph如下图所示:


由上图可见,视频和音频解码器分别已经链接在了source filter的视频和音频输出接口上,不过至于能不能正常使用现在还不得而知。我们的下一个目标就是通过用代码调用lav filter组件的方式手工播放这部电影。

抱歉!评论已关闭.