如何寫filter的轉帖 之 ----開發source filter的source sourcestream兩個基類介紹

轉貼地址:http://www.cnblogs.com/wqj1212/archive/2012/04/09/2439692.html

第一個是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方法來設置時間戳。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章