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

类别:软件工程 点击:0 评论:0 推荐:

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(const CMediaType* mtIn) PURE;
// check if you can support the transform from this input to this output,必须override
virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE;
// call the SetProperties function with appropriate arguments,必须override
virtual HRESULT DecideBufferSize(
                    IMemAllocator * pAllocator,
                    ALLOCATOR_PROPERTIES *pprop) PURE;
// override to suggest OUTPUT pin media types,必须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);
}

c)        继承CBaseFilter的函数:
virtual int GetPinCount();{return 2; }
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);}
    else if (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) {}
    else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) {
        if (m_pOutput && m_bEOSDelivered == FALSE) {
            m_pOutput->DeliverEndOfStream();
            m_bEOSDelivered = TRUE;
        }
        m_State = State_Paused;    }
    else if (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来设置
}

前一篇:学习(五) CSource类和其一个具体实现例子的源代码分析

本文地址:http://com.8s8s.com/it/it32821.htm