zoukankan      html  css  js  c++  java
  • 几篇关于如何写filter的转帖 之 开发source filter的source sourcestream两个基类介绍

    第一个是source,第二个是sourcestream

    3.3几种常用Filter的基类
    3.3.1CSource
    class CSource : public CBaseFilter {
    public:
    CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
    CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
    #ifdef UNICODE
    CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
    CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
    #endif
    ~CSource();

    int GetPinCount(void);
    CBasePin *GetPin(int n);

    CCritSec* pStateLock(void) { return &m_cStateLock; }
    HRESULT AddPin(CSourceStream *);
    HRESULT RemovePin(CSourceStream *);

    STDMETHODIMP FindPin(LPCWSTR Id,IPin ** ppPin );

    int FindPinNumber(IPin *iPin);

    protected:

    int m_iPins;
    CSourceStream **m_paStreams; // the pins on this filter.
    CCritSec m_cStateLock; // Lock this to serialize
    };

    CSource类是开发源Filter的基类,一个从从CSource类派生的Filter一般都支持一个或者几个从CSourceSteam类派生的输出pin。每一个输出pin都创建了一个工作线程用来将数据传递给下游的Filter。
    为了生产一个输出pin,请按照如下的步骤
    1 从CSoureceStream类派生一个类。
    2重载CSourceStream::GetMediaType和CSourceStream::CheckMediaType方法。
    3重载CBaseOutputPin::DecideBufferSize,这个方法将返回pin的buffer要求
    4重载CSourceStream::FillBuffer,这个方法用来产生数据流,将数据填充到buffer中
    为了派生一个源Filter,可以按照下面的步骤来做
    1从CSourec类派生一个类。
    2在构造函数中创建一个或者多个的输出pin。注意,这个pin要从CSourceStream派生哦。这些pin会在他们的构造函数中自动将自己添加到Filter中。并且在他们的析构函数种从Filter中删除Pin。
    为了在多线程中同步Filter的状态,调用CSource::pStateLock方法,这个方法返回一个指向临界区的指针,通过CAutoLock来生成一个锁,在pin中,你可以通过CBasePin::m_pFilter来指针来操纵临界区保护你的Filter,从而达到同步。例如
    CAutoLock lock(m_pFilter->pStateLock());
    注意:CSource用来生成推模式的源Filter,如果要读文件,则应该使用拉模式。
    下面我们分析一下CSourec的数据成员
    int m_iPins;
    CSourceStream **m_paStreams;
    CCritSec m_cStateLock;
    总共三个数据成员,一个表示pin的数量,一个pin的数组,用来存放Filter支持的所有的pin,另外一个是临界区对象。
    下面分析方法,也比较简单。
    1CSource::GetPinCount
    这个函数用来返回Filter支持的pin的数目。
    2CSource::GetPin
    CBasePin *GetPin( int n);
    根据指定的序号返回pin的指针。0,1,2,就是从Filter的那个pin数组中返回就是了,根据序号。
    3CCritSec* pStateLock(void);
    返回临界区对象
    4CSource::AddPin
    HRESULT AddPin( CSourceStream *pStream);
    构造函数通常调用这个函数将一个输出pin添加到Filter中。
    5CSource::RemovePin
    HRESULT RemovePin( CSourceStream *pStream);
    析构函数通常通过这个函数将一个输出pin从Filter中删除
    6CSource::FindPinNumber
    int FindPinNumber( IPin *iPin);
    这个函数根据指定的pin的指针,返回他的序号,如果返回-1表示没有这个pin。
    7CSource::FindPin
    HRESULT FindPin( LPCWSTR Id, IPin **ppPin);
    根据指定的ID返回pin。
    注意,Filter的第一个pin ID为1开始,然后是23456789等。

    3.3.2CSourceStream
    class CSourceStream : public CAMThread, public CBaseOutputPin {
    public:

    CSourceStream(TCHAR *pObjectName,
    HRESULT *phr,
    CSource *pms,
    LPCWSTR pName);
    #ifdef UNICODE
    CSourceStream(CHAR *pObjectName,
    HRESULT *phr,
    CSource *pms,
    LPCWSTR pName);
    #endif
    virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too.

    protected:

    CSource *m_pFilter; // The parent of this stream

    virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;

    virtual HRESULT OnThreadCreate(void) {return NOERROR;};
    virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
    virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};

    HRESULT Active(void); // Starts up the worker thread
    HRESULT Inactive(void); // Exits the worker thread.

    public:
    // thread commands
    enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
    HRESULT Init(void) { return CallWorker(CMD_INIT); }
    HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
    HRESULT Run(void) { return CallWorker(CMD_RUN); }
    HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
    HRESULT Stop(void) { return CallWorker(CMD_STOP); }

    protected:
    Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
    BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }

    // override these if you want to add thread commands
    virtual DWORD ThreadProc(void); // the thread function

    virtual HRESULT DoBufferProcessingLoop(void);
    virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
    virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
    virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}

    STDMETHODIMP QueryId(
    LPWSTR * Id
    );
    };

    CSourceStream类用来生成一个输出pin,当然为了CSource配合。
    关于如何使用这个类,可以参看CSource,这个类从CAMThread类继承而来,这个类提供了产生了数据流的工作线程,CSourceStream类通过下面的方法来给线程发送请求。
    CSourceStream::Exit,CSourceStream::Init,CSourceStream::Pause,CSourceStream::Run,
    CSourceStream::Stop
    发给线程的第一个请求一定是Init,Exit请求用来结束线程,实际上,我们没有必要亲自调用这些函数,因为在CSourceStream::Active and CSourceStream::Inactive都调用了所需要的方法。
    这个类也提供几个handler方法
    CSourceStream::OnThreadCreate
    CSourceStream::OnThreadDestroy
    CSourceStream::OnThreadStartPlay
    首先分析一下数据成员
    CSource *m_pFilter;
    靠,就一个数据成员,用来指向这个pin连接的Filter。
    看看成员函数吧,
    1CSourceStream::OnThreadCreate
    virtual HRESULT OnThreadCreate(void);
    线程处理CSourceStream::ThreadProc在第一次接收到Init请求的时候,就会调用这个方法,在基类的实现中,这个函数没有作任何的事情,派生类可以在这个函数中做一些初始化线程的工作。
    2CSourceStream::OnThreadDestroy
    当线程退出的时候,会调用这个函数,基类的实现没有作任何的事情,你可以在派生类中做清理现场的工作。
    3CSourceStream::OnThreadStartPlay
    在CSourceStream::DoBufferProcessingLoop开始的时候,会调用到这个函数
    4CSourceStream::Active
    5CSourceStream::Inactive
    6CSourceStream::GetRequest
    Command GetRequest(void);
    这个函数可以等待下一个线程请求。这个方法重载了CAMThread::GetRequest
    7CSourceStream::CheckRequest
    非阻塞情况下,这个函数用来查询是否有个线程请求
    8CSourceStream::ThreadProc
    这个函数是工作线程的函数体,重载了CAMThread::ThreadProc方法。
    virtual DWORD ThreadProc(void);
    这个函数会无限的等待线程的请求,通过调用CAMThread::GetRequest方法,如果它接收到CSourceStream::Run or CSourceStream::Pause请求,它就调用
    CSourceStream::DoBufferProcessingLoop方法,DoBufferProcessingLoop会一直往外推数据,直到它接收到一个CSourceStream::Stop请求,线程处理器当接收到CSourceStream::Exit请求,就会退出了。
    9CSourceStream::DoBufferProcessingLoop
    virtual HRESULT DoBufferProcessingLoop(void);
    这个方法其实是线程的实现函数,在这个循环中处理数据,并且将数据传递给下下游的Filter,每次,这个方法都会申请一个空的内存sample,然后将这个sample传递给CSourceStream::FillBuffer方法,FillBuffer方法在派生类中一定要实现哦,这个函数是用来产生数据,并将数据拷贝到sample。
    当发生下面的情形时,循环停止,退出
    1 当IMemInputPin::Receive方法拒绝samples。
    2FillBuffer返回False,表示结束发送数据了
    3线程接收到一个CSourceStream::Stop请求。
    10CSourceStream::CheckMediaType
    virtual HRESULT CheckMediaType( const CMediaType *pMediaType);
    确认是否支持指定的媒体类型。
    11CSourceStream::GetMediaType
    virtual HRESULT GetMediaType( int iPosition, CMediaType *pMediaType);

    virtual HRESULT GetMediaType( CMediaType *pMediaType);
    获取指定位置的媒体类型。
    12CSourceStream::Init
    HRESULT Init(void);
    这个函数用来启动一个线程,CSourceStream::Active方法会调用这个函数的。
    13CSourceStream::Exit
    The CSourceStream::Inactive method calls this method.
    14CSourceStream::Run
    15CSourceStream::Pause
    CSourceStream::Active会调用这个方法的。当CSourceStream::ThreadProc接收这个请求,它会调用CSourceStream::DoBufferProcessingLoop方法。
    16CSourceStream::Stop
    The CSourceStream::Inactive method calls this method.
    17CSourceStream::FillBuffer
    virtual HRESULT FillBuffer( IMediaSample *pSample) PURE;
    最重要的一个函数。
    派生类中一定要实现这个函数,媒体samples没有给这个方法提供时间戳,派生类应该调用IMediaSample::SetTime方法来设置时间戳。

  • 相关阅读:
    【转+补充】在OpenCV for Android 2.4.5中使用SURF(nonfree module)
    Delphi StarOffice Framework Beta 1.0 发布
    Angular ngIf相关问题
    angularjs文档下载
    公众号微信支付开发
    公众号第三方平台开发 教程六 代公众号使用JS SDK说明
    公众号第三方平台开发 教程五 代公众号处理消息和事件
    公众号第三方平台开发 教程四 代公众号发起网页授权说明
    公众号第三方平台开发 教程三 微信公众号授权第三方平台
    公众号第三方平台开发 教程二 component_verify_ticket和accessToken的获取
  • 原文地址:https://www.cnblogs.com/wqj1212/p/2439692.html
Copyright © 2011-2022 走看看