轉貼地址: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方法來設置時間戳。