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方法来设置时间戳。

  • 相关阅读:
    类与对象
    类的声明与实例化
    面向对象的基本概念
    css下拉导航栏代码
    面向对象的三大特性
    面向对象三大基本特性,五大基本原则
    dom事件
    PHP 流程
    权限 查找
    留言板案例
  • 原文地址:https://www.cnblogs.com/wqj1212/p/2439692.html
Copyright © 2011-2022 走看看