前文讲了一些开发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; }
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; }
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); //...... }
由上图可见,视频和音频解码器分别已经链接在了source filter的视频和音频输出接口上,不过至于能不能正常使用现在还不得而知。我们的下一个目标就是通过用代码调用lav filter组件的方式手工播放这部电影。