Filter组件开发中的SDK基类分析

14 篇文章 0 订阅
7 篇文章 0 订阅

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

参考书<<DirectShow开发指南>>

 

DirectShow SDK提供了一套开发Filter的基类源代码。基于这些基类开发Filter将大大简化开发过程。

1、CBaseObject

大部分SDK类都从CBaseObject类(参见combase.h)中继承而来的。

  1. class CBaseObject  
  2. {  
  3.   
  4. private:  
  5.   
  6.     // Disable the copy constructor and assignment by default so you will get  
  7.     //   compiler errors instead of unexpected behaviour if you pass objects  
  8.     //   by value or assign objects.  
  9.     CBaseObject(const CBaseObject& objectSrc);          // no implementation  
  10.     void operator=(const CBaseObject& objectSrc);       // no implementation  
  11.   
  12. private:  
  13.     static LONG m_cObjects;     /* Total number of objects active */  
  14.   
  15. protected:  
  16. #ifdef DEBUG  
  17.     DWORD m_dwCookie;           /* Cookie identifying this object */  
  18. #endif  
  19.   
  20.   
  21. public:  
  22.   
  23.     /* These increment and decrement the number of active objects */  
  24.   
  25.     CBaseObject(const TCHAR *pName);  
  26. #ifdef UNICODE  
  27.     CBaseObject(const char *pName);  
  28. #endif  
  29.     ~CBaseObject();  
  30.   
  31.     /* Call this to find if there are any CUnknown derived objects active */  
  32.   
  33.     static LONG ObjectsActive() {  
  34.         return m_cObjects;  
  35.     };  
  36. };  
class CBaseObject
{

private:

    // Disable the copy constructor and assignment by default so you will get
    //   compiler errors instead of unexpected behaviour if you pass objects
    //   by value or assign objects.
    CBaseObject(const CBaseObject& objectSrc);          // no implementation
    void operator=(const CBaseObject& objectSrc);       // no implementation

private:
    static LONG m_cObjects;     /* Total number of objects active */

protected:
#ifdef DEBUG
    DWORD m_dwCookie;           /* Cookie identifying this object */
#endif


public:

    /* These increment and decrement the number of active objects */

    CBaseObject(const TCHAR *pName);
#ifdef UNICODE
    CBaseObject(const char *pName);
#endif
    ~CBaseObject();

    /* Call this to find if there are any CUnknown derived objects active */

    static LONG ObjectsActive() {
        return m_cObjects;
    };
};

 


2、 CUnknown

作为COM组件(参见combase.cpp文件),最基本的当然是IUnknown接口的实现。SDK提供了CUnknown类,SDK实现了COM接口类都是直接或间接从这个类继承来的。

  1. class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,  
  2.                  public CBaseObject  
  3. {  
  4. private:  
  5.     const LPUNKNOWN m_pUnknown; /* Owner of this object */  
  6.   
  7. protected:                      /* So we can override NonDelegatingRelease() */  
  8.     volatile LONG m_cRef;       /* Number of reference counts */  
  9.   
  10. public:  
  11.   
  12.     CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);  
  13.     virtual ~CUnknown() {};  
  14.   
  15.     // This is redundant, just use the other constructor  
  16.     //   as we never touch the HRESULT in this anyway  
  17.     CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);  
  18. #ifdef UNICODE  
  19.     CUnknown(const char *pName, LPUNKNOWN pUnk);  
  20.     CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);  
  21. #endif  
  22.   
  23.     /* Return the owner of this object */  
  24.   
  25.     LPUNKNOWN GetOwner() const {  
  26.         return m_pUnknown;  
  27.     };  
  28.   
  29.     /* Called from the class factory to create a new instance, it is 
  30.        pure virtual so it must be overriden in your derived class */  
  31.   
  32.     /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */  
  33.   
  34.     /* Non delegating unknown implementation */  
  35.   
  36.     STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);  
  37.     STDMETHODIMP_(ULONG) NonDelegatingAddRef();  
  38.     STDMETHODIMP_(ULONG) NonDelegatingRelease();  
  39. };  
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
                 public CBaseObject
{
private:
    const LPUNKNOWN m_pUnknown; /* Owner of this object */

protected:                      /* So we can override NonDelegatingRelease() */
    volatile LONG m_cRef;       /* Number of reference counts */

public:

    CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);
    virtual ~CUnknown() {};

    // This is redundant, just use the other constructor
    //   as we never touch the HRESULT in this anyway
    CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);
#ifdef UNICODE
    CUnknown(const char *pName, LPUNKNOWN pUnk);
    CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);
#endif

    /* Return the owner of this object */

    LPUNKNOWN GetOwner() const {
        return m_pUnknown;
    };

    /* Called from the class factory to create a new instance, it is
       pure virtual so it must be overriden in your derived class */

    /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */

    /* Non delegating unknown implementation */

    STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
    STDMETHODIMP_(ULONG) NonDelegatingAddRef();
    STDMETHODIMP_(ULONG) NonDelegatingRelease();
};

 

CUnknown类从CBaseObject中继承而来,另外CUnknown类还实现了INonDelegatingUnknown接口,用于支持引用计数、接口查询、COM组件“聚合”等。

CUnknown类的使用方法如下:

(1) 从CUnknown派生一个子类,并在子类的public区加入DECLARE_IUNKNOWN宏;

(2) 重写NonDelegatingQueryInterface函数,用以支持IUnknown外的其他接口;

(3) 在子类的构造函数中调用CUnknown的构造函数。

eg:

  1. class CSeekingPassThru : public ISeekingPassThru, public CUnknown  
  2. {  
  3. public:  
  4.     static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);  
  5.     CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);  
  6.     ~CSeekingPassThru();  
  7.   
  8.     DECLARE_IUNKNOWN;  
  9.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);  
  10.   
  11.     STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);  
  12.   
  13. private:  
  14.     CPosPassThru              *m_pPosPassThru;  
  15. };  
class CSeekingPassThru : public ISeekingPassThru, public CUnknown
{
public:
    static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
    CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
    ~CSeekingPassThru();

    DECLARE_IUNKNOWN;
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);

    STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);

private:
    CPosPassThru              *m_pPosPassThru;
};

 


  

  1. CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )  
  2.                             : CUnknown(pName, pUnk, phr),  
  3.                             m_pPosPassThru(NULL)  
  4. {  
  5. }  
CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
                            : CUnknown(pName, pUnk, phr),
                            m_pPosPassThru(NULL)
{
}

 


3、 CBaseFilter

最基本的Filter由CBaseFilter 类(参见amfilter.cpp)实现。

作为Filter的基本特征,CBaseFilter实现了IBaseFilter接口(IbaseFilter从IMediaFilter继承而来)。

同时CBaseFilter还实现了Filter框架(描述了各个Pin组件的情况)。

  1. class AM_NOVTABLE CBaseFilter : public CUnknown,        // Handles an IUnknown  
  2.                     public IBaseFilter,     // The Filter Interface  
  3.                     public IAMovieSetup     // For un/registration  
  4. {  
  5.   
  6. friend class CBasePin;  
  7.   
  8. protected:  
  9.     FILTER_STATE    m_State;            // current state: running, paused  
  10.     IReferenceClock *m_pClock;          // this graph's ref clock  
  11.     CRefTime        m_tStart;           // offset from stream time to reference time  
  12.     CLSID       m_clsid;            // This filters clsid  
  13.                                         // used for serialization  
  14.     CCritSec        *m_pLock;           // Object we use for locking  
  15.   
  16.     WCHAR           *m_pName;           // Full filter name  
  17.     IFilterGraph    *m_pGraph;          // Graph we belong to  
  18.     IMediaEventSink *m_pSink;           // Called with notify events  
  19.     LONG            m_PinVersion;       // Current pin version  
  20.   
  21. public:  
  22.   
  23.     CBaseFilter(  
  24.         const TCHAR *pName,     // Object description  
  25.         LPUNKNOWN pUnk,         // IUnknown of delegating object  
  26.         CCritSec  *pLock,       // Object who maintains lock  
  27.     REFCLSID   clsid);      // The clsid to be used to serialize this filter  
  28.   
  29.     CBaseFilter(  
  30.         TCHAR     *pName,       // Object description  
  31.         LPUNKNOWN pUnk,         // IUnknown of delegating object  
  32.         CCritSec  *pLock,       // Object who maintains lock  
  33.     REFCLSID   clsid,       // The clsid to be used to serialize this filter  
  34.         HRESULT   *phr);        // General OLE return code  
  35. #ifdef UNICODE  
  36.     CBaseFilter(  
  37.         const CHAR *pName,     // Object description  
  38.         LPUNKNOWN pUnk,         // IUnknown of delegating object  
  39.         CCritSec  *pLock,       // Object who maintains lock  
  40.     REFCLSID   clsid);      // The clsid to be used to serialize this filter  
  41.   
  42.     CBaseFilter(  
  43.         CHAR     *pName,       // Object description  
  44.         LPUNKNOWN pUnk,         // IUnknown of delegating object  
  45.         CCritSec  *pLock,       // Object who maintains lock  
  46.     REFCLSID   clsid,       // The clsid to be used to serialize this filter  
  47.         HRESULT   *phr);        // General OLE return code  
  48. #endif  
  49.     ~CBaseFilter();  
  50.   
  51.     DECLARE_IUNKNOWN  
  52.   
  53.     // override this to say what interfaces we support where  
  54.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);  
  55. #ifdef DEBUG  
  56.     STDMETHODIMP_(ULONG) NonDelegatingRelease();  
  57. #endif  
  58.   
  59.     //  
  60.     // --- IPersist method ---  
  61.     //  
  62.   
  63.     STDMETHODIMP GetClassID(CLSID *pClsID);  
  64.   
  65.     // --- IMediaFilter methods ---  
  66.   
  67.     STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State);  
  68.   
  69.     STDMETHODIMP SetSyncSource(IReferenceClock *pClock);  
  70.   
  71.     STDMETHODIMP GetSyncSource(IReferenceClock **pClock);  
  72.   
  73.   
  74.     // override Stop and Pause so we can activate the pins.  
  75.     // Note that Run will call Pause first if activation needed.  
  76.     // Override these if you want to activate your filter rather than  
  77.     // your pins.  
  78.     STDMETHODIMP Stop();  
  79.     STDMETHODIMP Pause();  
  80.   
  81.     // the start parameter is the difference to be added to the  
  82.     // sample's stream time to get the reference time for  
  83.     // its presentation  
  84.     STDMETHODIMP Run(REFERENCE_TIME tStart);  
  85.   
  86.     // --- helper methods ---  
  87.   
  88.     // return the current stream time - ie find out what  
  89.     // stream time should be appearing now  
  90.     virtual HRESULT StreamTime(CRefTime& rtStream);  
  91.   
  92.     // Is the filter currently active?  
  93.     BOOL IsActive() {  
  94.         CAutoLock cObjectLock(m_pLock);  
  95.         return ((m_State == State_Paused) || (m_State == State_Running));  
  96.     };  
  97.   
  98.     // Is this filter stopped (without locking)  
  99.     BOOL IsStopped() {  
  100.         return (m_State == State_Stopped);  
  101.     };  
  102.   
  103.     //  
  104.     // --- IBaseFilter methods ---  
  105.     //  
  106.   
  107.     // pin enumerator  
  108.     STDMETHODIMP EnumPins(  
  109.                     IEnumPins ** ppEnum);  
  110.   
  111.   
  112.     // default behaviour of FindPin assumes pin ids are their names  
  113.     STDMETHODIMP FindPin(  
  114.         LPCWSTR Id,  
  115.         IPin ** ppPin  
  116.     );  
  117.   
  118.     STDMETHODIMP QueryFilterInfo(  
  119.                     FILTER_INFO * pInfo);  
  120.   
  121.     STDMETHODIMP JoinFilterGraph(  
  122.                     IFilterGraph * pGraph,  
  123.                     LPCWSTR pName);  
  124.   
  125.     // return a Vendor information string. Optional - may return E_NOTIMPL.  
  126.     // memory returned should be freed using CoTaskMemFree  
  127.     // default implementation returns E_NOTIMPL  
  128.     STDMETHODIMP QueryVendorInfo(  
  129.                     LPWSTR* pVendorInfo  
  130.             );  
  131.   
  132.     // --- helper methods ---  
  133.   
  134.     // send an event notification to the filter graph if we know about it.  
  135.     // returns S_OK if delivered, S_FALSE if the filter graph does not sink  
  136.     // events, or an error otherwise.  
  137.     HRESULT NotifyEvent(  
  138.         long EventCode,  
  139.         LONG_PTR EventParam1,  
  140.         LONG_PTR EventParam2);  
  141.   
  142.     // return the filter graph we belong to  
  143.     IFilterGraph *GetFilterGraph() {  
  144.         return m_pGraph;  
  145.     }  
  146.   
  147.     // Request reconnect  
  148.     // pPin is the pin to reconnect  
  149.     // pmt is the type to reconnect with - can be NULL  
  150.     // Calls ReconnectEx on the filter graph  
  151.     HRESULT ReconnectPin(IPin *pPin, AM_MEDIA_TYPE const *pmt);  
  152.   
  153.     // find out the current pin version (used by enumerators)  
  154.     virtual LONG GetPinVersion();  
  155.     void IncrementPinVersion();  
  156.   
  157.     // you need to supply these to access the pins from the enumerator  
  158.     // and for default Stop and Pause/Run activation.  
  159.     virtual int GetPinCount() PURE;  
  160.     virtual CBasePin *GetPin(int n) PURE;  
  161.   
  162.     // --- IAMovieSetup methods ---  
  163.   
  164.     STDMETHODIMP Register();    // ask filter to register itself  
  165.     STDMETHODIMP Unregister();  // and unregister itself  
  166.   
  167.     // --- setup helper methods ---  
  168.     // (override to return filters setup data)  
  169.   
  170.     virtual LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; }  
  171.   
  172. };  
class AM_NOVTABLE CBaseFilter : public CUnknown,        // Handles an IUnknown
                    public IBaseFilter,     // The Filter Interface
                    public IAMovieSetup     // For un/registration
{

friend class CBasePin;

protected:
    FILTER_STATE    m_State;            // current state: running, paused
    IReferenceClock *m_pClock;          // this graph's ref clock
    CRefTime        m_tStart;           // offset from stream time to reference time
    CLSID	    m_clsid;            // This filters clsid
                                        // used for serialization
    CCritSec        *m_pLock;           // Object we use for locking

    WCHAR           *m_pName;           // Full filter name
    IFilterGraph    *m_pGraph;          // Graph we belong to
    IMediaEventSink *m_pSink;           // Called with notify events
    LONG            m_PinVersion;       // Current pin version

public:

    CBaseFilter(
        const TCHAR *pName,     // Object description
        LPUNKNOWN pUnk,         // IUnknown of delegating object
        CCritSec  *pLock,       // Object who maintains lock
	REFCLSID   clsid);      // The clsid to be used to serialize this filter

    CBaseFilter(
        TCHAR     *pName,       // Object description
        LPUNKNOWN pUnk,         // IUnknown of delegating object
        CCritSec  *pLock,       // Object who maintains lock
	REFCLSID   clsid,       // The clsid to be used to serialize this filter
        HRESULT   *phr);        // General OLE return code
#ifdef UNICODE
    CBaseFilter(
        const CHAR *pName,     // Object description
        LPUNKNOWN pUnk,         // IUnknown of delegating object
        CCritSec  *pLock,       // Object who maintains lock
	REFCLSID   clsid);      // The clsid to be used to serialize this filter

    CBaseFilter(
        CHAR     *pName,       // Object description
        LPUNKNOWN pUnk,         // IUnknown of delegating object
        CCritSec  *pLock,       // Object who maintains lock
	REFCLSID   clsid,       // The clsid to be used to serialize this filter
        HRESULT   *phr);        // General OLE return code
#endif
    ~CBaseFilter();

    DECLARE_IUNKNOWN

    // override this to say what interfaces we support where
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
#ifdef DEBUG
    STDMETHODIMP_(ULONG) NonDelegatingRelease();
#endif

    //
    // --- IPersist method ---
    //

    STDMETHODIMP GetClassID(CLSID *pClsID);

    // --- IMediaFilter methods ---

    STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State);

    STDMETHODIMP SetSyncSource(IReferenceClock *pClock);

    STDMETHODIMP GetSyncSource(IReferenceClock **pClock);


    // override Stop and Pause so we can activate the pins.
    // Note that Run will call Pause first if activation needed.
    // Override these if you want to activate your filter rather than
    // your pins.
    STDMETHODIMP Stop();
    STDMETHODIMP Pause();

    // the start parameter is the difference to be added to the
    // sample's stream time to get the reference time for
    // its presentation
    STDMETHODIMP Run(REFERENCE_TIME tStart);

    // --- helper methods ---

    // return the current stream time - ie find out what
    // stream time should be appearing now
    virtual HRESULT StreamTime(CRefTime& rtStream);

    // Is the filter currently active?
    BOOL IsActive() {
        CAutoLock cObjectLock(m_pLock);
        return ((m_State == State_Paused) || (m_State == State_Running));
    };

    // Is this filter stopped (without locking)
    BOOL IsStopped() {
        return (m_State == State_Stopped);
    };

    //
    // --- IBaseFilter methods ---
    //

    // pin enumerator
    STDMETHODIMP EnumPins(
                    IEnumPins ** ppEnum);


    // default behaviour of FindPin assumes pin ids are their names
    STDMETHODIMP FindPin(
        LPCWSTR Id,
        IPin ** ppPin
    );

    STDMETHODIMP QueryFilterInfo(
                    FILTER_INFO * pInfo);

    STDMETHODIMP JoinFilterGraph(
                    IFilterGraph * pGraph,
                    LPCWSTR pName);

    // return a Vendor information string. Optional - may return E_NOTIMPL.
    // memory returned should be freed using CoTaskMemFree
    // default implementation returns E_NOTIMPL
    STDMETHODIMP QueryVendorInfo(
                    LPWSTR* pVendorInfo
            );

    // --- helper methods ---

    // send an event notification to the filter graph if we know about it.
    // returns S_OK if delivered, S_FALSE if the filter graph does not sink
    // events, or an error otherwise.
    HRESULT NotifyEvent(
        long EventCode,
        LONG_PTR EventParam1,
        LONG_PTR EventParam2);

    // return the filter graph we belong to
    IFilterGraph *GetFilterGraph() {
        return m_pGraph;
    }

    // Request reconnect
    // pPin is the pin to reconnect
    // pmt is the type to reconnect with - can be NULL
    // Calls ReconnectEx on the filter graph
    HRESULT ReconnectPin(IPin *pPin, AM_MEDIA_TYPE const *pmt);

    // find out the current pin version (used by enumerators)
    virtual LONG GetPinVersion();
    void IncrementPinVersion();

    // you need to supply these to access the pins from the enumerator
    // and for default Stop and Pause/Run activation.
    virtual int GetPinCount() PURE;
    virtual CBasePin *GetPin(int n) PURE;

    // --- IAMovieSetup methods ---

    STDMETHODIMP Register();    // ask filter to register itself
    STDMETHODIMP Unregister();  // and unregister itself

    // --- setup helper methods ---
    // (override to return filters setup data)

    virtual LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; }

};

 


CBaseFilter类的使用方法如下:

(1) 声明一个新类是从CBaseFilter中继承而来;

(2) 在新类中定义Filter上的Pin的实例(Pin从CBasePin类继承而来);

(3) 实现纯虚函数CBaseFilter::GetPin,用于返回Filter上各个Pin的对象指针;

(4) 实现纯虚函数CBaseFilter::GetPinCount,用于返回Filter上Pin 的数量;

(5) 考虑如何处理从输入Pin进来的Sample数据。

eg:

  1. //  
  2. // The filter object itself. Supports IBaseFilter through  
  3. // CBaseFilter and also IFileSourceFilter directly in this object  
  4. // CAsyncReader类实现了一个Filter,它从CBaseFilter派生,实现了仅含一个输出  
  5. // Pin(CAsyncOutputPin类的实例)的Source filter框架。  
  6. class CAsyncReader : public CBaseFilter  
  7. {  
  8.   
  9. protected:  
  10.     // filter-wide lock  
  11.     CCritSec m_csFilter;  
  12.   
  13.     // all i/o done here  
  14.     CAsyncIo m_Io;  
  15.   
  16.     // (2)在新类中定义Filter上的Pin的实例(Pin从CBasePin类继承而来);  
  17.     // our output pin  
  18.     CAsyncOutputPin m_OutputPin;  
  19.   
  20.     // Type we think our data is  
  21.     CMediaType m_mt;  
  22.   
  23. public:  
  24.           
  25.     // construction / destruction  
  26.   
  27.     CAsyncReader(  
  28.         TCHAR *pName,  
  29.         LPUNKNOWN pUnk,  
  30.         CAsyncStream *pStream, // 它是Filter获取数据的源  
  31.         HRESULT *phr);  
  32.   
  33.     ~CAsyncReader();  
  34.   
  35.   
  36.     //(3) 实现纯虚函数CBaseFilter::GetPin,用于返回Filter上各个Pin的对象指针;  
  37.     //(4) 实现纯虚函数CBaseFilter::GetPinCount,用于返回Filter上Pin 的数量;  
  38.     int GetPinCount();  
  39.     CBasePin *GetPin(int n);  
  40.   
  41.     // --- Access our media type  
  42.     const CMediaType *LoadType() const  
  43.     {  
  44.         return &m_mt;  
  45.     }  
  46.   
  47.     virtual HRESULT Connect(  
  48.         IPin * pReceivePin,  
  49.         const AM_MEDIA_TYPE *pmt   // optional media type  
  50.     )  
  51.     {  
  52.         return m_OutputPin.CBasePin::Connect(pReceivePin, pmt);  
  53.     }  
  54. };  
//
// The filter object itself. Supports IBaseFilter through
// CBaseFilter and also IFileSourceFilter directly in this object
// CAsyncReader类实现了一个Filter,它从CBaseFilter派生,实现了仅含一个输出
// Pin(CAsyncOutputPin类的实例)的Source filter框架。
class CAsyncReader : public CBaseFilter
{

protected:
    // filter-wide lock
    CCritSec m_csFilter;

    // all i/o done here
    CAsyncIo m_Io;

	// (2)在新类中定义Filter上的Pin的实例(Pin从CBasePin类继承而来);
    // our output pin
    CAsyncOutputPin m_OutputPin;

    // Type we think our data is
    CMediaType m_mt;

public:
        
    // construction / destruction

    CAsyncReader(
        TCHAR *pName,
        LPUNKNOWN pUnk,
        CAsyncStream *pStream, // 它是Filter获取数据的源
        HRESULT *phr);

    ~CAsyncReader();


	//(3) 实现纯虚函数CBaseFilter::GetPin,用于返回Filter上各个Pin的对象指针;
	//(4) 实现纯虚函数CBaseFilter::GetPinCount,用于返回Filter上Pin 的数量;
    int GetPinCount();
    CBasePin *GetPin(int n);

    // --- Access our media type
    const CMediaType *LoadType() const
    {
        return &m_mt;
    }

    virtual HRESULT Connect(
        IPin * pReceivePin,
        const AM_MEDIA_TYPE *pmt   // optional media type
    )
    {
        return m_OutputPin.CBasePin::Connect(pReceivePin, pmt);
    }
};

 


还有SDK类的CSource、CBaseRenderer、 CTracsformFilter都是从CBaseFilter继承来的,实现开发Filter时,

使用这些子类作为Filter类。

4、CBasePin

Filter  上最基本的Pin由CBasePin类(参见 amfilter.h)实现。

作为Pin的基本特征,CBasePin实现了IPin接口。CBasePin设计了Pin 的整个连接过程。

另外,这个类还实现了IQualityControl接口,该接口用于质量控制

  1. class  AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl  
  2. {  
  3.   
  4. protected:  
  5.   
  6.     WCHAR *         m_pName;                // This pin's name  
  7.     IPin            *m_Connected;               // Pin we have connected to  
  8.     PIN_DIRECTION   m_dir;                      // Direction of this pin  
  9.     CCritSec        *m_pLock;                   // Object we use for locking  
  10.     bool            m_bRunTimeError;            // Run time error generated  
  11.     bool            m_bCanReconnectWhenActive;  // OK to reconnect when active  
  12.     bool            m_bTryMyTypesFirst;         // When connecting enumerate  
  13.                                                 // this pin's types first  
  14.     CBaseFilter    *m_pFilter;                  // Filter we were created by  
  15.     IQualityControl *m_pQSink;                  // Target for Quality messages  
  16.     LONG            m_TypeVersion;              // Holds current type version  
  17.     CMediaType      m_mt;                       // Media type of connection  
  18.   
  19.     CRefTime        m_tStart;                   // time from NewSegment call  
  20.     CRefTime        m_tStop;                    // time from NewSegment  
  21.     double          m_dRate;                    // rate from NewSegment  
  22.   
  23. #ifdef DEBUG  
  24.     LONG            m_cRef;                     // Ref count tracing  
  25. #endif  
  26.   
  27.     // displays pin connection information  
  28.   
  29. #ifdef DEBUG  
  30.     void DisplayPinInfo(IPin *pReceivePin);  
  31.     void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt);  
  32. #else  
  33.     void DisplayPinInfo(IPin *pReceivePin) {};  
  34.     void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {};  
  35. #endif  
  36.   
  37.     // used to agree a media type for a pin connection  
  38.   
  39.     // given a specific media type, attempt a connection (includes  
  40.     // checking that the type is acceptable to this pin)  
  41.     HRESULT  
  42.     AttemptConnection(  
  43.         IPin* pReceivePin,      // connect to this pin  
  44.         const CMediaType* pmt   // using this type  
  45.     );  
  46.   
  47.     // try all the media types in this enumerator - for each that  
  48.     // we accept, try to connect using ReceiveConnection.  
  49.     HRESULT TryMediaTypes(  
  50.                         IPin *pReceivePin,      // connect to this pin  
  51.                         const CMediaType *pmt,        // proposed type from Connect  
  52.                         IEnumMediaTypes *pEnum);    // try this enumerator  
  53.   
  54.     // establish a connection with a suitable mediatype. Needs to  
  55.     // propose a media type if the pmt pointer is null or partially  
  56.     // specified - use TryMediaTypes on both our and then the other pin's  
  57.     // enumerator until we find one that works.  
  58.     HRESULT AgreeMediaType(  
  59.                         IPin *pReceivePin,      // connect to this pin  
  60.                         const CMediaType *pmt);       // proposed type from Connect  
  61.   
  62. public:  
  63.   
  64.     CBasePin(  
  65.         TCHAR *pObjectName,         // Object description  
  66.         CBaseFilter *pFilter,       // Owning filter who knows about pins  
  67.         CCritSec *pLock,            // Object who implements the lock  
  68.         HRESULT *phr,               // General OLE return code  
  69.         LPCWSTR pName,              // Pin name for us  
  70.         PIN_DIRECTION dir);         // Either PINDIR_INPUT or PINDIR_OUTPUT  
  71. #ifdef UNICODE  
  72.     CBasePin(  
  73.         CHAR *pObjectName,         // Object description  
  74.         CBaseFilter *pFilter,       // Owning filter who knows about pins  
  75.         CCritSec *pLock,            // Object who implements the lock  
  76.         HRESULT *phr,               // General OLE return code  
  77.         LPCWSTR pName,              // Pin name for us  
  78.         PIN_DIRECTION dir);         // Either PINDIR_INPUT or PINDIR_OUTPUT  
  79. #endif  
  80.     virtual ~CBasePin();  
  81.   
  82.     DECLARE_IUNKNOWN  
  83.   
  84.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);  
  85.     STDMETHODIMP_(ULONG) NonDelegatingRelease();  
  86.     STDMETHODIMP_(ULONG) NonDelegatingAddRef();  
  87.   
  88.     // --- IPin methods ---  
  89.   
  90.     // take lead role in establishing a connection. Media type pointer  
  91.     // may be null, or may point to partially-specified mediatype  
  92.     // (subtype or format type may be GUID_NULL).  
  93.     STDMETHODIMP Connect(  
  94.         IPin * pReceivePin,  
  95.         const AM_MEDIA_TYPE *pmt   // optional media type  
  96.     );  
  97.   
  98.     // (passive) accept a connection from another pin  
  99.     STDMETHODIMP ReceiveConnection(  
  100.         IPin * pConnector,      // this is the initiating connecting pin  
  101.         const AM_MEDIA_TYPE *pmt   // this is the media type we will exchange  
  102.     );  
  103.   
  104.     STDMETHODIMP Disconnect();  
  105.   
  106.     STDMETHODIMP ConnectedTo(IPin **pPin);  
  107.   
  108.     STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *pmt);  
  109.   
  110.     STDMETHODIMP QueryPinInfo(  
  111.         PIN_INFO * pInfo  
  112.     );  
  113.   
  114.     STDMETHODIMP QueryDirection(  
  115.         PIN_DIRECTION * pPinDir  
  116.     );  
  117.   
  118.     STDMETHODIMP QueryId(  
  119.         LPWSTR * Id  
  120.     );  
  121.   
  122.     // does the pin support this media type  
  123.     STDMETHODIMP QueryAccept(  
  124.         const AM_MEDIA_TYPE *pmt  
  125.     );  
  126.   
  127.     // return an enumerator for this pins preferred media types  
  128.     STDMETHODIMP EnumMediaTypes(  
  129.         IEnumMediaTypes **ppEnum  
  130.     );  
  131.   
  132.     // return an array of IPin* - the pins that this pin internally connects to  
  133.     // All pins put in the array must be AddReffed (but no others)  
  134.     // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE  
  135.     // Default: return E_NOTIMPL  
  136.     // The filter graph will interpret NOT_IMPL as any input pin connects to  
  137.     // all visible output pins and vice versa.  
  138.     // apPin can be NULL if nPin==0 (not otherwise).  
  139.     STDMETHODIMP QueryInternalConnections(  
  140.         IPin* *apPin,     // array of IPin*  
  141.         ULONG *nPin       // on input, the number of slots  
  142.                           // on output  the number of pins  
  143.     ) { return E_NOTIMPL; }  
  144.   
  145.     // Called when no more data will be sent  
  146.     STDMETHODIMP EndOfStream(void);  
  147.   
  148.     // Begin/EndFlush still PURE  
  149.   
  150.     // NewSegment notifies of the start/stop/rate applying to the data  
  151.     // about to be received. Default implementation records data and  
  152.     // returns S_OK.  
  153.     // Override this to pass downstream.  
  154.     STDMETHODIMP NewSegment(  
  155.                     REFERENCE_TIME tStart,  
  156.                     REFERENCE_TIME tStop,  
  157.                     double dRate);  
  158.   
  159.     //================================================================================  
  160.     // IQualityControl methods  
  161.     //================================================================================  
  162.   
  163.     STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);  
  164.   
  165.     STDMETHODIMP SetSink(IQualityControl * piqc);  
  166.   
  167.     // --- helper methods ---  
  168.   
  169.     // Returns true if the pin is connected. false otherwise.  
  170.     BOOL IsConnected(void) {return (m_Connected != NULL); };  
  171.     // Return the pin this is connected to (if any)  
  172.     IPin * GetConnected() { return m_Connected; };  
  173.   
  174.     // Check if our filter is currently stopped  
  175.     BOOL IsStopped() {  
  176.         return (m_pFilter->m_State == State_Stopped);  
  177.     };  
  178.   
  179.     // find out the current type version (used by enumerators)  
  180.     virtual LONG GetMediaTypeVersion();  
  181.     void IncrementTypeVersion();  
  182.   
  183.     // switch the pin to active (paused or running) mode  
  184.     // not an error to call this if already active  
  185.     virtual HRESULT Active(void);  
  186.   
  187.     // switch the pin to inactive state - may already be inactive  
  188.     virtual HRESULT Inactive(void);  
  189.   
  190.     // Notify of Run() from filter  
  191.     virtual HRESULT Run(REFERENCE_TIME tStart);  
  192.   
  193.     // check if the pin can support this specific proposed type and format  
  194.     virtual HRESULT CheckMediaType(const CMediaType *) PURE;  
  195.   
  196.     // set the connection to use this format (previously agreed)  
  197.     virtual HRESULT SetMediaType(const CMediaType *);  
  198.   
  199.     // check that the connection is ok before verifying it  
  200.     // can be overridden eg to check what interfaces will be supported.  
  201.     virtual HRESULT CheckConnect(IPin *);  
  202.   
  203.     // Set and release resources required for a connection  
  204.     virtual HRESULT BreakConnect();  
  205.     virtual HRESULT CompleteConnect(IPin *pReceivePin);  
  206.   
  207.     // returns the preferred formats for a pin  
  208.     virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);  
  209.   
  210.     // access to NewSegment values  
  211.     REFERENCE_TIME CurrentStopTime() {  
  212.         return m_tStop;  
  213.     }  
  214.     REFERENCE_TIME CurrentStartTime() {  
  215.         return m_tStart;  
  216.     }  
  217.     double CurrentRate() {  
  218.         return m_dRate;  
  219.     }  
  220.   
  221.     //  Access name  
  222.     LPWSTR Name() { return m_pName; };  
  223.   
  224.     //  Can reconnectwhen active?  
  225.     void SetReconnectWhenActive(bool bCanReconnect)  
  226.     {  
  227.         m_bCanReconnectWhenActive = bCanReconnect;  
  228.     }  
  229.   
  230.     bool CanReconnectWhenActive()  
  231.     {  
  232.         return m_bCanReconnectWhenActive;  
  233.     }  
  234.   
  235. protected:  
  236.     STDMETHODIMP DisconnectInternal();  
  237. };  
class  AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl
{

protected:

    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
                                                // this pin's types first
    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

#ifdef DEBUG
    LONG            m_cRef;                     // Ref count tracing
#endif

    // displays pin connection information

#ifdef DEBUG
    void DisplayPinInfo(IPin *pReceivePin);
    void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt);
#else
    void DisplayPinInfo(IPin *pReceivePin) {};
    void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {};
#endif

    // used to agree a media type for a pin connection

    // given a specific media type, attempt a connection (includes
    // checking that the type is acceptable to this pin)
    HRESULT
    AttemptConnection(
        IPin* pReceivePin,      // connect to this pin
        const CMediaType* pmt   // using this type
    );

    // try all the media types in this enumerator - for each that
    // we accept, try to connect using ReceiveConnection.
    HRESULT TryMediaTypes(
                        IPin *pReceivePin,      // connect to this pin
                        const CMediaType *pmt,        // proposed type from Connect
                        IEnumMediaTypes *pEnum);    // try this enumerator

    // establish a connection with a suitable mediatype. Needs to
    // propose a media type if the pmt pointer is null or partially
    // specified - use TryMediaTypes on both our and then the other pin's
    // enumerator until we find one that works.
    HRESULT AgreeMediaType(
                        IPin *pReceivePin,      // connect to this pin
                        const CMediaType *pmt);       // proposed type from Connect

public:

    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
#ifdef UNICODE
    CBasePin(
        CHAR *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
#endif
    virtual ~CBasePin();

    DECLARE_IUNKNOWN

    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
    STDMETHODIMP_(ULONG) NonDelegatingRelease();
    STDMETHODIMP_(ULONG) NonDelegatingAddRef();

    // --- IPin methods ---

    // take lead role in establishing a connection. Media type pointer
    // may be null, or may point to partially-specified mediatype
    // (subtype or format type may be GUID_NULL).
    STDMETHODIMP Connect(
        IPin * pReceivePin,
        const AM_MEDIA_TYPE *pmt   // optional media type
    );

    // (passive) accept a connection from another pin
    STDMETHODIMP ReceiveConnection(
        IPin * pConnector,      // this is the initiating connecting pin
        const AM_MEDIA_TYPE *pmt   // this is the media type we will exchange
    );

    STDMETHODIMP Disconnect();

    STDMETHODIMP ConnectedTo(IPin **pPin);

    STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *pmt);

    STDMETHODIMP QueryPinInfo(
        PIN_INFO * pInfo
    );

    STDMETHODIMP QueryDirection(
    	PIN_DIRECTION * pPinDir
    );

    STDMETHODIMP QueryId(
        LPWSTR * Id
    );

    // does the pin support this media type
    STDMETHODIMP QueryAccept(
        const AM_MEDIA_TYPE *pmt
    );

    // return an enumerator for this pins preferred media types
    STDMETHODIMP EnumMediaTypes(
        IEnumMediaTypes **ppEnum
    );

    // return an array of IPin* - the pins that this pin internally connects to
    // All pins put in the array must be AddReffed (but no others)
    // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE
    // Default: return E_NOTIMPL
    // The filter graph will interpret NOT_IMPL as any input pin connects to
    // all visible output pins and vice versa.
    // apPin can be NULL if nPin==0 (not otherwise).
    STDMETHODIMP QueryInternalConnections(
        IPin* *apPin,     // array of IPin*
        ULONG *nPin       // on input, the number of slots
                          // on output  the number of pins
    ) { return E_NOTIMPL; }

    // Called when no more data will be sent
    STDMETHODIMP EndOfStream(void);

    // Begin/EndFlush still PURE

    // NewSegment notifies of the start/stop/rate applying to the data
    // about to be received. Default implementation records data and
    // returns S_OK.
    // Override this to pass downstream.
    STDMETHODIMP NewSegment(
                    REFERENCE_TIME tStart,
                    REFERENCE_TIME tStop,
                    double dRate);

    //================================================================================
    // IQualityControl methods
    //================================================================================

    STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);

    STDMETHODIMP SetSink(IQualityControl * piqc);

    // --- helper methods ---

    // Returns true if the pin is connected. false otherwise.
    BOOL IsConnected(void) {return (m_Connected != NULL); };
    // Return the pin this is connected to (if any)
    IPin * GetConnected() { return m_Connected; };

    // Check if our filter is currently stopped
    BOOL IsStopped() {
        return (m_pFilter->m_State == State_Stopped);
    };

    // find out the current type version (used by enumerators)
    virtual LONG GetMediaTypeVersion();
    void IncrementTypeVersion();

    // switch the pin to active (paused or running) mode
    // not an error to call this if already active
    virtual HRESULT Active(void);

    // switch the pin to inactive state - may already be inactive
    virtual HRESULT Inactive(void);

    // Notify of Run() from filter
    virtual HRESULT Run(REFERENCE_TIME tStart);

    // check if the pin can support this specific proposed type and format
    virtual HRESULT CheckMediaType(const CMediaType *) PURE;

    // set the connection to use this format (previously agreed)
    virtual HRESULT SetMediaType(const CMediaType *);

    // check that the connection is ok before verifying it
    // can be overridden eg to check what interfaces will be supported.
    virtual HRESULT CheckConnect(IPin *);

    // Set and release resources required for a connection
    virtual HRESULT BreakConnect();
    virtual HRESULT CompleteConnect(IPin *pReceivePin);

    // returns the preferred formats for a pin
    virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);

    // access to NewSegment values
    REFERENCE_TIME CurrentStopTime() {
        return m_tStop;
    }
    REFERENCE_TIME CurrentStartTime() {
        return m_tStart;
    }
    double CurrentRate() {
        return m_dRate;
    }

    //  Access name
    LPWSTR Name() { return m_pName; };

    //  Can reconnectwhen active?
    void SetReconnectWhenActive(bool bCanReconnect)
    {
        m_bCanReconnectWhenActive = bCanReconnect;
    }

    bool CanReconnectWhenActive()
    {
        return m_bCanReconnectWhenActive;
    }

protected:
    STDMETHODIMP DisconnectInternal();
};

 


在CBasePin实现的成员函数中,有3个与Filter的状态转换相对应

  1. // 转换pin到活动状态(暂停或运行)  
  2.   // not an error to call this if already active  
  3.   virtual HRESULT Active(void);  
  4.   
  5.   // 转换pin到不活动状态 - 可能已经处于非活动状态  
  6.   virtual HRESULT Inactive(void);  
  7.   
  8.   // 通知运行filter 的 Run()  
  9.   virtual HRESULT Run(REFERENCE_TIME tStart);  
  // 转换pin到活动状态(暂停或运行)
    // not an error to call this if already active
    virtual HRESULT Active(void);

    // 转换pin到不活动状态 - 可能已经处于非活动状态
    virtual HRESULT Inactive(void);

    // 通知运行filter 的 Run()
    virtual HRESULT Run(REFERENCE_TIME tStart);

 


 

我们来看一下Filter的Stop的实现,实际上就是调用Filter的所有pin的Inactive函数

  1. STDMETHODIMP  
  2. CBaseFilter::Stop()  
  3. {  
  4.     CAutoLock cObjectLock(m_pLock);  
  5.     HRESULT hr = NOERROR;  
  6.   
  7.     // 通知所有pin改变状态  
  8.     if (m_State != State_Stopped) {  
  9.         int cPins = GetPinCount();  
  10.         for (int c = 0; c < cPins; c++) {  
  11.   
  12.             CBasePin *pPin = GetPin(c);  
  13.   
  14.             // Disconnected pins are not activated - this saves pins worrying  
  15.             // about this state themselves. We ignore the return code to make  
  16.             // sure everyone is inactivated regardless. The base input pin  
  17.             // class can return an error if it has no allocator but Stop can  
  18.             // be used to resync the graph state after something has gone bad  
  19.             // 仅在完成连接的pin上调用Inactive函数  
  20.             // 如果Inactive函数返回一个错误值,则暂时忽略,  
  21.             // 以便所有Pin都有机会被调用Inactive  
  22.             if (pPin->IsConnected()) {  
  23.                 HRESULT hrTmp = pPin->Inactive();  
  24.                 if (FAILED(hrTmp) && SUCCEEDED(hr)) {  
  25.                     hr = hrTmp;  
  26.                 }  
  27.             }  
  28.         }  
  29.     }  
  30.   
  31.   
  32.     m_State = State_Stopped;  
  33.     return hr;  
  34. }  
STDMETHODIMP
CBaseFilter::Stop()
{
    CAutoLock cObjectLock(m_pLock);
    HRESULT hr = NOERROR;

    // 通知所有pin改变状态
    if (m_State != State_Stopped) {
        int cPins = GetPinCount();
        for (int c = 0; c < cPins; c++) {

            CBasePin *pPin = GetPin(c);

            // Disconnected pins are not activated - this saves pins worrying
            // about this state themselves. We ignore the return code to make
            // sure everyone is inactivated regardless. The base input pin
            // class can return an error if it has no allocator but Stop can
            // be used to resync the graph state after something has gone bad
			// 仅在完成连接的pin上调用Inactive函数
			// 如果Inactive函数返回一个错误值,则暂时忽略,
			// 以便所有Pin都有机会被调用Inactive
            if (pPin->IsConnected()) {
                HRESULT hrTmp = pPin->Inactive();
                if (FAILED(hrTmp) && SUCCEEDED(hr)) {
                    hr = hrTmp;
                }
            }
        }
    }


    m_State = State_Stopped;
    return hr;
}

 

 

在实际开发Filter的过程中,很有可能重写CBasePin::Inactive、 CBasePin::Active和CBasePin::Run这3个函数,以进行必要的初始化、释放资源等。

CBasePin类的使用方法如下:

(1) 从CBasePin派生一个子类;

(2) 实现纯虚函数CBasePIn::CheckMediaType,进行Pin连接时的媒体类型检查;

(3) 实现纯虚函数CBasePin::GetMediaType,提供Pin上的首选媒体类型。

(4) 实现IPin::BeginFlush和IPin::EndFlush两个函数。

(5) 可能需要重写的函数包括

CBasePin::Active()  实现资源分配

CBasePin::Inactive  实现资源释放

CBasePin::Run  在Filter运行前进行一些初始化

CBasePin::CheckConnect  连接时检查,如查询对方Pin上是否支持某个特殊接口

CBasePin::BreakConnect 断开连接,并进行必要的资源释放

CBasePin::CompleteConnect  完成连接时被调用,可以在这个函数中获得当前连接的媒体类型参数

CBasePin::EndOfStream 当上流数据全部传送完毕后被调用。

                    如果这个是Transform Filter,则将EndOfStream继续入下传送;

                   如果是Renderer Filter,需要向Filter Graph Manager发送一个EC_COMPLETE事件

CBasePin::Noftify  直接响应质量控制。

eg:

  1. // CAsyncOutputPin实现了一个输出Pin  
  2. // 继承自IAsyncReader、CBasePin,这是对拉模式的Source Filter的基本要求  
  3. /* IAsyncReader接口方法及描述如下: 
  4. BeginFlush  放弃所有正在进行的数据读取 
  5. EndFlush    与BeginFlush配对,标示Flush过程结束 
  6. Length      得到数据总长度和当前可以读取的长度 
  7. RequestAlloctor 要求一个输入Pin上的Sample管理器 
  8. Request     发出一个数据请求 
  9. SyncReadAligned 同步读取数据(边界对齐) 
  10. SyncRead    同步读取数据 
  11. WaitForNext 等待一个请求的完成 
  12. ====================================================================== 
  13. 可以看出CAsyOutputPin类上实现的IAsyncReader的各个接口方法,都“委托” 
  14. 给了CAsyncIo类对象的同名成员函数 
  15. */  
  16. class CAsyncOutputPin  
  17.   : public IAsyncReader,   
  18.     public CBasePin  
  19. {  
  20. protected:  
  21.     CAsyncReader* m_pReader;  
  22.     CAsyncIo * m_pIo;  
  23.   
  24.     //  This is set every time we're asked to return an IAsyncReader  
  25.     //  interface  
  26.     //  This allows us to know if the downstream pin can use  
  27.     //  this transport, otherwise we can hook up to thinks like the  
  28.     //  dump filter and nothing happens  
  29.     BOOL         m_bQueriedForAsyncReader;  
  30.   
  31.     HRESULT InitAllocator(IMemAllocator **ppAlloc);  
  32.   
  33. public:  
  34.     // constructor and destructor  
  35.     CAsyncOutputPin(  
  36.         HRESULT * phr,  
  37.         CAsyncReader *pReader,  
  38.         CAsyncIo *pIo,  
  39.         CCritSec * pLock);  
  40.   
  41.     ~CAsyncOutputPin();  
  42.   
  43.     // --- CUnknown ---  
  44.   
  45.     // need to expose IAsyncReader  
  46.     DECLARE_IUNKNOWN  
  47.     STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**);  
  48.   
  49.     // --- IPin methods ---  
  50.     STDMETHODIMP Connect(  
  51.         IPin * pReceivePin,  
  52.         const AM_MEDIA_TYPE *pmt   // optional media type  
  53.     );  
  54.   
  55.     // --- CBasePin methods ---  
  56.   
  57.     // return the types we prefer - this will return the known  
  58.     // file type  
  59.     HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);  
  60.   
  61.     // can we support this type?  
  62.     HRESULT CheckMediaType(const CMediaType* pType);  
  63.   
  64.     // Clear the flag so we see if IAsyncReader is queried for  
  65.     HRESULT CheckConnect(IPin *pPin)  
  66.     {  
  67.         m_bQueriedForAsyncReader = FALSE;  
  68.         return CBasePin::CheckConnect(pPin);  
  69.     }  
  70.   
  71.     // See if it was asked for  
  72.     HRESULT CompleteConnect(IPin *pReceivePin)  
  73.     {  
  74.         if (m_bQueriedForAsyncReader) {  
  75.             return CBasePin::CompleteConnect(pReceivePin);  
  76.         } else {  
  77.   
  78. #ifdef VFW_E_NO_TRANSPORT  
  79.             return VFW_E_NO_TRANSPORT;  
  80. #else  
  81.             return E_FAIL;  
  82. #endif  
  83.         }  
  84.     }  
  85.   
  86.     //  Remove our connection status  
  87.     HRESULT BreakConnect()  
  88.     {  
  89.         m_bQueriedForAsyncReader = FALSE;  
  90.         return CBasePin::BreakConnect();  
  91.     }  
  92.   
  93.     // --- IAsyncReader methods ---  
  94.     // pass in your preferred allocator and your preferred properties.  
  95.     // method returns the actual allocator to be used. Call GetProperties  
  96.     // on returned allocator to learn alignment and prefix etc chosen.  
  97.     // this allocator will be not be committed and decommitted by  
  98.     // the async reader, only by the consumer.  
  99.     STDMETHODIMP RequestAllocator(  
  100.                       IMemAllocator* pPreferred,  
  101.                       ALLOCATOR_PROPERTIES* pProps,  
  102.                       IMemAllocator ** ppActual);  
  103.   
  104.     // queue a request for data.  
  105.     // media sample start and stop times contain the requested absolute  
  106.     // byte position (start inclusive, stop exclusive).  
  107.     // may fail if sample not obtained from agreed allocator.  
  108.     // may fail if start/stop position does not match agreed alignment.  
  109.     // samples allocated from source pin's allocator may fail  
  110.     // GetPointer until after returning from WaitForNext.  
  111.     STDMETHODIMP Request(  
  112.                      IMediaSample* pSample,  
  113.                      DWORD_PTR dwUser);         // user context  
  114.   
  115.     // block until the next sample is completed or the timeout occurs.  
  116.     // timeout (millisecs) may be 0 or INFINITE. Samples may not  
  117.     // be delivered in order. If there is a read error of any sort, a  
  118.     // notification will already have been sent by the source filter,  
  119.     // and STDMETHODIMP will be an error.  
  120.     STDMETHODIMP WaitForNext(  
  121.                       DWORD dwTimeout,  
  122.                       IMediaSample** ppSample,  // completed sample  
  123.                       DWORD_PTR * pdwUser);     // user context  
  124.   
  125.     // sync read of data. Sample passed in must have been acquired from  
  126.     // the agreed allocator. Start and stop position must be aligned.  
  127.     // equivalent to a Request/WaitForNext pair, but may avoid the  
  128.     // need for a thread on the source filter.  
  129.     STDMETHODIMP SyncReadAligned(  
  130.                       IMediaSample* pSample);  
  131.   
  132.   
  133.     // sync read. works in stopped state as well as run state.  
  134.     // need not be aligned. Will fail if read is beyond actual total  
  135.     // length.  
  136.     STDMETHODIMP SyncRead(  
  137.                       LONGLONG llPosition,  // absolute file position  
  138.                       LONG lLength,         // nr bytes required  
  139.                       BYTE* pBuffer);       // write data here  
  140.   
  141.     // return total length of stream, and currently available length.  
  142.     // reads for beyond the available length but within the total length will  
  143.     // normally succeed but may block for a long period.  
  144.     STDMETHODIMP Length(  
  145.                       LONGLONG* pTotal,  
  146.                       LONGLONG* pAvailable);  
  147.   
  148.     // cause all outstanding reads to return, possibly with a failure code  
  149.     // (VFW_E_TIMEOUT) indicating they were cancelled.  
  150.     // these are defined on IAsyncReader and IPin  
  151.     STDMETHODIMP BeginFlush(void);  
  152.     STDMETHODIMP EndFlush(void);  
  153.   
  154. };  
// CAsyncOutputPin实现了一个输出Pin
// 继承自IAsyncReader、CBasePin,这是对拉模式的Source Filter的基本要求
/* IAsyncReader接口方法及描述如下:
BeginFlush  放弃所有正在进行的数据读取
EndFlush    与BeginFlush配对,标示Flush过程结束
Length      得到数据总长度和当前可以读取的长度
RequestAlloctor 要求一个输入Pin上的Sample管理器
Request     发出一个数据请求
SyncReadAligned 同步读取数据(边界对齐)
SyncRead    同步读取数据
WaitForNext 等待一个请求的完成
======================================================================
可以看出CAsyOutputPin类上实现的IAsyncReader的各个接口方法,都“委托”
给了CAsyncIo类对象的同名成员函数
*/
class CAsyncOutputPin
  : public IAsyncReader, 
    public CBasePin
{
protected:
    CAsyncReader* m_pReader;
    CAsyncIo * m_pIo;

    //  This is set every time we're asked to return an IAsyncReader
    //  interface
    //  This allows us to know if the downstream pin can use
    //  this transport, otherwise we can hook up to thinks like the
    //  dump filter and nothing happens
    BOOL         m_bQueriedForAsyncReader;

    HRESULT InitAllocator(IMemAllocator **ppAlloc);

public:
    // constructor and destructor
    CAsyncOutputPin(
        HRESULT * phr,
        CAsyncReader *pReader,
        CAsyncIo *pIo,
        CCritSec * pLock);

    ~CAsyncOutputPin();

    // --- CUnknown ---

    // need to expose IAsyncReader
    DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**);

    // --- IPin methods ---
    STDMETHODIMP Connect(
        IPin * pReceivePin,
        const AM_MEDIA_TYPE *pmt   // optional media type
    );

    // --- CBasePin methods ---

    // return the types we prefer - this will return the known
    // file type
    HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);

    // can we support this type?
    HRESULT CheckMediaType(const CMediaType* pType);

    // Clear the flag so we see if IAsyncReader is queried for
    HRESULT CheckConnect(IPin *pPin)
    {
        m_bQueriedForAsyncReader = FALSE;
        return CBasePin::CheckConnect(pPin);
    }

    // See if it was asked for
    HRESULT CompleteConnect(IPin *pReceivePin)
    {
        if (m_bQueriedForAsyncReader) {
            return CBasePin::CompleteConnect(pReceivePin);
        } else {

#ifdef VFW_E_NO_TRANSPORT
            return VFW_E_NO_TRANSPORT;
#else
            return E_FAIL;
#endif
        }
    }

    //  Remove our connection status
    HRESULT BreakConnect()
    {
        m_bQueriedForAsyncReader = FALSE;
        return CBasePin::BreakConnect();
    }

    // --- IAsyncReader methods ---
    // pass in your preferred allocator and your preferred properties.
    // method returns the actual allocator to be used. Call GetProperties
    // on returned allocator to learn alignment and prefix etc chosen.
    // this allocator will be not be committed and decommitted by
    // the async reader, only by the consumer.
    STDMETHODIMP RequestAllocator(
                      IMemAllocator* pPreferred,
                      ALLOCATOR_PROPERTIES* pProps,
                      IMemAllocator ** ppActual);

    // queue a request for data.
    // media sample start and stop times contain the requested absolute
    // byte position (start inclusive, stop exclusive).
    // may fail if sample not obtained from agreed allocator.
    // may fail if start/stop position does not match agreed alignment.
    // samples allocated from source pin's allocator may fail
    // GetPointer until after returning from WaitForNext.
    STDMETHODIMP Request(
                     IMediaSample* pSample,
                     DWORD_PTR dwUser);         // user context

    // block until the next sample is completed or the timeout occurs.
    // timeout (millisecs) may be 0 or INFINITE. Samples may not
    // be delivered in order. If there is a read error of any sort, a
    // notification will already have been sent by the source filter,
    // and STDMETHODIMP will be an error.
    STDMETHODIMP WaitForNext(
                      DWORD dwTimeout,
                      IMediaSample** ppSample,  // completed sample
                      DWORD_PTR * pdwUser);     // user context

    // sync read of data. Sample passed in must have been acquired from
    // the agreed allocator. Start and stop position must be aligned.
    // equivalent to a Request/WaitForNext pair, but may avoid the
    // need for a thread on the source filter.
    STDMETHODIMP SyncReadAligned(
                      IMediaSample* pSample);


    // sync read. works in stopped state as well as run state.
    // need not be aligned. Will fail if read is beyond actual total
    // length.
    STDMETHODIMP SyncRead(
                      LONGLONG llPosition,  // absolute file position
                      LONG lLength,         // nr bytes required
                      BYTE* pBuffer);       // write data here

    // return total length of stream, and currently available length.
    // reads for beyond the available length but within the total length will
    // normally succeed but may block for a long period.
    STDMETHODIMP Length(
                      LONGLONG* pTotal,
                      LONGLONG* pAvailable);

    // cause all outstanding reads to return, possibly with a failure code
    // (VFW_E_TIMEOUT) indicating they were cancelled.
    // these are defined on IAsyncReader and IPin
    STDMETHODIMP BeginFlush(void);
    STDMETHODIMP EndFlush(void);

};

 


5、 CBaseInputPin和CBaseOutputPin

 从CBasePin类派生的,也是很基本的输入或输出pin。

它们的实现可参见 amfilter.cpp

CBaseInputPin实现了IMemInputPin(用于推模式的数据传送),

CBaseOutputPin主要完成了传送数据所使用的Sample管理器(Allocator)的协商,并重写了CBasePin::Active(用于实际的Sample内存分配)

以及CBasePin::Inactive(用于Sample内存的释放)

  1. class AM_NOVTABLE CBaseInputPin : public CBasePin,  
  2.                                   public IMemInputPin  
  3. {  
  4.   
  5. protected:  
  6.   
  7.     IMemAllocator *m_pAllocator;    // Default memory allocator  
  8.   
  9.     // allocator is read-only, so received samples  
  10.     // cannot be modified (probably only relevant to in-place  
  11.     // transforms  
  12.     BYTE m_bReadOnly;  
  13.   
  14.     // in flushing state (between BeginFlush and EndFlush)  
  15.     // if TRUE, all Receives are returned with S_FALSE  
  16.     BYTE m_bFlushing;  
  17.   
  18.     // Sample properties - initalized in Receive  
  19.     AM_SAMPLE2_PROPERTIES m_SampleProps;  
  20.   
  21. public:  
  22.   
  23.     CBaseInputPin(  
  24.         TCHAR *pObjectName,  
  25.         CBaseFilter *pFilter,  
  26.         CCritSec *pLock,  
  27.         HRESULT *phr,  
  28.         LPCWSTR pName);  
  29. #ifdef UNICODE  
  30.     CBaseInputPin(  
  31.         CHAR *pObjectName,  
  32.         CBaseFilter *pFilter,  
  33.         CCritSec *pLock,  
  34.         HRESULT *phr,  
  35.         LPCWSTR pName);  
  36. #endif  
  37.     virtual ~CBaseInputPin();  
  38.   
  39.     DECLARE_IUNKNOWN  
  40.   
  41.     // override this to publicise our interfaces  
  42.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);  
  43.   
  44.     // return the allocator interface that this input pin  
  45.     // would like the output pin to use  
  46.     STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);  
  47.   
  48.     // tell the input pin which allocator the output pin is actually  
  49.     // going to use.  
  50.     STDMETHODIMP NotifyAllocator(  
  51.                     IMemAllocator * pAllocator,  
  52.                     BOOL bReadOnly);  
  53.   
  54.     // do something with this media sample  
  55.     STDMETHODIMP Receive(IMediaSample *pSample);  
  56.   
  57.     // do something with these media samples  
  58.     STDMETHODIMP ReceiveMultiple (  
  59.         IMediaSample **pSamples,  
  60.         long nSamples,  
  61.         long *nSamplesProcessed);  
  62.   
  63.     // See if Receive() blocks  
  64.     STDMETHODIMP ReceiveCanBlock();  
  65.   
  66.     // Default handling for BeginFlush - call at the beginning  
  67.     // of your implementation (makes sure that all Receive calls  
  68.     // fail). After calling this, you need to free any queued data  
  69.     // and then call downstream.  
  70.     STDMETHODIMP BeginFlush(void);  
  71.   
  72.     // default handling for EndFlush - call at end of your implementation  
  73.     // - before calling this, ensure that there is no queued data and no thread  
  74.     // pushing any more without a further receive, then call downstream,  
  75.     // then call this method to clear the m_bFlushing flag and re-enable  
  76.     // receives  
  77.     STDMETHODIMP EndFlush(void);  
  78.   
  79.     // this method is optional (can return E_NOTIMPL).  
  80.     // default implementation returns E_NOTIMPL. Override if you have  
  81.     // specific alignment or prefix needs, but could use an upstream  
  82.     // allocator  
  83.     STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps);  
  84.   
  85.     // Release the pin's allocator.  
  86.     HRESULT BreakConnect();  
  87.   
  88.     // helper method to check the read-only flag  
  89.     BOOL IsReadOnly() {  
  90.         return m_bReadOnly;  
  91.     };  
  92.   
  93.     // helper method to see if we are flushing  
  94.     BOOL IsFlushing() {  
  95.         return m_bFlushing;  
  96.     };  
  97.   
  98.     //  Override this for checking whether it's OK to process samples  
  99.     //  Also call this from EndOfStream.  
  100.     virtual HRESULT CheckStreaming();  
  101.   
  102.     // Pass a Quality notification on to the appropriate sink  
  103.     HRESULT PassNotify(Quality& q);  
  104.   
  105.   
  106.     //================================================================================  
  107.     // IQualityControl methods (from CBasePin)  
  108.     //================================================================================  
  109.   
  110.     STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);  
  111.   
  112.     // no need to override:  
  113.     // STDMETHODIMP SetSink(IQualityControl * piqc);  
  114.   
  115.   
  116.     // switch the pin to inactive state - may already be inactive  
  117.     virtual HRESULT Inactive(void);  
  118.   
  119.     // Return sample properties pointer  
  120.     AM_SAMPLE2_PROPERTIES * SampleProps() {  
  121.         ASSERT(m_SampleProps.cbData != 0);  
  122.         return &m_SampleProps;  
  123.     }  
  124.   
  125. };  
class AM_NOVTABLE CBaseInputPin : public CBasePin,
                                  public IMemInputPin
{

protected:

    IMemAllocator *m_pAllocator;    // Default memory allocator

    // allocator is read-only, so received samples
    // cannot be modified (probably only relevant to in-place
    // transforms
    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;

public:

    CBaseInputPin(
        TCHAR *pObjectName,
        CBaseFilter *pFilter,
        CCritSec *pLock,
        HRESULT *phr,
        LPCWSTR pName);
#ifdef UNICODE
    CBaseInputPin(
        CHAR *pObjectName,
        CBaseFilter *pFilter,
        CCritSec *pLock,
        HRESULT *phr,
        LPCWSTR pName);
#endif
    virtual ~CBaseInputPin();

    DECLARE_IUNKNOWN

    // override this to publicise our interfaces
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);

    // return the allocator interface that this input pin
    // would like the output pin to use
    STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);

    // tell the input pin which allocator the output pin is actually
    // going to use.
    STDMETHODIMP NotifyAllocator(
                    IMemAllocator * pAllocator,
                    BOOL bReadOnly);

    // do something with this media sample
    STDMETHODIMP Receive(IMediaSample *pSample);

    // do something with these media samples
    STDMETHODIMP ReceiveMultiple (
        IMediaSample **pSamples,
        long nSamples,
        long *nSamplesProcessed);

    // See if Receive() blocks
    STDMETHODIMP ReceiveCanBlock();

    // Default handling for BeginFlush - call at the beginning
    // of your implementation (makes sure that all Receive calls
    // fail). After calling this, you need to free any queued data
    // and then call downstream.
    STDMETHODIMP BeginFlush(void);

    // default handling for EndFlush - call at end of your implementation
    // - before calling this, ensure that there is no queued data and no thread
    // pushing any more without a further receive, then call downstream,
    // then call this method to clear the m_bFlushing flag and re-enable
    // receives
    STDMETHODIMP EndFlush(void);

    // this method is optional (can return E_NOTIMPL).
    // 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);

    // Release the pin's allocator.
    HRESULT BreakConnect();

    // helper method to check the read-only flag
    BOOL IsReadOnly() {
        return m_bReadOnly;
    };

    // helper method to see if we are flushing
    BOOL IsFlushing() {
        return m_bFlushing;
    };

    //  Override this for checking whether it's OK to process samples
    //  Also call this from EndOfStream.
    virtual HRESULT CheckStreaming();

    // Pass a Quality notification on to the appropriate sink
    HRESULT PassNotify(Quality& q);


    //================================================================================
    // IQualityControl methods (from CBasePin)
    //================================================================================

    STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);

    // no need to override:
    // STDMETHODIMP SetSink(IQualityControl * piqc);


    // switch the pin to inactive state - may already be inactive
    virtual HRESULT Inactive(void);

    // Return sample properties pointer
    AM_SAMPLE2_PROPERTIES * SampleProps() {
        ASSERT(m_SampleProps.cbData != 0);
        return &m_SampleProps;
    }

};

 


 

 

  1. class  AM_NOVTABLE CBaseOutputPin : public CBasePin  
  2. {  
  3.   
  4. protected:  
  5.   
  6.     IMemAllocator *m_pAllocator;  
  7.     IMemInputPin *m_pInputPin;        // interface on the downstreaminput pin  
  8.                                       // set up in CheckConnect when we connect.  
  9.   
  10. public:  
  11.   
  12.     CBaseOutputPin(  
  13.         TCHAR *pObjectName,  
  14.         CBaseFilter *pFilter,  
  15.         CCritSec *pLock,  
  16.         HRESULT *phr,  
  17.         LPCWSTR pName);  
  18. #ifdef UNICODE  
  19.     CBaseOutputPin(  
  20.         CHAR *pObjectName,  
  21.         CBaseFilter *pFilter,  
  22.         CCritSec *pLock,  
  23.         HRESULT *phr,  
  24.         LPCWSTR pName);  
  25. #endif  
  26.     // override CompleteConnect() so we can negotiate an allocator  
  27.     virtual HRESULT CompleteConnect(IPin *pReceivePin);  
  28.   
  29.     // negotiate the allocator and its buffer size/count and other properties  
  30.     // Calls DecideBufferSize to set properties  
  31.     virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);  
  32.   
  33.     // override this to set the buffer size and count. Return an error  
  34.     // if the size/count is not to your liking.  
  35.     // The allocator properties passed in are those requested by the  
  36.     // input pin - use eg the alignment and prefix members if you have  
  37.     // no preference on these.  
  38.     virtual HRESULT DecideBufferSize(  
  39.         IMemAllocator * pAlloc,  
  40.         ALLOCATOR_PROPERTIES * ppropInputRequest  
  41.     ) PURE;  
  42.   
  43.     // returns an empty sample buffer from the allocator  
  44.     virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample,  
  45.                                       REFERENCE_TIME * pStartTime,  
  46.                                       REFERENCE_TIME * pEndTime,  
  47.                                       DWORD dwFlags);  
  48.   
  49.     // deliver a filled-in sample to the connected input pin  
  50.     // note - you need to release it after calling this. The receiving  
  51.     // pin will addref the sample if it needs to hold it beyond the  
  52.     // call.  
  53.     virtual HRESULT Deliver(IMediaSample *);  
  54.   
  55.     // override this to control the connection  
  56.     virtual HRESULT InitAllocator(IMemAllocator **ppAlloc);  
  57.     HRESULT CheckConnect(IPin *pPin);  
  58.     HRESULT BreakConnect();  
  59.   
  60.     // override to call Commit and Decommit  
  61.     HRESULT Active(void);  
  62.     HRESULT Inactive(void);  
  63.   
  64.     // we have a default handling of EndOfStream which is to return  
  65.     // an error, since this should be called on input pins only  
  66.     STDMETHODIMP EndOfStream(void);  
  67.   
  68.     // called from elsewhere in our filter to pass EOS downstream to  
  69.     // our connected input pin  
  70.     virtual HRESULT DeliverEndOfStream(void);  
  71.   
  72.     // same for Begin/EndFlush - we handle Begin/EndFlush since it  
  73.     // is an error on an output pin, and we have Deliver methods to  
  74.     // call the methods on the connected pin  
  75.     STDMETHODIMP BeginFlush(void);  
  76.     STDMETHODIMP EndFlush(void);  
  77.     virtual HRESULT DeliverBeginFlush(void);  
  78.     virtual HRESULT DeliverEndFlush(void);  
  79.   
  80.     // deliver NewSegment to connected pin - you will need to  
  81.     // override this if you queue any data in your output pin.  
  82.     virtual HRESULT DeliverNewSegment(  
  83.                         REFERENCE_TIME tStart,  
  84.                         REFERENCE_TIME tStop,  
  85.                         double dRate);  
  86.   
  87.     //================================================================================  
  88.     // IQualityControl methods  
  89.     //================================================================================  
  90.   
  91.     // All inherited from CBasePin and not overridden here.  
  92.     // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);  
  93.     // STDMETHODIMP SetSink(IQualityControl * piqc);  
  94. };  
class  AM_NOVTABLE CBaseOutputPin : public CBasePin
{

protected:

    IMemAllocator *m_pAllocator;
    IMemInputPin *m_pInputPin;        // interface on the downstreaminput pin
                                      // set up in CheckConnect when we connect.

public:

    CBaseOutputPin(
        TCHAR *pObjectName,
        CBaseFilter *pFilter,
        CCritSec *pLock,
        HRESULT *phr,
        LPCWSTR pName);
#ifdef UNICODE
    CBaseOutputPin(
        CHAR *pObjectName,
        CBaseFilter *pFilter,
        CCritSec *pLock,
        HRESULT *phr,
        LPCWSTR pName);
#endif
    // override CompleteConnect() so we can negotiate an allocator
    virtual HRESULT CompleteConnect(IPin *pReceivePin);

    // negotiate the allocator and its buffer size/count and other properties
    // Calls DecideBufferSize to set properties
    virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);

    // override this to set the buffer size and count. Return an error
    // if the size/count is not to your liking.
    // The allocator properties passed in are those requested by the
    // input pin - use eg the alignment and prefix members if you have
    // no preference on these.
    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);

    // deliver a filled-in sample to the connected input pin
    // note - you need to release it after calling this. The receiving
    // pin will addref the sample if it needs to hold it beyond the
    // call.
    virtual HRESULT Deliver(IMediaSample *);

    // override this to control the connection
    virtual HRESULT InitAllocator(IMemAllocator **ppAlloc);
    HRESULT CheckConnect(IPin *pPin);
    HRESULT BreakConnect();

    // override to call Commit and Decommit
    HRESULT Active(void);
    HRESULT Inactive(void);

    // we have a default handling of EndOfStream which is to return
    // an error, since this should be called on input pins only
    STDMETHODIMP EndOfStream(void);

    // called from elsewhere in our filter to pass EOS downstream to
    // our connected input pin
    virtual HRESULT DeliverEndOfStream(void);

    // same for Begin/EndFlush - we handle Begin/EndFlush since it
    // is an error on an output pin, and we have Deliver methods to
    // call the methods on the connected pin
    STDMETHODIMP BeginFlush(void);
    STDMETHODIMP EndFlush(void);
    virtual HRESULT DeliverBeginFlush(void);
    virtual HRESULT DeliverEndFlush(void);

    // deliver NewSegment to connected pin - you will need to
    // override this if you queue any data in your output pin.
    virtual HRESULT DeliverNewSegment(
                        REFERENCE_TIME tStart,
                        REFERENCE_TIME tStop,
                        double dRate);

    //================================================================================
    // IQualityControl methods
    //================================================================================

    // All inherited from CBasePin and not overridden here.
    // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
    // STDMETHODIMP SetSink(IQualityControl * piqc);
};

 


 CBaseInputPin类的使用方法(派生一个子类,并且至少需要重写以下函数)如下:

(1) CBaseInputPin::BeginFlush

(2) CBaseInputPin::EndFlush

(3) CBaseInputPin::Receive

(4) CBaseInputPin::CheckMediaType

(5) CBaseInputPin::GetMediaType

eg:

  1. class CRendererInputPin : public CBaseInputPin  
  2. {  
  3. protected:  
  4.   
  5.     CBaseRenderer *m_pRenderer;  
  6.   
  7. public:  
  8.   
  9.     CRendererInputPin(CBaseRenderer *pRenderer,  
  10.                       HRESULT *phr,  
  11.                       LPCWSTR Name);  
  12.   
  13.     // Overriden from the base pin classes  
  14.   
  15.     HRESULT BreakConnect();  
  16.     HRESULT CompleteConnect(IPin *pReceivePin);  
  17.     HRESULT SetMediaType(const CMediaType *pmt);  
  18.     HRESULT CheckMediaType(const CMediaType *pmt);  
  19.     HRESULT Active();  
  20.     HRESULT Inactive();  
  21.   
  22.     // Add rendering behaviour to interface functions  
  23.   
  24.     STDMETHODIMP QueryId(LPWSTR *Id);  
  25.     STDMETHODIMP EndOfStream();  
  26.     STDMETHODIMP BeginFlush();  
  27.     STDMETHODIMP EndFlush();  
  28.     STDMETHODIMP Receive(IMediaSample *pMediaSample);  
  29.   
  30.     // Helper  
  31.     IMemAllocator inline *Allocator() const  
  32.     {  
  33.         return m_pAllocator;  
  34.     }  
  35. };  
class CRendererInputPin : public CBaseInputPin
{
protected:

    CBaseRenderer *m_pRenderer;

public:

    CRendererInputPin(CBaseRenderer *pRenderer,
                      HRESULT *phr,
                      LPCWSTR Name);

    // Overriden from the base pin classes

    HRESULT BreakConnect();
    HRESULT CompleteConnect(IPin *pReceivePin);
    HRESULT SetMediaType(const CMediaType *pmt);
    HRESULT CheckMediaType(const CMediaType *pmt);
    HRESULT Active();
    HRESULT Inactive();

    // Add rendering behaviour to interface functions

    STDMETHODIMP QueryId(LPWSTR *Id);
    STDMETHODIMP EndOfStream();
    STDMETHODIMP BeginFlush();
    STDMETHODIMP EndFlush();
    STDMETHODIMP Receive(IMediaSample *pMediaSample);

    // Helper
    IMemAllocator inline *Allocator() const
    {
        return m_pAllocator;
    }
};

 


 

CBaseOutputPin类的使用方法(派生一个子类,并且最少需要重写以下函数)如下:

(1) 重写CBasePin::CheckMediaType进行连接时媒体类型的检查;

(2) 实现纯虚函数CBaseOutputPin::DecideBufferSize,决定Sample内存的大小;

(3) 重写CBasePin::GetMediaType, 提供Pin 上的首选媒体类型。

 

  1. class CTransformOutputPin : public CBaseOutputPin  
  2. {  
  3.     friend class CTransformFilter;  
  4.   
  5. protected:  
  6.     CTransformFilter *m_pTransformFilter;  
  7.   
  8. public:  
  9.   
  10.     // implement IMediaPosition by passing upstream  
  11.     IUnknown * m_pPosition;  
  12.   
  13.     CTransformOutputPin(  
  14.         TCHAR *pObjectName,  
  15.         CTransformFilter *pTransformFilter,  
  16.         HRESULT * phr,  
  17.         LPCWSTR pName);  
  18. #ifdef UNICODE  
  19.     CTransformOutputPin(  
  20.         CHAR *pObjectName,  
  21.         CTransformFilter *pTransformFilter,  
  22.         HRESULT * phr,  
  23.         LPCWSTR pName);  
  24. #endif  
  25.     ~CTransformOutputPin();  
  26.   
  27.     // override to expose IMediaPosition  
  28.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);  
  29.   
  30.     // --- CBaseOutputPin ------------  
  31.   
  32.     STDMETHODIMP QueryId(LPWSTR * Id)  
  33.     {  
  34.         return AMGetWideString(L"Out", Id);  
  35.     }  
  36.   
  37.     // Grab and release extra interfaces if required  
  38.   
  39.     HRESULT CheckConnect(IPin *pPin);  
  40.     HRESULT BreakConnect();  
  41.     HRESULT CompleteConnect(IPin *pReceivePin);  
  42.   
  43.     // check that we can support this output type  
  44.     HRESULT CheckMediaType(const CMediaType* mtOut);  
  45.   
  46.     // set the connection media type  
  47.     HRESULT SetMediaType(const CMediaType *pmt);  
  48.   
  49.     // called from CBaseOutputPin during connection to ask for  
  50.     // the count and size of buffers we need.  
  51.     HRESULT DecideBufferSize(  
  52.                 IMemAllocator * pAlloc,  
  53.                 ALLOCATOR_PROPERTIES *pProp);  
  54.   
  55.     // returns the preferred formats for a pin  
  56.     HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);  
  57.   
  58.     // inherited from IQualityControl via CBasePin  
  59.     STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);  
  60.   
  61.     // Media type  
  62. public:  
  63.     CMediaType& CurrentMediaType() { return m_mt; };  
  64. };  
class CTransformOutputPin : public CBaseOutputPin
{
    friend class CTransformFilter;

protected:
    CTransformFilter *m_pTransformFilter;

public:

    // implement IMediaPosition by passing upstream
    IUnknown * m_pPosition;

    CTransformOutputPin(
        TCHAR *pObjectName,
        CTransformFilter *pTransformFilter,
        HRESULT * phr,
        LPCWSTR pName);
#ifdef UNICODE
    CTransformOutputPin(
        CHAR *pObjectName,
        CTransformFilter *pTransformFilter,
        HRESULT * phr,
        LPCWSTR pName);
#endif
    ~CTransformOutputPin();

    // override to expose IMediaPosition
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);

    // --- CBaseOutputPin ------------

    STDMETHODIMP QueryId(LPWSTR * Id)
    {
        return AMGetWideString(L"Out", Id);
    }

    // Grab and release extra interfaces if required

    HRESULT CheckConnect(IPin *pPin);
    HRESULT BreakConnect();
    HRESULT CompleteConnect(IPin *pReceivePin);

    // check that we can support this output type
    HRESULT CheckMediaType(const CMediaType* mtOut);

    // set the connection media type
    HRESULT SetMediaType(const CMediaType *pmt);

    // called from CBaseOutputPin during connection to ask for
    // the count and size of buffers we need.
    HRESULT DecideBufferSize(
                IMemAllocator * pAlloc,
                ALLOCATOR_PROPERTIES *pProp);

    // returns the preferred formats for a pin
    HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);

    // inherited from IQualityControl via CBasePin
    STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);

    // Media type
public:
    CMediaType& CurrentMediaType() { return m_mt; };
};

 


 ===================================================================

如果开发的是一个Transform Filter,Filter的父类很多时候都是选择CTransformFilter或CTransInPlaceFilter,这种Filter的开发相对简单。

但有时,Filter框架不得不选择CBaseFilter、 CBaseInputPin、CBaseOutputFilter等类来实现,这就有点麻烦了。

这时候可以参考CTransformFilter、CTransformInputPin、CTransformOutputPin对上述3上基类的使用,以此来指导Filter的开发。

 ===================================================================

6、 CSource

DirectShow SDK还提供了其他更加实用的Filter类,如:

CSource、CTransformFilter、CTransInPlaceFilter、CVideoTransformFilter、 CBaseRender、CBase Video Render等。

它们的继承关系如图:

如上图所示,CSource类(参见source.cpp的实现)直接从CaseFilter中继承而来,一般作为推模式Source Filter的父类

CSource类的使用方法如下:

(1)从CSource类中派生一个新的Filter类;

(2)在新的Filter类的构造函数中创建各个CSourceStream类实例(CSourceStream类的构造函数会自动将该Pin加入Filter中,并在析构函数中自动删除);

(3)使用CSource::pStateLock函数返回的同步对象进行Filter对象上的多线程同步。

注意: 使用CSource作为Filter父类的Filter未必就是Source Filter。在有些开发Transform Filter的应用中,输出Pin需要使用独立的线程。(即与输入Pin上传送数据

              不同的线程)传关,也可以考虑使用CSource。

eg: 参照我的另一篇文章:  

  1. class CPushSourceBitmap : public CSource  
  2. {  
  3.   
  4. private:  
  5.     // Constructor is private because you have to use CreateInstance  
  6.     CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr);  
  7.     ~CPushSourceBitmap();  
  8.   
  9.     CPushPinBitmap *m_pPin;  
  10.   
  11. public:  
  12.     static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);    
  13.   
  14. };  
class CPushSourceBitmap : public CSource
{

private:
    // Constructor is private because you have to use CreateInstance
    CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr);
    ~CPushSourceBitmap();

    CPushPinBitmap *m_pPin;

public:
    static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);  

};

 

 

  1. CPushSourceBitmap::CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr)  
  2.            : CSource(NAME("PushSourceBitmap"), pUnk, CLSID_PushSourceBitmap)  
  3. {  
  4.     // The pin magically adds itself to our pin array.  
  5.     m_pPin = new CPushPinBitmap(phr, this);  
  6.   
  7.     if (phr)  
  8.     {  
  9.         if (m_pPin == NULL)  
  10.             *phr = E_OUTOFMEMORY;  
  11.         else  
  12.             *phr = S_OK;  
  13.     }    
  14. }  
CPushSourceBitmap::CPushSourceBitmap(IUnknown *pUnk, HRESULT *phr)
           : CSource(NAME("PushSourceBitmap"), pUnk, CLSID_PushSourceBitmap)
{
    // The pin magically adds itself to our pin array.
    m_pPin = new CPushPinBitmap(phr, this);

    if (phr)
    {
        if (m_pPin == NULL)
            *phr = E_OUTOFMEMORY;
        else
            *phr = S_OK;
    }  
}

 


7 、  CSourceStream

CSource实际上继承自CBaseFilter,提供了一个“推”数据的能力,这种Filter至少有一个输出

Pin采用了CSourecStream类(或CSourceStream的子类)。如下图所示:

CSourceStream上实现了一个线程(CSourceStream从CAMThread类继承而来),Sample数据就是靠这个线程向一线Filter发送的。

CSourceStream类的使用方法如下:

(1)从CSourceStream派生一个输出Pin类;

(2)重写CSourceStream::GetMediaType,提供输出Pin上的首选媒体类型;

(3)重写CSourceStream::CheckMediaType,进行连续时媒体类型的检查;(可选

(4)实现CBaseOutPin::DecideBufferSize,决定Sample内存的大小;

(5)实现CSourceStream::FillBuffer,为即将传送出去的Sample 填充数据;

(6)可选地实现CSourceStream::OnThreadCreate、CSourceSream::OnThreadDestroy、CSourceStream::OnThreadStartPlay等函数,

进行适当时节的初始化、资源管理等操作。

eg: 参照我的另一篇文章:  

  1. class CPushPinBitmap : public CSourceStream  
  2. {  
  3. protected:  
  4.   
  5.     int m_FramesWritten;                // To track where we are in the file  
  6.     BOOL m_bZeroMemory;                 // Do we need to clear the buffer?  
  7.     CRefTime m_rtSampleTime;            // The time stamp for each sample  
  8.   
  9.     BITMAPINFO *m_pBmi;                 // Pointer to the bitmap header  
  10.     DWORD       m_cbBitmapInfo;         // Size of the bitmap header  
  11.       
  12.     // File opening variables   
  13.     HANDLE m_hFile;                     // Handle returned from CreateFile  
  14.     BYTE * m_pFile;                     // Points to beginning of file buffer  
  15.     BYTE * m_pImage;                    // Points to pixel bits                                        
  16.   
  17.     int m_iFrameNumber;  
  18.     const REFERENCE_TIME m_rtFrameLength;  
  19.   
  20.     CCritSec m_cSharedState;            // Protects our internal state  
  21.     CImageDisplay m_Display;            // Figures out our media type for us  
  22.   
  23. public:  
  24.   
  25.     CPushPinBitmap(HRESULT *phr, CSource *pFilter);  
  26.     ~CPushPinBitmap();  
  27.   
  28.     // Override the version that offers exactly one media type  
  29.     HRESULT GetMediaType(CMediaType *pMediaType);  
  30.     HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);  
  31.     HRESULT FillBuffer(IMediaSample *pSample);  
  32.       
  33.     // Quality control  
  34.     // Not implemented because we aren't going in real time.  
  35.     // If the file-writing filter slows the graph down, we just do nothing, which means  
  36.     // wait until we're unblocked. No frames are ever dropped.  
  37.     STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)  
  38.     {  
  39.         return E_FAIL;  
  40.     }  
  41.   
  42. };  
class CPushPinBitmap : public CSourceStream
{
protected:

    int m_FramesWritten;				// To track where we are in the file
    BOOL m_bZeroMemory;                 // Do we need to clear the buffer?
    CRefTime m_rtSampleTime;	        // The time stamp for each sample

    BITMAPINFO *m_pBmi;                 // Pointer to the bitmap header
    DWORD       m_cbBitmapInfo;         // Size of the bitmap header
	
	// File opening variables 
	HANDLE m_hFile;                     // Handle returned from CreateFile
    BYTE * m_pFile;                     // Points to beginning of file buffer
	BYTE * m_pImage;                    // Points to pixel bits                                      

    int m_iFrameNumber;
    const REFERENCE_TIME m_rtFrameLength;

    CCritSec m_cSharedState;            // Protects our internal state
    CImageDisplay m_Display;            // Figures out our media type for us

public:

    CPushPinBitmap(HRESULT *phr, CSource *pFilter);
    ~CPushPinBitmap();

    // Override the version that offers exactly one media type
    HRESULT GetMediaType(CMediaType *pMediaType);
    HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest);
    HRESULT FillBuffer(IMediaSample *pSample);
    
    // Quality control
	// Not implemented because we aren't going in real time.
	// If the file-writing filter slows the graph down, we just do nothing, which means
	// wait until we're unblocked. No frames are ever dropped.
    STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
    {
        return E_FAIL;
    }

};

 


8、 CTransformFilter

 CTransformFilter类是开发Transform Filter最基本的类,也是最常用到的类。结构如下:

它有一个输入Pin和一个输出Pin,分别使用CTransformInputPin类和CTransformOutputPin类。

 

从图4.8和图4.9可以看出,

CTransformFilter从CBaseFilter继承而来,

CTransformInputPin从CBaseInputPin继承而来,

CTransformOutputPin从CBaseOutputPin继承而来。另个,在CTransformOutputPin上还实现了IMdiaSeeking 和 IMediaPosition接口。

(其实,CTransformOutputPin并没有真正实现各个Seek操作。在实际的Seek操作请发生时,CTransformOutpPin会将这些操作请求转发给上一级Filter的输出Pin)。

CTransformFilter实现的最大特征是,它将Pin上必须实现的函数都“委托”到了Filter上(Pin上必须实现的函数在Filter上有类似的函数定义)。

一般无须重写输入和输出Pin类,而只须在Filter上实现相应的函数就行了)。

提示:CTransformFilter默认在GetPin函数实现中创建输入和输出Pin。因此,如果重写了自己的输入或输出Pin类,需要重写GetPin函数。

CTransformFilter类的使用方法(派生一个Filter子类,且最少需要重写以下函数):

(1)CTransformFilter::CheckInputType

(2)CTransformFilter::CheckTransform

(3)CTransformFilter::DecideBufferSize

(4)CTransformFilter::GetMeiaType

(5)CTransformFilter::Transform

eg:CVideoTransformFilter虽然没有实现上面五个函数,但CVideoTransformFilter 的继承类去实现它们。

  1. class CVideoTransformFilter : public CTransformFilter  
  2. {  
  3.   public:  
  4.   
  5.     CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);  
  6.     ~CVideoTransformFilter();  
  7.     HRESULT EndFlush();  
  8.   
  9.     // =================================================================  
  10.     // ----- override these bits ---------------------------------------  
  11.     // =================================================================  
  12.     // The following methods are in CTransformFilter which is inherited.  
  13.     // They are mentioned here for completeness  
  14.     //  
  15.     // These MUST be supplied in a derived class  
  16.     //  
  17.     // NOTE:  
  18.     // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);  
  19.     // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;  
  20.     // virtual HRESULT CheckTransform  
  21.     //     (const CMediaType* mtIn, const CMediaType* mtOut) PURE;  
  22.     // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);  
  23.     // virtual HRESULT DecideBufferSize  
  24.     //     (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;  
  25.     // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;  
  26.     //  
  27.     // These MAY also be overridden  
  28.     //  
  29.     // virtual HRESULT StopStreaming();  
  30.     // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);  
  31.     // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);  
  32.     // virtual HRESULT BreakConnect(PIN_DIRECTION dir);  
  33.     // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);  
  34.     // virtual HRESULT EndOfStream(void);  
  35.     // virtual HRESULT BeginFlush(void);  
  36.     // virtual HRESULT EndFlush(void);  
  37.     // virtual HRESULT NewSegment  
  38.     //     (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);  
  39. #ifdef PERF  
  40.   
  41.     // If you override this - ensure that you register all these ids  
  42.     // as well as any of your own,  
  43.     virtual void RegisterPerfId() {  
  44.         m_idSkip        = MSR_REGISTER(TEXT("Video Transform Skip frame"));  
  45.         m_idFrameType   = MSR_REGISTER(TEXT("Video transform frame type"));  
  46.         m_idLate        = MSR_REGISTER(TEXT("Video Transform Lateness"));  
  47.         m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));  
  48.         CTransformFilter::RegisterPerfId();  
  49.     }  
  50. #endif  
  51.   
  52.   protected:  
  53.   
  54.     // =========== QUALITY MANAGEMENT IMPLEMENTATION ========================  
  55.     // Frames are assumed to come in three types:  
  56.     // Type 1: an AVI key frame or an MPEG I frame.  
  57.     //        This frame can be decoded with no history.  
  58.     //        Dropping this frame means that no further frame can be decoded  
  59.     //        until the next type 1 frame.  
  60.     //        Type 1 frames are sync points.  
  61.     // Type 2: an AVI non-key frame or an MPEG P frame.  
  62.     //        This frame cannot be decoded unless the previous type 1 frame was  
  63.     //        decoded and all type 2 frames since have been decoded.  
  64.     //        Dropping this frame means that no further frame can be decoded  
  65.     //        until the next type 1 frame.  
  66.     // Type 3: An MPEG B frame.  
  67.     //        This frame cannot be decoded unless the previous type 1 or 2 frame  
  68.     //        has been decoded AND the subsequent type 1 or 2 frame has also  
  69.     //        been decoded.  (This requires decoding the frames out of sequence).  
  70.     //        Dropping this frame affects no other frames.  This implementation  
  71.     //        does not allow for these.  All non-sync-point frames are treated  
  72.     //        as being type 2.  
  73.     //  
  74.     // The spacing of frames of type 1 in a file is not guaranteed.  There MUST  
  75.     // be a type 1 frame at (well, near) the start of the file in order to start  
  76.     // decoding at all.  After that there could be one every half second or so,  
  77.     // there could be one at the start of each scene (aka "cut", "shot") or  
  78.     // there could be no more at all.  
  79.     // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED  
  80.     // without losing all the rest of the movie.  There is no way to tell whether  
  81.     // this is the case, so we find that we are in the gambling business.  
  82.     // To try to improve the odds, we record the greatest interval between type 1s  
  83.     // that we have seen and we bet on things being no worse than this in the  
  84.     // future.  
  85.   
  86.     // You can tell if it's a type 1 frame by calling IsSyncPoint().  
  87.     // there is no architected way to test for a type 3, so you should override  
  88.     // the quality management here if you have B-frames.  
  89.   
  90.     int m_nKeyFramePeriod; // the largest observed interval between type 1 frames  
  91.                            // 1 means every frame is type 1, 2 means every other.  
  92.   
  93.     int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.  
  94.                                 // becomes the new m_nKeyFramePeriod if greater.  
  95.   
  96.     BOOL m_bSkipping;           // we are skipping to the next type 1 frame  
  97.   
  98. #ifdef PERF  
  99.     int m_idFrameType;          // MSR id Frame type.  1=Key, 2="non-key"  
  100.     int m_idSkip;               // MSR id skipping  
  101.     int m_idLate;               // MSR id lateness  
  102.     int m_idTimeTillKey;        // MSR id for guessed time till next key frame.  
  103. #endif  
  104.   
  105.     virtual HRESULT StartStreaming();  
  106.   
  107.     HRESULT AbortPlayback(HRESULT hr);  // if something bad happens  
  108.   
  109.     HRESULT Receive(IMediaSample *pSample);  
  110.   
  111.     HRESULT AlterQuality(Quality q);  
  112.   
  113.     BOOL ShouldSkipFrame(IMediaSample * pIn);  
  114.   
  115.     int m_itrLate;              // lateness from last Quality message  
  116.                                 // (this overflows at 214 secs late).  
  117.     int m_tDecodeStart;         // timeGetTime when decode started.  
  118.     int m_itrAvgDecode;         // Average decode time in reference units.  
  119.   
  120.     BOOL m_bNoSkip;             // debug - no skipping.  
  121.   
  122.     // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.  
  123.     // We send one when we start degrading, not one for every frame, this means  
  124.     // we track whether we've sent one yet.  
  125.     BOOL m_bQualityChanged;  
  126.   
  127.     // When non-zero, don't pass anything to renderer until next keyframe  
  128.     // If there are few keys, give up and eventually draw something  
  129.     int m_nWaitForKey;  
  130. };  
class CVideoTransformFilter : public CTransformFilter
{
  public:

    CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
    ~CVideoTransformFilter();
    HRESULT EndFlush();

    // =================================================================
    // ----- override these bits ---------------------------------------
    // =================================================================
    // The following methods are in CTransformFilter which is inherited.
    // They are mentioned here for completeness
    //
    // These MUST be supplied in a derived class
    //
    // NOTE:
    // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
    // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
    // virtual HRESULT CheckTransform
    //     (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
    // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
    // virtual HRESULT DecideBufferSize
    //     (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
    // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
    //
    // These MAY also be overridden
    //
    // virtual HRESULT StopStreaming();
    // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
    // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
    // virtual HRESULT BreakConnect(PIN_DIRECTION dir);
    // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
    // virtual HRESULT EndOfStream(void);
    // virtual HRESULT BeginFlush(void);
    // virtual HRESULT EndFlush(void);
    // virtual HRESULT NewSegment
    //     (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
#ifdef PERF

    // If you override this - ensure that you register all these ids
    // as well as any of your own,
    virtual void RegisterPerfId() {
        m_idSkip        = MSR_REGISTER(TEXT("Video Transform Skip frame"));
        m_idFrameType   = MSR_REGISTER(TEXT("Video transform frame type"));
        m_idLate        = MSR_REGISTER(TEXT("Video Transform Lateness"));
        m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));
        CTransformFilter::RegisterPerfId();
    }
#endif

  protected:

    // =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
    // Frames are assumed to come in three types:
    // Type 1: an AVI key frame or an MPEG I frame.
    //        This frame can be decoded with no history.
    //        Dropping this frame means that no further frame can be decoded
    //        until the next type 1 frame.
    //        Type 1 frames are sync points.
    // Type 2: an AVI non-key frame or an MPEG P frame.
    //        This frame cannot be decoded unless the previous type 1 frame was
    //        decoded and all type 2 frames since have been decoded.
    //        Dropping this frame means that no further frame can be decoded
    //        until the next type 1 frame.
    // Type 3: An MPEG B frame.
    //        This frame cannot be decoded unless the previous type 1 or 2 frame
    //        has been decoded AND the subsequent type 1 or 2 frame has also
    //        been decoded.  (This requires decoding the frames out of sequence).
    //        Dropping this frame affects no other frames.  This implementation
    //        does not allow for these.  All non-sync-point frames are treated
    //        as being type 2.
    //
    // The spacing of frames of type 1 in a file is not guaranteed.  There MUST
    // be a type 1 frame at (well, near) the start of the file in order to start
    // decoding at all.  After that there could be one every half second or so,
    // there could be one at the start of each scene (aka "cut", "shot") or
    // there could be no more at all.
    // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
    // without losing all the rest of the movie.  There is no way to tell whether
    // this is the case, so we find that we are in the gambling business.
    // To try to improve the odds, we record the greatest interval between type 1s
    // that we have seen and we bet on things being no worse than this in the
    // future.

    // You can tell if it's a type 1 frame by calling IsSyncPoint().
    // there is no architected way to test for a type 3, so you should override
    // the quality management here if you have B-frames.

    int m_nKeyFramePeriod; // the largest observed interval between type 1 frames
                           // 1 means every frame is type 1, 2 means every other.

    int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.
                                // becomes the new m_nKeyFramePeriod if greater.

    BOOL m_bSkipping;           // we are skipping to the next type 1 frame

#ifdef PERF
    int m_idFrameType;          // MSR id Frame type.  1=Key, 2="non-key"
    int m_idSkip;               // MSR id skipping
    int m_idLate;               // MSR id lateness
    int m_idTimeTillKey;        // MSR id for guessed time till next key frame.
#endif

    virtual HRESULT StartStreaming();

    HRESULT AbortPlayback(HRESULT hr);	// if something bad happens

    HRESULT Receive(IMediaSample *pSample);

    HRESULT AlterQuality(Quality q);

    BOOL ShouldSkipFrame(IMediaSample * pIn);

    int m_itrLate;              // lateness from last Quality message
                                // (this overflows at 214 secs late).
    int m_tDecodeStart;         // timeGetTime when decode started.
    int m_itrAvgDecode;         // Average decode time in reference units.

    BOOL m_bNoSkip;             // debug - no skipping.

    // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
    // We send one when we start degrading, not one for every frame, this means
    // we track whether we've sent one yet.
    BOOL m_bQualityChanged;

    // When non-zero, don't pass anything to renderer until next keyframe
    // If there are few keys, give up and eventually draw something
    int m_nWaitForKey;
};

 


 

9、 CTransInPlaceFilter

CTransInPlaceFilter是一个“就地”处理的Transform Filter类。结构如下:

与CTransformFilter,CTransInPlaceFilter也有一个输入Pin和一个输出Pin,但使用CTransInPlaceOutputPin类

 

CTransInPlaceFilter的输入和输出Pin上一般使用相同的媒体类型进行连接,并且使用同一个Sample管理器(如果Filter实现时要修改Sample数据,

而协商达成一致的Sample管理器只读的,那么CTransInPlaceFilter的输入和输出Pin将不得不使用各自的Sample管理器)。

CTransInPlaceFilter类要实现上述的目标,主要依赖于CTransInPlaceFilter::CompleteConnect、CTransInPlaceInputPin::GetAllocator和

CTransInPlaceInputPin::NotifyAlocator的函数实现。代码如下:

  1. // 当输入或输出Pin完成连接时被调用,  
  2. // 经过一个反复重连的过程,来达到输入和输出Pin使用相同的媒体类型的目的  
  3. HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin)  
  4. {  
  5.     UNREFERENCED_PARAMETER(pReceivePin);  
  6.     ASSERT(m_pInput);  
  7.     ASSERT(m_pOutput);  
  8.   
  9.     // if we are not part of a graph, then don't indirect the pointer  
  10.     // this probably prevents use of the filter without a filtergraph  
  11.     if (!m_pGraph) {  
  12.         return VFW_E_NOT_IN_GRAPH;  
  13.     }  
  14.   
  15.     // Always reconnect the input to account for buffering changes  
  16.     //  
  17.     // Because we don't get to suggest a type on ReceiveConnection  
  18.     // we need another way of making sure the right type gets used.  
  19.     //  
  20.     // One way would be to have our EnumMediaTypes return our output  
  21.     // connection type first but more deterministic and simple is to  
  22.     // call ReconnectEx passing the type we want to reconnect with  
  23.     // via the base class ReconeectPin method.  
  24.   
  25.     // 当输出Pin调用该函数(并且此时输入Pin已连上)时,使用输出Pin上的媒体类型对  
  26.     // 输入Pin进行重连接  
  27.     if (dir == PINDIR_OUTPUT) {  
  28.         if( m_pInput->IsConnected() ) {  
  29.             return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() );  
  30.         }  
  31.         return NOERROR;  
  32.     }  
  33.   
  34.     ASSERT(dir == PINDIR_INPUT);  
  35.   
  36.     // Reconnect output if necessary  
  37.   
  38.     // 当输入Pin调用该函数(并且此时输出Pin已连上)时,如果输入和输出Pin上使用的  
  39.     // 媒体类型不一致,则使用输入Pin上的媒体类型对输出Pin进行重新连接  
  40.     if( m_pOutput->IsConnected() ) {  
  41.   
  42.         if (  m_pInput->CurrentMediaType()  
  43.            != m_pOutput->CurrentMediaType()  
  44.            ) {  
  45.             return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() );  
  46.         }  
  47.     }  
  48.     return NOERROR;  
  49.   
  50. // ComnpleteConnect  
// 当输入或输出Pin完成连接时被调用,
// 经过一个反复重连的过程,来达到输入和输出Pin使用相同的媒体类型的目的
HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin)
{
    UNREFERENCED_PARAMETER(pReceivePin);
    ASSERT(m_pInput);
    ASSERT(m_pOutput);

    // if we are not part of a graph, then don't indirect the pointer
    // this probably prevents use of the filter without a filtergraph
    if (!m_pGraph) {
        return VFW_E_NOT_IN_GRAPH;
    }

    // Always reconnect the input to account for buffering changes
    //
    // Because we don't get to suggest a type on ReceiveConnection
    // we need another way of making sure the right type gets used.
    //
    // One way would be to have our EnumMediaTypes return our output
    // connection type first but more deterministic and simple is to
    // call ReconnectEx passing the type we want to reconnect with
    // via the base class ReconeectPin method.

	// 当输出Pin调用该函数(并且此时输入Pin已连上)时,使用输出Pin上的媒体类型对
	// 输入Pin进行重连接
    if (dir == PINDIR_OUTPUT) {
        if( m_pInput->IsConnected() ) {
            return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() );
        }
        return NOERROR;
    }

    ASSERT(dir == PINDIR_INPUT);

    // Reconnect output if necessary

	// 当输入Pin调用该函数(并且此时输出Pin已连上)时,如果输入和输出Pin上使用的
	// 媒体类型不一致,则使用输入Pin上的媒体类型对输出Pin进行重新连接
    if( m_pOutput->IsConnected() ) {

        if (  m_pInput->CurrentMediaType()
           != m_pOutput->CurrentMediaType()
           ) {
            return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() );
        }
    }
    return NOERROR;

} // ComnpleteConnect

 


  

  1. // 当上一级Filter的输出Pin要求我们的输入Pin提供Sample管理器时,  
  2. // 如果我们的输出Pin已连接上,则可以取出输出Pin上的Sample管理器提供给上一级  
  3. // Filter,以此达到我们的输入和输出Pin使用同一个Sample管理器的目的  
  4. STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)  
  5. {  
  6.     CheckPointer(ppAllocator,E_POINTER);  
  7.     ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));  
  8.     CAutoLock cObjectLock(m_pLock);  
  9.   
  10.     HRESULT hr;  
  11.   
  12.     if ( m_pTIPFilter->m_pOutput->IsConnected() ) {  
  13.         //  Store the allocator we got  
  14.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()  
  15.                                         ->GetAllocator( ppAllocator );  
  16.         if (SUCCEEDED(hr)) {  
  17.             m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );  
  18.         }  
  19.     }  
  20.     else {  
  21.         //  Help upstream filter (eg TIP filter which is having to do a copy)  
  22.         //  by providing a temp allocator here - we'll never use  
  23.         //  this allocator because when our output is connected we'll  
  24.         //  reconnect this pin  
  25.         hr = CTransformInputPin::GetAllocator( ppAllocator );  
  26.     }  
  27.     return hr;  
  28.   
  29. // GetAllocator  
// 当上一级Filter的输出Pin要求我们的输入Pin提供Sample管理器时,
// 如果我们的输出Pin已连接上,则可以取出输出Pin上的Sample管理器提供给上一级
// Filter,以此达到我们的输入和输出Pin使用同一个Sample管理器的目的
STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)
{
    CheckPointer(ppAllocator,E_POINTER);
    ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
    CAutoLock cObjectLock(m_pLock);

    HRESULT hr;

    if ( m_pTIPFilter->m_pOutput->IsConnected() ) {
        //  Store the allocator we got
        hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
                                        ->GetAllocator( ppAllocator );
        if (SUCCEEDED(hr)) {
            m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator );
        }
    }
    else {
        //  Help upstream filter (eg TIP filter which is having to do a copy)
        //  by providing a temp allocator here - we'll never use
        //  this allocator because when our output is connected we'll
        //  reconnect this pin
        hr = CTransformInputPin::GetAllocator( ppAllocator );
    }
    return hr;

} // GetAllocator


 


  

  1. // 上一级Filter调用该函数,告知输入Pin上到底使用哪一个Sample管理器  
  2. // 如果设置进来的Sample管理器是只读的,而我们在Filter中又想修改数据,  
  3. // 则我们的Filter不得不最终使用不同的Sample管理器  
  4. STDMETHODIMP  
  5. CTransInPlaceInputPin::NotifyAllocator(  
  6.     IMemAllocator * pAllocator,  
  7.     BOOL bReadOnly)  
  8. {  
  9.     HRESULT hr = S_OK;  
  10.     CheckPointer(pAllocator,E_POINTER);  
  11.     ValidateReadPtr(pAllocator,sizeof(IMemAllocator));  
  12.   
  13.     CAutoLock cObjectLock(m_pLock);  
  14.   
  15.     m_bReadOnly = bReadOnly;  
  16.     //  If we modify data then don't accept the allocator if it's  
  17.     //  the same as the output pin's allocator  
  18.   
  19.     //  If our output is not connected just accept the allocator  
  20.     //  We're never going to use this allocator because when our  
  21.     //  output pin is connected we'll reconnect this pin  
  22.     if (!m_pTIPFilter->OutputPin()->IsConnected()) {  
  23.         return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);  
  24.     }  
  25.   
  26.     //  If the allocator is read-only and we're modifying data  
  27.     //  and the allocator is the same as the output pin's  
  28.     //  then reject  
  29.     if (bReadOnly && m_pTIPFilter->m_bModifiesData) {  
  30.         IMemAllocator *pOutputAllocator =  
  31.             m_pTIPFilter->OutputPin()->PeekAllocator();  
  32.   
  33.         //  Make sure we have an output allocator  
  34.         if (pOutputAllocator == NULL) {  
  35.             hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->  
  36.                                       GetAllocator(&pOutputAllocator);  
  37.             if(FAILED(hr)) {  
  38.                 hr = CreateMemoryAllocator(&pOutputAllocator);  
  39.             }  
  40.             if (SUCCEEDED(hr)) {  
  41.                 m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);  
  42.                 pOutputAllocator->Release();  
  43.             }  
  44.         }  
  45.         if (pAllocator == pOutputAllocator) {  
  46.             hr = E_FAIL;  
  47.         } else if(SUCCEEDED(hr)) {  
  48.             //  Must copy so set the allocator properties on the output  
  49.             ALLOCATOR_PROPERTIES Props, Actual;  
  50.             hr = pAllocator->GetProperties(&Props);  
  51.             if (SUCCEEDED(hr)) {  
  52.                 hr = pOutputAllocator->SetProperties(&Props, &Actual);  
  53.             }  
  54.             if (SUCCEEDED(hr)) {  
  55.                 if (  (Props.cBuffers > Actual.cBuffers)  
  56.                    || (Props.cbBuffer > Actual.cbBuffer)  
  57.                    || (Props.cbAlign  > Actual.cbAlign)  
  58.                    ) {  
  59.                     hr =  E_FAIL;  
  60.                 }  
  61.             }  
  62.   
  63.             //  Set the allocator on the output pin  
  64.             if (SUCCEEDED(hr)) {  
  65.                 hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()  
  66.                                        ->NotifyAllocator( pOutputAllocator, FALSE );  
  67.             }  
  68.         }  
  69.     } else {  
  70.         hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()  
  71.                                    ->NotifyAllocator( pAllocator, bReadOnly );  
  72.         if (SUCCEEDED(hr)) {  
  73.             m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );  
  74.         }  
  75.     }  
  76.   
  77.     if (SUCCEEDED(hr)) {  
  78.   
  79.         // It's possible that the old and the new are the same thing.  
  80.         // AddRef before release ensures that we don't unload it.  
  81.         pAllocator->AddRef();  
  82.   
  83.         if( m_pAllocator != NULL )  
  84.             m_pAllocator->Release();  
  85.   
  86.         m_pAllocator = pAllocator;    // We have an allocator for the input pin  
  87.     }  
  88.   
  89.     return hr;  
  90.   
  91. // NotifyAllocator  
// 上一级Filter调用该函数,告知输入Pin上到底使用哪一个Sample管理器
// 如果设置进来的Sample管理器是只读的,而我们在Filter中又想修改数据,
// 则我们的Filter不得不最终使用不同的Sample管理器
STDMETHODIMP
CTransInPlaceInputPin::NotifyAllocator(
    IMemAllocator * pAllocator,
    BOOL bReadOnly)
{
    HRESULT hr = S_OK;
    CheckPointer(pAllocator,E_POINTER);
    ValidateReadPtr(pAllocator,sizeof(IMemAllocator));

    CAutoLock cObjectLock(m_pLock);

    m_bReadOnly = bReadOnly;
    //  If we modify data then don't accept the allocator if it's
    //  the same as the output pin's allocator

    //  If our output is not connected just accept the allocator
    //  We're never going to use this allocator because when our
    //  output pin is connected we'll reconnect this pin
    if (!m_pTIPFilter->OutputPin()->IsConnected()) {
        return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly);
    }

    //  If the allocator is read-only and we're modifying data
    //  and the allocator is the same as the output pin's
    //  then reject
    if (bReadOnly && m_pTIPFilter->m_bModifiesData) {
        IMemAllocator *pOutputAllocator =
            m_pTIPFilter->OutputPin()->PeekAllocator();

        //  Make sure we have an output allocator
        if (pOutputAllocator == NULL) {
            hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()->
                                      GetAllocator(&pOutputAllocator);
            if(FAILED(hr)) {
                hr = CreateMemoryAllocator(&pOutputAllocator);
            }
            if (SUCCEEDED(hr)) {
                m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator);
                pOutputAllocator->Release();
            }
        }
        if (pAllocator == pOutputAllocator) {
            hr = E_FAIL;
        } else if(SUCCEEDED(hr)) {
            //  Must copy so set the allocator properties on the output
            ALLOCATOR_PROPERTIES Props, Actual;
            hr = pAllocator->GetProperties(&Props);
            if (SUCCEEDED(hr)) {
                hr = pOutputAllocator->SetProperties(&Props, &Actual);
            }
            if (SUCCEEDED(hr)) {
                if (  (Props.cBuffers > Actual.cBuffers)
                   || (Props.cbBuffer > Actual.cbBuffer)
                   || (Props.cbAlign  > Actual.cbAlign)
                   ) {
                    hr =  E_FAIL;
                }
            }

            //  Set the allocator on the output pin
            if (SUCCEEDED(hr)) {
                hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
                                       ->NotifyAllocator( pOutputAllocator, FALSE );
            }
        }
    } else {
        hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()
                                   ->NotifyAllocator( pAllocator, bReadOnly );
        if (SUCCEEDED(hr)) {
            m_pTIPFilter->OutputPin()->SetAllocator( pAllocator );
        }
    }

    if (SUCCEEDED(hr)) {

        // It's possible that the old and the new are the same thing.
        // AddRef before release ensures that we don't unload it.
        pAllocator->AddRef();

        if( m_pAllocator != NULL )
            m_pAllocator->Release();

        m_pAllocator = pAllocator;    // We have an allocator for the input pin
    }

    return hr;

} // NotifyAllocator

 

CTransInPlaceFilter类定义了一个成员变量m_bModifiesData ,用于指示我们在Filter中是否会修改Saple 数据。

这个变量在CTransInPlaceFilter构造函数调用时被默认初始化为true。如果我们确定不会在Filter中修改Sample数据,

那么,将m_bModifiesData设置为false, 可以保证输入和输出Pin连接完成后使用同一个Sample管理器。

 

10、 CVideoTransformFilter

CVieoTransformFilter是一个实现了视频的质量控制的Transform Filter类。其结构如下:

CVieoTransformFilter通过输入Pin上的Receive 函数接收Sample时,能够根据质量消息决定是否丢帧。这个类主要是为开发AVI解码Filter而设计的。

CVieoTransformFilter类的使用基本上与CTransformFilter相同。

 

11、 CBaseRenderer

CBaseRender是最基本的实现Renderer Filter的类。它默认实现了一个使用CRendererInputPin类的输入Pin(Renderer Filter没有输出Pin)。

这两个类的结构如下:

从图中可以看出,CBaseRenderer从CBaseFilter继承而来。另外,CBaseRenderer上还实现了IMediaSeekin和IMediaPosition接口。

CRendererInputPin从CBaseInputPin 继承而来,它把各个主要函数调用都“委托”到Filter上。值得注意的是,当输入Pin接收到EndOfStream调用时,

Renderer Filter 有责任向Filter Graph Manager发送一个EC_COMPLETE事件。

CBaseRenderer类的使用方法(派生一个子类,并至少实现如下函数)如下:

(1)CBaseRenderer::CheckMediaType,用于检查输入Pin连接用的媒体类型;

(2)CBaseRenderer::DoRenderSample,处理当前的Sample。

提示:CBaseRenderer实际上是为了用于播放的Render Filter设计的,对于Sample的安排比较复杂

如果我们要开发Renderer Filter不播放Sample(比如写文件的Filter、或者负责网络的Filter),Fitler的基类可以选择CBaseFilter,而此时输入Pin最

好选择CRenderedInputPin类派生。

 

12、CBaseVideoRenderer

CBaseVideoRenderer是一个实现Video Renderer类的基类,结构如下:

CBaseVideoRenderer在CBaseRenderer的基础上增加了IQualityControl和IQualProp接口的实现。

其中IQualityControl用于视频质量控制,IQualProp用于在Filter属性页显示一些实时性能参数。CBaseVideoRenderer类的使用方法基本上与CBaseRenderer相同。

 

在DirectShow SDK基类库中,除了上述Filter和Pin类外,还有很多工具类,有了这些类的支持,我们开发Fitler或DirectShow应用程序会更加轻松。

这些类包括: CPullPin、 COutputQueue、  CSourceSeeking  、CEnumPins、 CEnumMediaTypes  、CMemAllocator 、 CMediaSample  、

CBaseReferenceClock  、CMediaType、 CBasePropertyPage  等。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
//指定视频采集设备的友好名字,为它创建一个Filter IBaseFilter * CTestPreviewDlg::CreateVideoDevice(const char * inFriendlyName) { return CreateHardwareFilter(CLSID_VideoInputDeviceCategory,inFriendlyName); } //根据设备的友好名字,创建一个代表该设备的Filter IBaseFilter * CTestPreviewDlg::CreateHardwareFilter(GUID inCategory,const char * inFriendlyName) { //创建一个系统枚举组件对象 ICreateDevEnum * enumHardware = NULL; HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_ALL, IID_ICreateDevEnum,(void**)&enumHardware); if(FAILED(hr)) { return NULL; } IBaseFilter * hardwareFilter = NULL; IEnumMoniker * enumMoniker = NULL; //为指定的目录创建枚举器 hr = enumHardware->CreateClassEnumerator(inCategory,&enumMoniker,0); if(enumMoniker) { enumMoniker->Reset(); ULONG fetched = 0; IMoniker * moniker = NULL; char friendlyName[256]; //枚举得到该目录下所有的设备,逐个进行名字匹配 while(!hardwareFilter && SUCCEEDED(enumMoniker->Next(1,&moniker, &fetched)) && fetched) { if(moniker) { IPropertyBag * propertyBag = NULL; VARIANT name; friendlyName[0] = 0; hr = moniker->BindToStorage(0,0,IID_IPropertyBag,(void**)&propertyBag); //读取设备的友好名字 if(SUCCEEDED(hr)) { name.vt = VT_BSTR; hr = propertyBag->Read(L"Friendlyname",&name,NULL); } if(SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP,0,name.bstrVal,-1, friendlyName,256,NULL,NULL); //如果当前设备的友好名字与用户指定的设备名字相同, //则将当前设备标识绑定为Filter形式 if(strcmp(friendlyName,inFriendlyName) == 0) { moniker->BindToObject(0,0,IID_IBaseFilter, (void**)&hardwareFilter); } } //释放使用过的接口 if(propertyBag) { propertyBag->Release(); propertyBag = NULL; } moniker->Release(); } } enumMoniker->Release(); } enumHardware->Release(); return hardwareFilter; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值