预备知识
CMediaType[mtype.h/mtype.cpp]
CMediaType从_AMMediaType继承,是一个在DirectShow中非常有用的Helper Class。它提供了一些常用的辅助函数来操作AMMediaType结构。另外,还提供了几个很常用的全局函数
CreateMediaType、
DeleteMediaType、
CopyMediaType和
FreeMediaType以及
CreateAudioMediaType。
CBasePin类
[amfilter.h/amfilter.cpp]
BasePin继承了接口IPin, IPin的接口定义如下
IPin : public IUnknown
{
public:
// 连接两个Pin,主动连接InputPin
virtual HRESULT STDMETHODCALLTYPE Connect(
/* [in] */ IPin *pReceivePin,
/* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
// 连接两个Pin,被动连接
virtual HRESULT STDMETHODCALLTYPE ReceiveConnection(
/* [in] */ IPin *pConnector,
/* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
// 断开连接,只能在Stop状态下断开
virtual HRESULT STDMETHODCALLTYPE Disconnect( void) = 0;
// 得到连接的Pin的接口,
成功返回连接的Pin被调用AddRef
virtual HRESULT STDMETHODCALLTYPE ConnectedTo(
/* [out] */ IPin **pPin) = 0;
// 得到连接状态下的MediaType
virtual HRESULT STDMETHODCALLTYPE ConnectionMediaType(
/* [out] */ AM_MEDIA_TYPE *pmt) = 0;
// 得到Pin的信息,填充PIN_INFO结构
virtual HRESULT STDMETHODCALLTYPE QueryPinInfo(
/* [out] */ PIN_INFO *pInfo) = 0;
// 得到Pin的连接方向
virtual HRESULT STDMETHODCALLTYPE QueryDirection(
/* [out] */ PIN_DIRECTION *pPinDir) = 0;
// 得到ID -
其实是Pin中的name
virtual HRESULT STDMETHODCALLTYPE QueryId(
/* [out] */ LPWSTR *Id) = 0;
// Determines whether the pin accepts a specified media type.
virtual HRESULT STDMETHODCALLTYPE QueryAccept(
/* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
// Enumerates the pin's preferred media types.
virtual HRESULT STDMETHODCALLTYPE EnumMediaTypes(
/* [out] */ IEnumMediaTypes **ppEnum) = 0;
// Retrieves the pins that are connected internally to this pin (within the filter).
virtual HRESULT STDMETHODCALLTYPE QueryInternalConnections(
/* [out] */ IPin **apPin,
/* [out][in] */ ULONG *nPin) = 0;
// Notifies the pin that no
additional data is expected
virtual HRESULT STDMETHODCALLTYPE EndOfStream( void) = 0;
// Begins / End a flush operation.
virtual HRESULT STDMETHODCALLTYPE BeginFlush( void) = 0;
virtual HRESULT STDMETHODCALLTYPE EndFlush( void) = 0;
// Notifies the pin that media samples received after this call are grouped as a segment.
virtual HRESULT STDMETHODCALLTYPE NewSegment(
/* [in] */ REFERENCE_TIME tStart,
/* [in] */ REFERENCE_TIME tStop,
/* [in] */ double dRate) = 0;
};
CBasePin同时继承了接口IQualityControl, IQualityControl的定义如下
IQualityControl : public IUnknown
{
public:
// Notifies the recipient that a quality change is requested.
virtual HRESULT STDMETHODCALLTYPE Notify(
/* [in] */ IBaseFilter *pSelf,
/* [in] */ Quality q) = 0;
virtual HRESULT STDMETHODCALLTYPE SetSink(
/* [in] */ IQualityControl *piqc) = 0;
};
CBasePin类的具体实现伪代码
派生自
CUnknown,
IPin,
IQualityControl成员变量:
WCHAR * m_pName; // This pin's name
IPin *m_Connected; // Pin we have connected to
PIN_DIRECTION m_dir; // Direction of this pin
CCritSec *m_pLock; // Object we use for locking
bool m_bRunTimeError; // Run time error generated
bool m_bCanReconnectWhenActive; // OK to reconnect when active
bool m_bTryMyTypesFirst; // When connecting enumerate
CBaseFilter *m_pFilter; // Filter we were created by
IQualityControl *m_pQSink; // Target for Quality messages
LONG m_TypeVersion; // Holds current type version
CMediaType m_mt; // Media type of connection
CRefTime m_tStart; // time from NewSegment call
CRefTime m_tStop; // time from NewSegment
double m_dRate; // rate from NewSegment
其中m_bRunTimeError默认为FALSE,m_pQSink默认为NULL,m_TypeVersion默认为1,m_tStart为空,m_tStop为MAX_TIME,m_bCanReconnectWhenActive和m_bTryMyTypesFirst都为FALSE,m_dRate为1.0。
构造函数部分:
Constructor:
CBasePin(
TCHAR *pObjectName, // Object description
CBaseFilter *pFilter, // Owning filter who knows about pins
CCritSec *pLock, // Object who implements the lock
HRESULT *phr, // General OLE return code
LPCWSTR pName, // Pin name for us
PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT
Pin之间的链接过程[详细Code讲解见
陆其明《DirectShow开发指南》第二章的讲解],通过调用IPin的
Connect->
AgreeMediaType(CBasePin的Protected函数)->
TryMediaTypes(CBasePin的Protected函数)->
AttempConnect(CBasePin的Protected函数)。
其中AttempConnect函数会首先调用
CheckConnect(CBasePin的Virtual函数),然后调用
CheckMediaType(CBasePin的Virtual函数),如果MediaType接受,则调用Receive Pin上的
ReceiveConnection(IPin接口函数)函数,如果成功则调用
CompleteConnection(CBasePin的virtual函数)。
CBasePin中的新增加virtual函数和解释以及虚拟代码:
virtual LONG GetMediaTypeVersion();{return m_TypeVersion;}
// switch the pin to active (paused or running) mode not an error to call this if already active,
virtual HRESULT Active(void);{return NOERROR;}
// switch the pin to inactive state - may already be inactive
virtual HRESULT Inactive(void);{ return NOERROR; }
// Notify of Run() from filter,
virtual HRESULT Run(REFERENCE_TIME tStart);{ return NOERROR; }
// check if the pin can support this specific proposed type and forma
virtual HRESULT CheckMediaType(const CMediaType *)
PURE;
必须Override// set the connection to use this format (previously agreed)
virtual HRESULT SetMediaType(const CMediaType *);{ HRESULT hr = m_mt.Set(*pmt);}
// check that the connection is ok before verifying it can be overridden eg to check what interfaces will be supported.
virtual HRESULT CheckConnect(IPin *); {
CBasePin中只检查了Pin的方向和当前方向是否一致}
// Set and release resources required for a connection
virtual HRESULT BreakConnect();{return NOERROR;}
virtual HRESULT CompleteConnect(IPin *pReceivePin);
// returns the
preferred formats for a pin
virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
必须Override
CBasePin实现IPin的函数
QueryAccept - 直接调用
CheckMediaType,并将结果返回
EnumMediaTypes - 通过辅助类
CEnumMediaTypes实现MediaType的Enum.
NewSegment – 只是简单设置参数后直接返回NOERROR
Disconnect – 调用函数
DisconnectInternalConnect/
ReceiveConnection – 见上面条目。
其它的简单接口函数
ConnectionMediaType、
QueryPinInfo、
QueryDirection等。
CBasePin中未实现IPin/IQualityControl的函数
直接设置为
NOERROR的部分函数:
EndOfStream直接设置为
IMPL错误码的部分函数:
QueryInternalConnectionsNotify[IQualityControl接口]
完全没有实现的部分函数:
BeginFlushEndFlush
CBaseOutputPin 类
[amfilter.h/amfilter.cpp]
CBaseOutputPin具体实现伪代码
派生自
CBasePin变量部分(均初始化为NULL):
IMemAllocator *m_pAllocator; // Memory allocator
IMemInputPin *m_pInputPin; // interface on the downstreaminput pin
新增加的virtual函数:
// negotiate the allocator and its buffer size/count and other properties
// Calls DecideBufferSize to set properties
virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
{
// 调用
pPin->GetAllocatorRequirements. 得到Input Pin的Prop.
// 调用
pPin->GetAllocator判断pPin是否以及存在Allocator,否则自己创建并初始化(
InitAlloc)
// 调用
DecideBufferSize 来得到需要的大小
// 调用
pPin->NotifyAllocator让Input Pin得到更新的Allocator
}
// override this to set the buffer size and count. Return an error
virtual HRESULT DecideBufferSize(
IMemAllocator * pAlloc,
ALLOCATOR_PROPERTIES * ppropInputRequest
)
PURE;
// returns an empty sample buffer from the allocator
virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample,
REFERENCE_TIME * pStartTime,
REFERENCE_TIME * pEndTime,
DWORD dwFlags);
{// 调用
m_pAllocator->GetBuffer… }
// deliver a filled-in sample to the connected input pin
// note - you need to release it after calling this. The receiving
virtual HRESULT Deliver(IMediaSample *);{
m_pInputPin->Receive(pSample); }
// override this to control the connection
virtual HRESULT
InitAllocator(IMemAllocator **ppAlloc);{
CreateMemoryAllocator(ppAlloc); }
// called from elsewhere in our filter to pass EOS downstream to our connected input pin
virtual HRESULT DeliverEndOfStream(void);{ m_Connected->EndOfStream(); }
virtual HRESULT DeliverBeginFlush(void);{ m_Connected->BeginFlush(); }
virtual HRESULT DeliverEndFlush(void);{ m_Connected->EndFlush(); }
virtual HRESULT DeliverNewSegment(
REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate);{ m_Connected->NewSegment(…);}
继承的virtual函数或者IPin接口函数:
// Complete connection
virtual HRESULT CompleteConnect(IPin *pReceivePin); {
DecideAllocator() }
// Check connection
HRESULT CheckConnect(IPin *pPin);
{
增加检查输入Pin是否支持IMemInputPin接口,m_pInputPin在这里赋值}
// Break connection
HRESULT BreakConnect();
{
// 调用
m_pAllocator->Decommit()后
释放m_pAllocator并置为空,
//
释放m_pInputPin并置为空}
HRESULT Active(void);{ m_pAllocator->Commit(); }
HRESULT Inactive(void); { m_pAllocator->Decommit();}
// 以下三个函数直接返回
E_UNEXPECTEDSTDMETHODIMP EndOfStream(void);
STDMETHODIMP BeginFlush(void);
STDMETHODIMP EndFlush(void);
IMemInput接口函数:
// Retrieves the memory allocator proposed by this pin.
virtual HRESULT STDMETHODCALLTYPE GetAllocator(
/* [out] */ IMemAllocator **ppAllocator) = 0;
// Specifies an allocator for the connection.
virtual HRESULT STDMETHODCALLTYPE NotifyAllocator(
/* [in] */ IMemAllocator *pAllocator,
/* [in] */ BOOL bReadOnly) = 0;
// Retrieves allocator properties that are requested by the input pin.
virtual HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(
/* [out] */ ALLOCATOR_PROPERTIES *pProps) = 0;
// Receives the next media sample in the stream.
virtual HRESULT STDMETHODCALLTYPE Receive(
/* [in] */ IMediaSample *pSample) = 0;
// Receives multiple samples in the stream.
virtual HRESULT STDMETHODCALLTYPE ReceiveMultiple(
/* [size_is][in] */ IMediaSample **pSamples,
/* [in] */ long nSamples,
/* [out] */ long *nSamplesProcessed) = 0;
// Determines whether calls to the Recive method might block.
virtual HRESULT STDMETHODCALLTYPE ReceiveCanBlock( void) = 0;
CBaseInputPin类
[amfilter.h/amfilter.cpp]
CBaseInputPin具体实现伪代码:
派生自
CBasePin,
IMemInputPin变量部分:
IMemAllocator *m_pAllocator; // Default memory allocator
// Allocator is read only or not
BYTE m_bReadOnly;
// in flushing state (between BeginFlush and EndFlush)
// if TRUE, all Receives are returned with S_FALSE
BYTE m_bFlushing;
// Sample properties - initalized in Receive
AM_SAMPLE2_PROPERTIES m_SampleProps;
INonDelegationUnknown的接口函数:
// 重写该函数是为了支持IMemInputPin接口。
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
具体实现函数:
HRESULT PassNotify(Quality& q);
{
// 如果m_pQSink不为空,直接调用
m_pQSink->Notify(…)
// 否则查询Connect Pin上的IQualityControl借口,对其调用
Notify(…)
}
新增的virtual函数
// Override this for checking whether it's OK to process samples
// Also call this from EndOfStream.
virtual HRESULT CheckStreaming();
{分别判断IsStopped、m_bFlushing和m_bRunTimeError }
IMemInputPin接口函数:
// return the allocator interface that this input pin
// would like the output pin to use
STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
{
// 如果
m_pAllocator为空,则
CreateMemoryAllocator。
// 调用
m_pAllocator->AddRef,返回
m_pAllocator}
// tell the input pin which allocator the output pin is actually going to use.
STDMETHODIMP NotifyAllocator(
IMemAllocator * pAllocator,
BOOL bReadOnly);
{
// 释放当前m_pAllocator,设置
m_pAllocator = pAllocator// 调用
m_pAllocator->AddRef
}
// do something with this media sample
STDMETHODIMP Receive(IMediaSample *pSample);
{
// 首先调用CheckStreaming
// 得出pSample的属性,即填充成员m_SampleProps
// 如果Sample属性未发生变化
(!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED))
// 则直接返回NOERROR,否则调用
CheckMediaType检查是否接受新的MediaType,如果接受
// 返回NOERROR,否则调用
EndOfStream,设置
RuntimeError,并通知Filter
//
m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
}
// do something with these media samples
STDMETHODIMP ReceiveMultiple (
IMediaSample **pSamples,
long nSamples,
long *nSamplesProcessed);
{
// 对每个Sample分别调用Receive函数。
}
// See if Receive() blocks
STDMETHODIMP ReceiveCanBlock();
{
// 如果当前Filter上没有Output Pin,则返回S_OK
// 否则遍历当前Filter上每个Output Pin,得出它们的Connected Input Pin,判断这些
// Connected Input Pin是否支持Block,只要有一个支持,则为S_OK
// 以上条件全不满足时,返回S_FALSE
}
// default implementation returns E_NOTIMPL. Override if you have
// specific alignment or prefix needs, but could use an upstream allocator
STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps);{
E_IMPL}
继承的virtual函数实现
STDMETHODIMP BeginFlush(void);
{仅仅设置m_bFlushing为TRUE.}
STDMETHODIMP EndFlush(void);
{仅仅设置m_bFlushing为FALSE,同时清除m_bRuntimeError。}
HRESULT BreakConnect();
{
// 如果m_pAllocator非空,调用
m_pAllocator->Decommit()// 释放
m_pAllocator->Release并置为空。
}
virtual HRESULT Inactive(void);
{
// 清理m_bRunTimeError和m_bFlushing,返回
m_pAllocator->Decommit().}
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
{这是IQualityControl的接口函数,CBaseInputPin只是简单报错DbgBreak说明未实现}
学习三将侧重于Filter的代码分析
本文地址:http://com.8s8s.com/it/it33006.htm