ダウンストリームフィルタへの通知
ファイルから再生して終端に到達したときや、シークによるフラッシュイベントが発生したとき、アップストリームフィルタから通知を受け取ります。通知を受け取ったらダウンストリームフィルタに通知を転送する必要があります。
![図1. イベントが発生したとき](http://cz-cdn.shoeisha.jp/static/images/article/3090/fig01.gif)
ストリーム終了通知
再生すべきストリームが終わったときに「ストリーム終了通知(EndOfStream)」を受け取ります。主にファイルの終端に到達した場合に発生します。通知を受け取ったフィルタは、ダウンストリームフィルタの入力ピンに対してIPin::EndOfStream
を呼び出します。
フラッシュの開始と終了および新セグメント通知
ファイルを再生中にシークした場合、迅速に新しい位置から再生するためにフラッシュの開始通知が行われます。フィルタは現在処理中または内部で保留しているサンプルを速やかに破棄します。その後フラッシュの終了通知が行われ、フィルタは新しいサンプルを受け付けられる状態になります。最後に、新セグメント通知が行われます。
呼び出すメソッド
通知を受け取るとき、それに対応する入力ピンのメソッドが呼ばれます。次にCBaseOutputPin
の「Deliver」で名前が始まる4つのメソッドをオーバーライドしておき、それを入力ピンから呼び出します。最後に対応するCOutputQueue
のメソッドを呼び出します。例えばフラッシュの開始通知であれば、まずアップストリームフィルタの出力ピンが、入力ピンのBeginFlush
を呼び出します。入力ピンは出力ピンのDeliverBeginFlush
を呼び出します。出力ピンはCOutputQueue::BeginFlush
を呼び出し、出力キューに入れます。COutputQueue
はストリーミングスレッドでダウンストリームフィルタの入力ピンへ渡します(表2、図2)。
種類 | 入力ピン | 出力ピン | COutputQueue |
フラッシュの開始 | BeginFlush | DeliverBeginFlush | BeginFlush |
フラッシュの終了 | EndFlush | DeliverEndFlush | EndFlush |
新セグメント | NewSegment | DeliverNewSegment | NewSegment |
ストリーム終了通知 | EndOfStream | DeliverEndOfStream | EOS |
![図2.フラッシュの開始通知の例](http://cz-cdn.shoeisha.jp/static/images/article/3090/fig02.gif)
//フラッシュの開始通知のコード STDMETHODIMP AudioInPin::BeginFlush(void) { CAutoLock my_lock(m_pLock); NOTE1("%S", __FUNCTION__); __super::BeginFlush(); AudioChSplitterFilter *filter=(AudioChSplitterFilter*)m_pFilter; filter->GetOutPin(0)->DeliverBeginFlush(); filter->GetOutPin(1)->DeliverBeginFlush(); return S_OK; } HRESULT AudioOutPin::DeliverBeginFlush() { if(m_OutQ) m_OutQ->BeginFlush(); return S_OK; }
シークのサポート
フィルタグラフに対してシーク要求を行うと、各レンダリングフィルタにそれが通知されます。要求を受け取ったフィルタはシークをサポートしていれば、その処理を行い、そうでなければアップストリームフィルタへ要求を渡します。このシーク要求を渡す処理をしてくれるのがCPosPassThru
です。
出力ピンクラスでCUnknown::NonDelegatingQueryInterface
をオーバーライドし、シーク用のインターフェイスであるIID_IMediaPosition
かIID_IMediaSeeking
のインターフェイスが要求されたら、インスタンスが無い場合は作成し、CPosPassThru
のQueryInterface
を呼び出します。
STDMETHODIMP AudioOutPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) { HRESULT hr; if(riid==IID_IMediaPosition || riid==IID_IMediaSeeking) { if(m_PosPass==NULL) { hr=CreatePosPassThru(GetOwner(), FALSE , m_pFilter->GetPin(0), (IUnknown**)&m_PosPass); if (FAILED(hr)) return hr; } return m_PosPass->QueryInterface(riid, ppv); } return __super::NonDelegatingQueryInterface(riid, ppv); }