|
|
DirectShow学习(二)CBasePin类、CBaseOutputPin类和CBaseInputPin类源代码解析 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
- 预备知识 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 – 调用函数 DisconnectInternal Connect/ReceiveConnection – 见上面条目。 其它的简单接口函数 ConnectionMediaType、QueryPinInfo、QueryDirection等。
- CBasePin中未实现IPin/IQualityControl的函数
直接设置为NOERROR的部分函数: EndOfStream 直接设置为IMPL错误码的部分函数: QueryInternalConnections Notify[IQualityControl接口] 完全没有实现的部分函数: BeginFlush EndFlush
- 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_UNEXPECTED STDMETHODIMP 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的代码分析

|
|
相关文章:相关软件: |
|