はじめに
前編では、フィルタクラスと入力ピンクラスを実装し、アップストリームフィルタと接続できるようになりました。後編では、出力ピンクラスを実装し、オーディオサンプルを転送できるようにします。
対象読者
- C++言語が分かる方
- DirectShowアプリケーションを作成したことのある方
- DirectShowフィルタの作成に興味のある方
前回の記事
本稿は前編の続きです。前回の記事を先にお読みください。クラス図も前編の記事に示してます。
出力ピンクラスの実装
クラス定義
出力ピンクラスAudioOutPin
を定義しましょう。これはCBaseOutputPin
から派生させます。ここでも他のクラスと同様にいくつかオーバーライドすべきメソッドがあります(表1)。
メソッド名 | 説明 |
NonDelegatingQueryInterface | インターフェイスの問い合わせに応える。 |
Active | ピンがアクティブになったとき呼ばれる。 |
Inactive | ピンが非アクティブになっとき呼ばれる。 |
DeliverBeginFlush | フラッシュ処理の開始を入力ピンに要求する。 |
DeliverEndFlush | フラッシュ処理の終了を入力ピンに要求する。 |
DeliverEndOfStream | ストリーム終了通知を入力ピンに出力する。 |
DeliverNewSegment | 新セグメント通知を入力ピンへ出力する。 |
Deliver | サンプルを入力ピンへ出力する。 |
DecideBufferSize | アロケータプロパティを設定してバッファサイズを決める(純粋仮想)。 |
GetMediaType | 優先メディアタイプを提示する。 |
CheckMediaType | ピンが特定のメディア タイプを受け入れるかどうかを判定する(純粋仮想)。 |
表1における「入力ピン」とはダウンストリームフィルタの入力ピンのことです。
class AudioOutPin : public CBaseOutputPin { int m_Channel; // 出力ch 0=L 1=R COutputQueue* m_OutQ; CPosPassThru* m_PosPass; public: AudioOutPin(LPCTSTR name, CBaseFilter *pFilter , CCritSec *pLock , HRESULT *phr, int ch); virtual ~AudioOutPin(); STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); // CBaseOutputPin HRESULT Active(void); HRESULT Inactive(void); HRESULT DeliverBeginFlush(void); HRESULT DeliverEndFlush(void); HRESULT DeliverEndOfStream(void); HRESULT DeliverNewSegment( REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); HRESULT Deliver(IMediaSample *pSample); HRESULT DecideBufferSize( IMemAllocator *pAlloc , ALLOCATOR_PROPERTIES *ppropInputRequest); HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); HRESULT CheckMediaType(const CMediaType *pmt); };
上記のコードで使っている2つのクラス、COutputQueue
とCPosPassThru
について少し説明しておきます。なおいずれも基底クラスライブラリで定義されています。
COutputQueue
とは、内部で新たなストリーミングスレッドを生成することにより、サンプルを非同期的に出力します。その名のとおりキューを持っており、複数サンプルの出力もサポートしています。もし同期的に処理をした場合、ある出力ピンのダウンストリームフィルタで処理をしている間、もう一方のピンの処理が始まりません。たとえば映像と音声を分離するフィルタの場合、映像のデコードやレンダリングを行っている間、音声のレンダリングが行われません。また、フィルタグラフが停止から実行状態に遷移するとき、ポーズ状態を経由しますが、レンダリングフィルタによってはポーズ状態になり最初のサンプルを受信した後、実行状態に遷移するまでロックすることがあります。これは複数のレンダリングフィルタを使った場合にデッドロックが発生する原因となります。
もう一方のCPosPassThru
はシーク処理をアップストリームフィルタに任せるクラスです。詳しくは「シークのサポート」で解説します。
コンストラクタ・デストラクタ
入力ピンと同様、特に必要な処理はありません。基底クラスであるCBaseOutputPin
を初期化するだけです。
AudioOutPin::AudioOutPin(LPCTSTR name, CBaseFilter *pFilter , CCritSec *pLock, HRESULT *phr, int ch) : CBaseOutputPin(name, pFilter, pLock, phr, name) , m_OutQ(NULL), m_Channel(ch) { NOTE1("%S", __FUNCTION__); }
デストラクタではCOutputQueue
およびCPosPassThru
の解放を行います。
AudioOutPin::~AudioOutPin() { NOTE1("%S", __FUNCTION__); if(m_OutQ) delete m_OutQ; if(m_PosPass) m_PosPass->Release(); }