软件工程

本类阅读TOP10

·PHP4 + MYSQL + APACHE 在 WIN 系统下的安装、配置
·Linux 入门常用命令(1)
·Linux 入门常用命令(2)
·使用 DCPROMO/FORCEREMOVAL 命令强制将 Active Directory 域控制器降级
·DirectShow学习(八): CBaseRender类及相应Pin类的源代码分析
·基于ICE方式SIP信令穿透Symmetric NAT技术研究
·Windows 2003网络负载均衡的实现
·一网打尽Win十四种系统故障解决方法
·数百种 Windows 软件的免费替代品列表
·收藏---行百里半九十

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
DirectShow学习(二)CBasePin类、CBaseOutputPin类和CBaseInputPin类源代码解析

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

  1. 预备知识 CMediaType[mtype.h/mtype.cpp]
    CMediaType从_AMMediaType继承,是一个在DirectShow中非常有用的Helper Class。它提供了一些常用的辅助函数来操作AMMediaType结构。另外,还提供了几个很常用的全局函数CreateMediaTypeDeleteMediaTypeCopyMediaTypeFreeMediaType以及CreateAudioMediaType
  2. CBasePin类[amfilter.h/amfilter.cpp]
    • BasePin继承了接口IPin, IPin的接口定义如下
       IPin : public IUnknown
      {
          public:
          // 连接两个Pin,主动连接InputPin
          virtual HRESULT STDMETHODCALLTYPE Connect(
                  /* [in] */ IPin *pReceivePin,
                  /* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
          // 连接两个Pin,被动连接
          virtual HRESULT STDMETHODCALLTYPE ReceiveConnection(
                  /* [in] */ IPin *pConnector,
                  /* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
          // 断开连接,只能在Stop状态下断开
          virtual HRESULT STDMETHODCALLTYPE Disconnect( void) = 0;
          // 得到连接的Pin的接口,成功返回连接的Pin被调用AddRef
          virtual HRESULT STDMETHODCALLTYPE ConnectedTo(
                  /* [out] */ IPin **pPin) = 0;
          // 得到连接状态下的MediaType
          virtual HRESULT STDMETHODCALLTYPE ConnectionMediaType(
                  /* [out] */ AM_MEDIA_TYPE *pmt) = 0;
          // 得到Pin的信息,填充PIN_INFO结构
          virtual HRESULT STDMETHODCALLTYPE QueryPinInfo(
                  /* [out] */ PIN_INFO *pInfo) = 0;
          // 得到Pin的连接方向
          virtual HRESULT STDMETHODCALLTYPE QueryDirection(
                  /* [out] */ PIN_DIRECTION *pPinDir) = 0;
          // 得到ID - 其实是Pin中的name
          virtual HRESULT STDMETHODCALLTYPE QueryId(
                  /* [out] */ LPWSTR *Id) = 0;
          // Determines whether the pin accepts a specified media type.
          virtual HRESULT STDMETHODCALLTYPE QueryAccept(
                  /* [in] */ const AM_MEDIA_TYPE *pmt) = 0;
          // Enumerates the pin's preferred media types.
          virtual HRESULT STDMETHODCALLTYPE EnumMediaTypes(
                  /* [out] */ IEnumMediaTypes **ppEnum) = 0;
          // Retrieves the pins that are connected internally to this pin (within the filter).
          virtual HRESULT STDMETHODCALLTYPE QueryInternalConnections(
                  /* [out] */ IPin **apPin,
                  /* [out][in] */ ULONG *nPin) = 0;
          // Notifies the pin that no additional data is expected
          virtual HRESULT STDMETHODCALLTYPE EndOfStream( void) = 0;
          // Begins / End a flush operation.
          virtual HRESULT STDMETHODCALLTYPE BeginFlush( void) = 0;
          virtual HRESULT STDMETHODCALLTYPE EndFlush( void) = 0;
          // Notifies the pin that media samples received after this call are grouped as a segment.
          virtual HRESULT STDMETHODCALLTYPE NewSegment(
                  /* [in] */ REFERENCE_TIME tStart,
                  /* [in] */ REFERENCE_TIME tStop,
                  /* [in] */ double dRate) = 0;
          };
    • CBasePin同时继承了接口IQualityControl, IQualityControl的定义如下
      IQualityControl : public IUnknown
      {
      public:
          // Notifies the recipient that a quality change is requested.
          virtual HRESULT STDMETHODCALLTYPE Notify(
              /* [in] */ IBaseFilter *pSelf,
              /* [in] */ Quality q) = 0;
          virtual HRESULT STDMETHODCALLTYPE SetSink(
              /* [in] */ IQualityControl *piqc) = 0;
      };
    • CBasePin类的具体实现伪代码
      派生自 CUnknown, IPin, IQualityControl
      成员变量:
          WCHAR *         m_pName;          // This pin's name
          IPin            *m_Connected;               // Pin we have connected to
          PIN_DIRECTION   m_dir;                      // Direction of this pin
          CCritSec        *m_pLock;                   // Object we use for locking
          bool            m_bRunTimeError;            // Run time error generated
          bool            m_bCanReconnectWhenActive;  // OK to reconnect when active
          bool            m_bTryMyTypesFirst;         // When connecting enumerate
         CBaseFilter    *m_pFilter;                  // Filter we were created by
          IQualityControl *m_pQSink;                  // Target for Quality messages
          LONG            m_TypeVersion;              // Holds current type version
          CMediaType      m_mt;                       // Media type of connection
          CRefTime        m_tStart;                   // time from NewSegment call
          CRefTime        m_tStop;                    // time from NewSegment
          double          m_dRate;                    // rate from NewSegment
      其中m_bRunTimeError默认为FALSE,m_pQSink默认为NULL,m_TypeVersion默认为1,m_tStart为空,m_tStop为MAX_TIME,m_bCanReconnectWhenActive和m_bTryMyTypesFirst都为FALSE,m_dRate为1.0。
      构造函数部分:
      Constructor:
          CBasePin(
              TCHAR *pObjectName,         // Object description
              CBaseFilter *pFilter,       // Owning filter who knows about pins
              CCritSec *pLock,            // Object who implements the lock
              HRESULT *phr,               // General OLE return code
              LPCWSTR pName,              // Pin name for us
              PIN_DIRECTION dir);         // Either PINDIR_INPUT or PINDIR_OUTPUT
    • Pin之间的链接过程[详细Code讲解见陆其明《DirectShow开发指南》第二章的讲解],通过调用IPin的Connect->AgreeMediaType(CBasePin的Protected函数)->TryMediaTypes(CBasePin的Protected函数)->AttempConnect(CBasePin的Protected函数)。
      其中AttempConnect函数会首先调用CheckConnect(CBasePin的Virtual函数),然后调用CheckMediaType(CBasePin的Virtual函数),如果MediaType接受,则调用Receive Pin上的ReceiveConnection(IPin接口函数)函数,如果成功则调用CompleteConnection(CBasePin的virtual函数)。
    • CBasePin中的新增加virtual函数和解释以及虚拟代码:
      virtual LONG GetMediaTypeVersion();{return m_TypeVersion;}
      // switch the pin to active (paused or running) mode not an error to call this if already active,
      virtual HRESULT Active(void);{return NOERROR;}
      // switch the pin to inactive state - may already be inactive
      virtual HRESULT Inactive(void);{ return NOERROR; }
      // Notify of Run() from filter,
      virtual HRESULT Run(REFERENCE_TIME tStart);{ return NOERROR; }
      // check if the pin can support this specific proposed type and forma
      virtual HRESULT CheckMediaType(const CMediaType *) PURE; 必须Override
      // set the connection to use this format (previously agreed)
      virtual HRESULT SetMediaType(const CMediaType *);{ HRESULT hr = m_mt.Set(*pmt);}
      // check that the connection is ok before verifying it can be overridden eg to check what interfaces will be supported.
      virtual HRESULT CheckConnect(IPin *); {CBasePin中只检查了Pin的方向和当前方向是否一致}
      // Set and release resources required for a connection
      virtual HRESULT BreakConnect();{return NOERROR;}
      virtual HRESULT CompleteConnect(IPin *pReceivePin);
      // returns the preferred formats for a pin
      virtual HRESULT GetMediaType(int iPosition,CMediaType *pMediaType); 必须Override
    • CBasePin实现IPin的函数
      QueryAccept - 直接调用CheckMediaType,并将结果返回
      EnumMediaTypes - 通过辅助类CEnumMediaTypes实现MediaType的Enum.
      NewSegment – 只是简单设置参数后直接返回NOERROR
      Disconnect – 调用函数 DisconnectInternal
      Connect/ReceiveConnection – 见上面条目。
      其它的简单接口函数 ConnectionMediaTypeQueryPinInfoQueryDirection等。
    • CBasePin中未实现IPin/IQualityControl的函数
      直接设置为NOERROR的部分函数:
      EndOfStream
      直接设置为IMPL错误码的部分函数:
      QueryInternalConnections
      Notify[IQualityControl接口]
      完全没有实现的部分函数:
      BeginFlush
      EndFlush
  3. CBaseOutputPin 类[amfilter.h/amfilter.cpp]
    • CBaseOutputPin具体实现伪代码
      派生自 CBasePin
      变量部分(均初始化为NULL):
      IMemAllocator *m_pAllocator; // Memory allocator
      IMemInputPin *m_pInputPin;  // interface on the downstreaminput pin
    • 新增加的virtual函数:
      // negotiate the allocator and its buffer size/count and other properties
      // Calls DecideBufferSize to set properties
      virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
      {
      // 调用 pPin->GetAllocatorRequirements. 得到Input Pin的Prop.
      // 调用 pPin->GetAllocator判断pPin是否以及存在Allocator,否则自己创建并初始化(InitAlloc)
      // 调用 DecideBufferSize 来得到需要的大小
      // 调用 pPin->NotifyAllocator让Input Pin得到更新的Allocator
      }
      // override this to set the buffer size and count. Return an error
      virtual HRESULT DecideBufferSize(
          IMemAllocator * pAlloc,
          ALLOCATOR_PROPERTIES * ppropInputRequest
      ) PURE;
      // returns an empty sample buffer from the allocator
      virtual HRESULT GetDeliveryBuffer(IMediaSample ** ppSample,
                                        REFERENCE_TIME * pStartTime,
                                        REFERENCE_TIME * pEndTime,
                                        DWORD dwFlags);
      {// 调用 m_pAllocator->GetBuffer… }
      // deliver a filled-in sample to the connected input pin
      // note - you need to release it after calling this. The receiving
      virtual HRESULT Deliver(IMediaSample *);{ m_pInputPin->Receive(pSample); }
      // override this to control the connection
      virtual HRESULT InitAllocator(IMemAllocator **ppAlloc);{ CreateMemoryAllocator(ppAlloc); }
      // called from elsewhere in our filter to pass EOS downstream to our connected input pin
      virtual HRESULT DeliverEndOfStream(void);{ m_Connected->EndOfStream(); }
      virtual HRESULT DeliverBeginFlush(void);{ m_Connected->BeginFlush(); }
      virtual HRESULT DeliverEndFlush(void);{ m_Connected->EndFlush(); }
      virtual HRESULT DeliverNewSegment(
                          REFERENCE_TIME tStart,
                          REFERENCE_TIME tStop,
                          double dRate);{ m_Connected->NewSegment(…);}
    • 继承的virtual函数或者IPin接口函数:
      // Complete connection
      virtual HRESULT CompleteConnect(IPin *pReceivePin); { DecideAllocator() }
      // Check connection
      HRESULT CheckConnect(IPin *pPin);
      {增加检查输入Pin是否支持IMemInputPin接口,m_pInputPin在这里赋值}
      // Break connection
      HRESULT BreakConnect();
      {
      // 调用m_pAllocator->Decommit()释放m_pAllocator并置为空,
      // 释放m_pInputPin并置为空
      }
      HRESULT Active(void);{ m_pAllocator->Commit(); }
      HRESULT Inactive(void); { m_pAllocator->Decommit();}
      // 以下三个函数直接返回E_UNEXPECTED
      STDMETHODIMP EndOfStream(void);
      STDMETHODIMP BeginFlush(void);
      STDMETHODIMP EndFlush(void);
  4. IMemInput接口函数:
    // Retrieves the memory allocator proposed by this pin.
    virtual HRESULT STDMETHODCALLTYPE GetAllocator(
        /* [out] */ IMemAllocator **ppAllocator) = 0;
    // Specifies an allocator for the connection.
    virtual HRESULT STDMETHODCALLTYPE NotifyAllocator(
        /* [in] */ IMemAllocator *pAllocator,
        /* [in] */ BOOL bReadOnly) = 0;
    // Retrieves allocator properties that are requested by the input pin.
    virtual HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(
        /* [out] */ ALLOCATOR_PROPERTIES *pProps) = 0;
    // Receives the next media sample in the stream.
    virtual HRESULT STDMETHODCALLTYPE Receive(
        /* [in] */ IMediaSample *pSample) = 0;
    // Receives multiple samples in the stream.
    virtual HRESULT STDMETHODCALLTYPE ReceiveMultiple(
        /* [size_is][in] */ IMediaSample **pSamples,
        /* [in] */ long nSamples,
        /* [out] */ long *nSamplesProcessed) = 0;
    // Determines whether calls to the Recive method might block.
    virtual HRESULT STDMETHODCALLTYPE ReceiveCanBlock( void) = 0;
  5. CBaseInputPin类[amfilter.h/amfilter.cpp]
    • CBaseInputPin具体实现伪代码:
      派生自 CBasePin, IMemInputPin
      变量部分:
      IMemAllocator *m_pAllocator;    // Default memory allocator
      // Allocator is read only or not
      BYTE m_bReadOnly;
      // in flushing state (between BeginFlush and EndFlush)
      // if TRUE, all Receives are returned with S_FALSE

      BYTE m_bFlushing;
      // Sample properties - initalized in Receive
      AM_SAMPLE2_PROPERTIES m_SampleProps;
      INonDelegationUnknown的接口函数:
      // 重写该函数是为了支持IMemInputPin接口
      STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
      具体实现函数:
      HRESULT PassNotify(Quality& q);
      {
      // 如果m_pQSink不为空,直接调用m_pQSink->Notify(…)
      // 否则查询Connect Pin上的IQualityControl借口,对其调用Notify(…)
      }
    • 新增的virtual函数
      //  Override this for checking whether it's OK to process samples
      //  Also call this from EndOfStream.
      virtual HRESULT CheckStreaming();
      {分别判断IsStopped、m_bFlushing和m_bRunTimeError }
    • IMemInputPin接口函数:
      // return the allocator interface that this input pin
      // would like the output pin to use
      STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
      {
      // 如果m_pAllocator为空,则CreateMemoryAllocator
      // 调用m_pAllocator->AddRef,返回m_pAllocator
      }
      // tell the input pin which allocator the output pin is actually going to use.
      STDMETHODIMP NotifyAllocator(
                      IMemAllocator * pAllocator,
                      BOOL bReadOnly);
      {
      // 释放当前m_pAllocator,设置m_pAllocator = pAllocator
      // 调用m_pAllocator->AddRef
      }
      // do something with this media sample
      STDMETHODIMP Receive(IMediaSample *pSample);
      {
      // 首先调用CheckStreaming
      // 得出pSample的属性,即填充成员m_SampleProps
      // 如果Sample属性未发生变化(!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED))
      // 则直接返回NOERROR,否则调用CheckMediaType检查是否接受新的MediaType,如果接受
      // 返回NOERROR,否则调用EndOfStream,设置RuntimeError,并通知Filter
      // m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
      }
      // do something with these media samples
      STDMETHODIMP ReceiveMultiple (
          IMediaSample **pSamples,
          long nSamples,
          long *nSamplesProcessed);
      {
      // 对每个Sample分别调用Receive函数。
      }
      // See if Receive() blocks
      STDMETHODIMP ReceiveCanBlock();
      {
      // 如果当前Filter上没有Output Pin,则返回S_OK
      // 否则遍历当前Filter上每个Output Pin,得出它们的Connected Input Pin,判断这些
      // Connected Input Pin是否支持Block,只要有一个支持,则为S_OK
      // 以上条件全不满足时,返回S_FALSE
      }
      // default implementation returns E_NOTIMPL. Override if you have
      // specific alignment or prefix needs, but could use an upstream allocator
      STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps);{E_IMPL}
    • 继承的virtual函数实现
      STDMETHODIMP BeginFlush(void);
      {仅仅设置m_bFlushing为TRUE.}
      STDMETHODIMP EndFlush(void);
      {仅仅设置m_bFlushing为FALSE,同时清除m_bRuntimeError。}
      HRESULT BreakConnect();
      {
      // 如果m_pAllocator非空,调用m_pAllocator->Decommit()
      // 释放m_pAllocator->Release并置为空
      }
      virtual HRESULT Inactive(void);
      {
      // 清理m_bRunTimeError和m_bFlushing,返回m_pAllocator->Decommit().
      }
      STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
      {这是IQualityControl的接口函数,CBaseInputPin只是简单报错DbgBreak说明未实现}
  6. 学习三将侧重于Filter的代码分析



相关文章

相关软件