上一篇文章分析了Media Player Classic - HC(mpc-hc)的源代码中的CFGManager类的RenderFile函数:
Media Player Classic - HC 源代码分析 8:RenderFile函数详细分析(CFGManager)
这一篇文章我们全面了解一下CFGManager类,这个类从IFilterGraph2接口继承,是DirectShow的Filter Graph Manager类。负责管理整个Graph链中的Filter。源码声明如下:
class CFGManager
: public CUnknown
, public IGraphBuilder2
, public IGraphBuilderDeadEnd
, public CCritSec
{
public:
struct path_t {
CLSID clsid;
CString filter, pin;
};
class CStreamPath : public CAtlList<path_t>
{
public:
void Append(IBaseFilter* pBF, IPin* pPin);
bool Compare(const CStreamPath& path);
};
class CStreamDeadEnd : public CStreamPath
{
public:
CAtlList<CMediaType> mts;
};
private:
CComPtr<IUnknown> m_pUnkInner;
DWORD m_dwRegister;
CStreamPath m_streampath;
CAutoPtrArray<CStreamDeadEnd> m_deadends;
protected:
CComPtr<IFilterMapper2> m_pFM;
CInterfaceList<IUnknown, &IID_IUnknown> m_pUnks;
CAtlList<CFGFilter*> m_source, m_transform, m_override;
static bool CheckBytes(HANDLE hFile, CString chkbytes);
HRESULT EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl);
HRESULT AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF);
HRESULT Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender);
// IFilterGraph
STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName);
STDMETHODIMP RemoveFilter(IBaseFilter* pFilter);
STDMETHODIMP EnumFilters(IEnumFilters** ppEnum);
STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter);
STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt);
STDMETHODIMP Reconnect(IPin* ppin);
STDMETHODIMP Disconnect(IPin* ppin);
STDMETHODIMP SetDefaultSyncSource();
// IGraphBuilder
STDMETHODIMP Connect(IPin* pPinOut, IPin* pPinIn);
STDMETHODIMP Render(IPin* pPinOut);
STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList);
STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter);
STDMETHODIMP SetLogFile(DWORD_PTR hFile);
STDMETHODIMP Abort();
STDMETHODIMP ShouldOperationContinue();
// IFilterGraph2
STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter);
STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt);
STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext);
// IGraphBuilder2
STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir);
STDMETHODIMP IsPinConnected(IPin* pPin);
STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn);
STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF);
STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt);
STDMETHODIMP NukeDownstream(IUnknown* pUnk);
STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove);
STDMETHODIMP AddToROT();
STDMETHODIMP RemoveFromROT();
// IGraphBuilderDeadEnd
STDMETHODIMP_(size_t) GetCount();
STDMETHODIMP GetDeadEnd(int iIndex, CAtlList<CStringW>& path, CAtlList<CMediaType>& mts);
public:
CFGManager(LPCTSTR pName, LPUNKNOWN pUnk);
virtual ~CFGManager();
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
};
从上面类声明中我们可以看到CFGManager继承自IGraphBuilder2接口,而IGraphBuilder2接口刚好是从IFilterGraph2接口继承的。
另外CComPtr<IUnknown> m_pUnkInner这个成员变量很重要,CFGManager将所有IFilterGraph2接口函数的调用都转接给这个对象。m_pUnkInner 为DirectShow现实的Filter Graph Manager基类对象。这个对象在CFGManager构造函数中创建,我们看一下具体创建代码:
CFGManager::CFGManager(LPCTSTR pName, LPUNKNOWN pUnk)
: CUnknown(pName, pUnk)
, m_dwRegister(0)
{
m_pUnkInner.CoCreateInstance(CLSID_FilterGraph, GetOwner());
m_pFM.CoCreateInstance(CLSID_FilterMapper2);
}
我们再看一下CFGManager类使如何将IFilterGraph2接口的调用转接给m_pUnkInner对象的。
CFGManager类的几个函数实现就能看出,源码如下:
STDMETHODIMP CFGManager::AddFilter(IBaseFilter* pFilter, LPCWSTR pName)
{
if (!m_pUnkInner) {
return E_UNEXPECTED;
}
CAutoLock cAutoLock(this);
HRESULT hr;
if (FAILED(hr = CComQIPtr<IFilterGraph2>(m_pUnkInner)->AddFilter(pFilter, pName))) {
return hr;
}
// TODO
hr = pFilter->JoinFilterGraph(nullptr, nullptr);
hr = pFilter->JoinFilterGraph(this, pName);
return hr;
}
STDMETHODIMP CFGManager::RemoveFilter(IBaseFilter* pFilter)
{
if (!m_pUnkInner) {
return E_UNEXPECTED;
}
CAutoLock cAutoLock(this);
return CComQIPtr<IFilterGraph2>(m_pUnkInner)->RemoveFilter(pFilter);
}
STDMETHODIMP CFGManager::Reconnect(IPin* ppin)
{
if (!m_pUnkInner) {
return E_UNEXPECTED;
}
CAutoLock cAutoLock(this);
return CComQIPtr<IFilterGraph2>(m_pUnkInner)->Reconnect(ppin);
}
STDMETHODIMP CFGManager::Disconnect(IPin* ppin)
{
if (!m_pUnkInner) {
return E_UNEXPECTED;
}
CAutoLock cAutoLock(this);
return CComQIPtr<IFilterGraph2>(m_pUnkInner)->Disconnect(ppin);
}
从以上几个函数我们可以看出,CFGManger将IFilterGraph2接口函数全部转接给m_pUnkInner 对象的同名函数。
总结:由上面分析可知,CFGManger类只是对DirectShow已经实现的Filter Graph Manager的一种包装,具体的工作还是由DirectShow自己处理。