DirectShow 学习(六): CTransfromFilter及相关联Pin类的源代码解析(转载)

来源:互联网 发布:牛屎芯片编程器 编辑:程序博客网 时间:2024/05/16 10:59
 转自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来设置
}