转自http://blog.csdn.net/alvachien/archive/2005/01/24/266353.aspx
DirectShow 学习(六): CTransfromFilter及相关联Pin类的源代码解析
1. CTransformInputPin
类
派生自CBaseInputPin。
a)
成员变量
CTransformFilter
*m_pTransformFilter;
b)
IPin
的接口函数:
STDMETHODIMP QueryId(LPWSTR* Id){ return AMGetWideString(L"In", Id); }
// provide EndOfStream that passes straight downstream
STDMETHODIMP EndOfStream(void);
{
CAutoLock lck(&m_pTransformFilter->m_csReceive);
HRESULT hr = CheckStreaming();
if(S_OK== hr){
hr =m_pTransformFilter->EndOfStream();}
return hr;
}
// passes it to CTransformFilter::BeginFlush
STDMETHODIMP BeginFlush(void);
{
CAutoLock lck(&m_pTransformFilter->m_csFilter);
if(!IsConnected()||
!m_pTransformFilter->m_pOutput->IsConnected()){
return VFW_E_NOT_CONNECTED;}
HRESULT hr = CBaseInputPin::BeginFlush();
return m_pTransformFilter->BeginFlush();
}
// passes it to CTransformFilter::EndFlush
STDMETHODIMP EndFlush(void);
{
CAutoLock lck(&m_pTransformFilter->m_csFilter);
if(!IsConnected()||
!m_pTransformFilter->m_pOutput->IsConnected()){
return VFW_E_NOT_CONNECTED;}
HRESULT hr = m_pTransformFilter->EndFlush();
return CBaseInputPin::EndFlush();
}
STDMETHODIMP NewSegment(
REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate);
{
// Save the values in the pin
CBasePin::NewSegment(tStart, tStop, dRate);
return m_pTransformFilter->NewSegment(tStart, tStop, dRate);
}
c)
IMemInputPin
的接口函数
// here's the next block of data from the stream.
// AddRef it yourself if you need to hold it beyond the end
// of this call.
STDMETHODIMP Receive(IMediaSample* pSample);
{
CAutoLock lck(&m_pTransformFilter->m_csReceive);
// check all is well with the base class
hr = CBaseInputPin::Receive(pSample);
if(S_OK== hr){ hr = m_pTransformFilter->Receive(pSample);}
return hr;
}
d)
从CBasePin和CBaseInputPin继承的函数:
HRESULT CheckConnect(IPin*pPin);
{
HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin);
return CBaseInputPin::CheckConnect(pPin);
}
HRESULT BreakConnect();
{
m_pTransformFilter->BreakConnect(PINDIR_INPUT);
return CBaseInputPin::BreakConnect();
}
HRESULT CompleteConnect(IPin*pReceivePin);
{
HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
return CBaseInputPin::CompleteConnect(pReceivePin);
}
HRESULT CheckMediaType(const CMediaType* mtIn);
{
HRESULT hr = m_pTransformFilter->CheckInputType(pmt);
// if the output pin is still connected, then we have
// to check the transform not just the input format
if((m_pTransformFilter->m_pOutput!= NULL)&&
(m_pTransformFilter->m_pOutput->IsConnected())){
return m_pTransformFilter->CheckTransform(
pmt,
&m_pTransformFilter->m_pOutput->CurrentMediaType());
}else{return hr;}
}
// set the connection media type
HRESULT SetMediaType(const CMediaType* mt);
{
// Set the base class media type (should always succeed)
HRESULT hr = CBasePin::SetMediaType(mtIn);
// check the transform can be done (should always succeed)
ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn)));
return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn);
}
// Check if it's OK to process samples
virtual HRESULT CheckStreaming();
{
// 类似于CBaseInputPin的CheckStreaming函数,只是增加了先检查
// Transform Filter的Output Pin是否连接
}
2.
CTransformOutputPin
类
派生自
CBaseOutputPin
。
a)
成员变量:
CTransformFilter
*m_pTransformFilter;
// implement IMediaPosition by passing upstream
IUnknown* m_pPosition;
b) NonDelegatingQueryInterface
函数
STDMETHODIMP NonDelegatingQueryInterface
(
REFIID
riid,void**ppv)
{
if(riid== IID_IMediaPosition || riid == IID_IMediaSeeking){
// we should have an input pin by now
if(m_pPosition== NULL){
HRESULT hr = CreatePosPassThru(
GetOwner(),FALSE, (IPin*)m_pTransformFilter->m_pInput, &m_pPosition);
return m_pPosition->QueryInterface(riid, ppv);
}else{
return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);}
}
STDAPI CreatePosPassThru(LPUNKNOWN pAgg, BOOL bRenderer, IPin*pPin,
IUnknown **ppPassThru )
{
HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru,
pAgg, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnkSeek );
ISeekingPassThru *pPassThru;
hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru,(void**)&pPassThru);
hr = pPassThru->Init(bRenderer, pPin);
pPassThru->Release();
*ppPassThru= pUnkSeek;
}
c) IPin
的接口函数
STDMETHODIMP QueryId(LPWSTR* Id){ return AMGetWideString(L"Out", Id);}
d) IQualityControl
的接口函数
STDMETHODIMP Notify(IBaseFilter* pSender, Quality q);
{
// First see if we want to handle this ourselves
HRESULT hr = m_pTransformFilter->AlterQuality(q);
if(hr!=S_FALSE){ return hr; // either S_OK or a failure }
return m_pTransformFilter->m_pInput->PassNotify(q);
}
e)
从CBasePin和CBaseInputPin继承的函数:
HRESULT CheckConnect(IPin*pPin);
{
if((m_pTransformFilter->m_pInput->IsConnected()== FALSE)){
return E_UNEXPECTED;
}
HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin);
return CBaseOutputPin::CheckConnect(pPin);
}
HRESULT BreakConnect();
{
m_pTransformFilter->BreakConnect(PINDIR_OUTPUT);
return CBaseOutputPin::BreakConnect();
}
HRESULT CompleteConnect(IPin*pReceivePin);
{
HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
return CBaseOutputPin::CompleteConnect(pReceivePin);
}
// check that we can support this output type
HRESULT CheckMediaType(const CMediaType* mtOut);
{
if((m_pTransformFilter->m_pInput->IsConnected()== FALSE))
{ return E_INVALIDARG;}
return m_pTransformFilter->CheckTransform(
&m_pTransformFilter->m_pInput->CurrentMediaType(),pmtOut);
}
// set the connection media type, called after we have agreed a media type to
// actually set it in which case we run the CheckTransform function to get the
// output format type again
HRESULT SetMediaType(const CMediaType *pmt);
{
hr = CBasePin::SetMediaType(pmtOut);
return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut);
}
// called from CBaseOutputPin during connection to ask for
// the count and size of buffers we need.
HRESULT DecideBufferSize(
IMemAllocator * pAlloc,
ALLOCATOR_PROPERTIES *pProp);
{
return m_pTransformFilter->DecideBufferSize(pAllocator, pProp);
}
// returns the preferred formats for a pin
HRESULT GetMediaType(int iPosition,CMediaType*pMediaType);
{
if(m_pTransformFilter->m_pInput->IsConnected()){
return m_pTransformFilter->GetMediaType(iPosition,pMediaType);
}else{
return VFW_S_NO_MORE_ITEMS;
}
}
3. CTransformFilter
类
派生自CBaseFilter
a)
成员变量
BOOL
m_bEOSDelivered; // have we sent EndOfStream
BOOL m_bSampleSkipped; // Did we just skip a frame
BOOL m_bQualityChanged; // Have we degraded?
// critical section protecting filter state.
CCritSec m_csFilter;
// critical section stopping state changes (ie Stop) while we're
// processing a sample. This critical section is held when processing
// events that occur on the receive thread - Receive() and EndOfStream().
// If you want to hold both m_csReceive and m_csFilter then grab
// m_csFilter FIRST - like CTransformFilter::Stop() does.
CCritSec m_csReceive;
// these hold our input and output pins
CTransformInputPin*m_pInput;
CTransformOutputPin*m_pOutput;
b)
新增的virtual 函数:
// Transform,必须override
virtual HRESULT Transform(IMediaSample* pIn, IMediaSample *pOut);
// check if you can support mtIn,必须override
virtual HRESULT CheckInputType必须override
virtual HRESULT CheckTransform必须override
virtual HRESULT DecideBufferSize必须override
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType)PURE;
// you can also override these if you want to know about streaming
virtual HRESULT StartStreaming();{return NOERROR; }
virtual HRESULT StopStreaming();{return NOERROR;}
// override if you can do anything constructive with quality notifications
virtual HRESULT AlterQuality(Quality q);
{
// Return S_FALSE to mean "pass the note on upstream"
// Return NOERROR (Same as S_OK)
// to mean "I've done something about it, don't pass it on"
return S_FALSE;
}
// override this to know when the media type is actually set
virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
{ return NOERROR;}
// chance to grab extra interfaces on connection
virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin*pPin);{ return NOERROR;}
virtual HRESULT BreakConnect(PIN_DIRECTION dir);{ return NOERROR;}
virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin*pReceivePin);
{ return NOERROR;}
// chance to customize the transform process
virtual HRESULT Receive(IMediaSample*pSample);
{
/* Check for other streams and pass them on */
AM_SAMPLE2_PROPERTIES *const pProps = m_pInput->SampleProps();
if(pProps->dwStreamId!= AM_STREAM_MEDIA){
return m_pOutput->m_pInputPin->Receive(pSample);
}
IMediaSample * pOutSample;
// Set up the output sample
hr = InitializeOutputSample(pSample,&pOutSample);
// have the derived class transform the data
hr = Transform(pSample, pOutSample);
// the Transform() function can return S_FALSE to indicate that the
// sample should not be delivered; we only deliver the sample if it's
// really S_OK (same as NOERROR, of course.)
if(hr== NOERROR){
hr = m_pOutput->m_pInputPin->Receive(pOutSample);
m_bSampleSkipped = FALSE; // last thing no longer dropped
}else{
// S_FALSE returned from Transform is a PRIVATE agreement
// We should return NOERROR from Receive() in this cause because
// returning S_FALSE from Receive() means that this is the end of
// the stream and no more data should be sent.
if(S_FALSE== hr){
// Release the sample before calling notify to avoid
// deadlocks if the sample holds a lock on the system
// such as DirectDraw buffers do
pOutSample->Release();
m_bSampleSkipped = TRUE;
if(!m_bQualityChanged){
NotifyEvent(EC_QUALITY_CHANGE,0,0);
m_bQualityChanged = TRUE;
}
return NOERROR;
}
}
pOutSample->Release();
}
// if you override Receive, you may need to override these three too
virtual HRESULT EndOfStream(void);
{
hr = m_pOutput->DeliverEndOfStream();
}
virtual HRESULT BeginFlush(void);
{
hr= m_pOutput->DeliverBeginFlush();
}
virtual HRESULT EndFlush(void);
{
return m_pOutput->DeliverEndFlush();
}
virtual HRESULT NewSegment(
REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate);
{
return m_pOutput->DeliverNewSegment(tStart, tStop, dRate);
}(
IMemAllocator * pAllocator,
ALLOCATOR_PROPERTIES *pprop) PURE;
// override to suggest OUTPUT pin media types,(const CMediaType* mtIn,const CMediaType* mtOut) PURE;
// call the SetProperties function with appropriate arguments,(const CMediaType* mtIn) PURE;
// check if you can support the transform from this input to this output,
c)
继承CBaseFilter的函数:
virtualint GetPinCount();{return2; }
virtual CBasePin * GetPin(int n);
{
// Create an input pin if necessary
if(m_pInput== NULL){
m_pInput =new CTransformInputPin(NAME("Transform input pin"),
this, // Owner filter
&hr, // Result code
L"XForm In"); // Pin name
m_pOutput =(CTransformOutputPin*)
new CTransformOutputPin(NAME("Transform output pin"),
this, // Owner filter
&hr, // Result code
L"XForm Out"); // Pin name
}
// Return the appropriate pin
if(n==0){ return m_pInput;}
else if(n==1){ return m_pOutput;}
else{ return NULL;}
}
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
{
if(0==lstrcmpW(Id,L"In")){ *ppPin= GetPin(0);}
elseif(0==lstrcmpW(Id,L"Out")){ *ppPin= GetPin(1); }
if(*ppPin){ (*ppPin)->AddRef();}
}
STDMETHODIMP Stop();
{
CAutoLock lck1(&m_csFilter);
if(m_State== State_Stopped){ return NOERROR; }
if(m_pInput== NULL || m_pInput->IsConnected()== FALSE ||
m_pOutput->IsConnected()== FALSE){
m_State = State_Stopped;
m_bEOSDelivered = FALSE;
return NOERROR;
}
// decommit the input pin before locking or we can deadlock
m_pInput->Inactive();
// synchronize with Receive calls
CAutoLock lck2(&m_csReceive);
m_pOutput->Inactive();
// allow a class derived from CTransformFilter
// to know about starting and stopping streaming
HRESULT hr = StopStreaming();
if(SUCCEEDED(hr)){
// complete the state transition
m_State = State_Stopped;
m_bEOSDelivered = FALSE;
}
}
STDMETHODIMP Pause();
{
CAutoLock lck(&m_csFilter);
if(m_State== State_Paused){}
elseif(m_pInput== NULL || m_pInput->IsConnected()== FALSE){
if(m_pOutput&& m_bEOSDelivered == FALSE){
m_pOutput->DeliverEndOfStream();
m_bEOSDelivered = TRUE;
}
m_State = State_Paused; }
elseif(m_pOutput->IsConnected()== FALSE){
m_State = State_Paused;}
else{
if(m_State== State_Stopped){
CAutoLock lck2(&m_csReceive);
hr = StartStreaming();}
if(SUCCEEDED(hr)){ hr = CBaseFilter::Pause();}
}
m_bSampleSkipped = FALSE;
m_bQualityChanged = FALSE;
}
d)
其他函数
// Standard setup for output sample
HRESULT InitializeOutputSample(IMediaSample*pSample, IMediaSample **ppOutSample);
{
IMediaSample *pOutSample;
AM_SAMPLE2_PROPERTIES *const pProps = m_pInput->SampleProps();
DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED :0;
if(!(pProps->dwSampleFlags& AM_SAMPLE_SPLICEPOINT)){
dwFlags |= AM_GBF_NOTASYNCPOINT; }
HRESULT hr = m_pOutput->m_pAllocator->GetBuffer(
&pOutSample
, pProps->dwSampleFlags& AM_SAMPLE_TIMEVALID ? &pProps->tStart:NULL
, pProps->dwSampleFlags& AM_SAMPLE_STOPVALID ? &pProps->tStop:NULL
,dwFlags
);
*ppOutSample= pOutSample;
// 如果支持IMediaSample2接口,则调用该接口来设置属性,否则调用IMediaSample来设置
}