ピンを接続できるようにする
このフィルタの出力ピンとダウンストリームフィルタの入力ピンを接続できるようにしましょう。こちらも基本的に入力ピンと同じ作りです。ただし、入力ピンが繋がっていないときは接続できないように制限します。これは入力ピンが接続されるまで出力ピンのメディアタイプが分からないためです。
まずGetMediaType
を実装します。入力ピンが接続されておりメディアタイプが分かれば出力ピンのメディアタイプが決定できるので、それを優先メディアタイプとして提示します。このとき入力ピンのメディアタイプからWAVEFORMATEXTENSIBLE
を取得し、チャンネル数を1(モノラル)に修正して提示します。
HRESULT AudioOutPin::GetMediaType(int iPosition, CMediaType *pMediaType) { NOTE1("%S", __FUNCTION__); if(iPosition<0) return E_INVALIDARG; //アップストリームフィルタと接続済み? AudioChSplitterFilter *pFilter=(AudioChSplitterFilter*)m_pFilter; AudioInPin *pPin=pFilter->GetInPin(); if(pPin->IsConnected()==NULL) { return VFW_S_NO_MORE_ITEMS; } if(iPosition>0) { return VFW_S_NO_MORE_ITEMS; } //モノラルに修正して提示する HRESULT hr=pPin->ConnectionMediaType(pMediaType); WAVEFORMATEXTENSIBLE *wfxe= (WAVEFORMATEXTENSIBLE *)pMediaType->Format(); wfxe->Format.nChannels=1; wfxe->Format.nAvgBytesPerSec/=2; wfxe->Format.nBlockAlign/=2; //WAVEFORMATEXTENSIBLEのスピーカ属性を書き換える if(pMediaType->FormatLength()==sizeof(WAVEFORMATEXTENSIBLE)) { wfxe->dwChannelMask=SPEAKER_FRONT_CENTER; } return hr; }
次にCheckMediaType
です。入力ピンのメディアタイプを基に、チャンネルが1であること、周波数およびサンプルあたりのビット数が一致することを確認します。
HRESULT AudioOutPin::CheckMediaType(const CMediaType *pmt) { NOTE1("%S", __FUNCTION__); AudioChSplitterFilter *pFilter=(AudioChSplitterFilter*)m_pFilter; AudioInPin *pPin=pFilter->GetInPin(); if(pPin->IsConnected()==NULL) { return S_FALSE; } CMediaType in_type; pPin->ConnectionMediaType(&in_type); WAVEFORMATEXTENSIBLE *wfxe_in= (WAVEFORMATEXTENSIBLE *)in_type.Format(); int eq_major =(pmt->majortype==MEDIATYPE_Audio); int eq_sub =(pmt->subtype==MEDIASUBTYPE_PCM); int eq_format=(pmt->formattype==FORMAT_WaveFormatEx); if(!eq_major || !eq_sub || !eq_format) return S_FALSE; if(pmt->Format()==NULL) return S_FALSE; if(pmt->FormatLength()!=sizeof(WAVEFORMATEX) && pmt->FormatLength()!=sizeof(WAVEFORMATEXTENSIBLE)) { return S_FALSE; } WAVEFORMATEXTENSIBLE *wfxe= (WAVEFORMATEXTENSIBLE *)pmt->Format(); if((wfxe->Format.wFormatTag==WAVE_FORMAT_EXTENSIBLE || wfxe->Format.wFormatTag==WAVE_FORMAT_PCM) && wfxe->Format.nChannels==1 && wfxe->Format.nSamplesPerSec==wfxe_in->Format.nSamplesPerSec && wfxe->Format.wBitsPerSample==wfxe_in->Format.wBitsPerSample) { return S_OK; } return S_FALSE; }
送信バッファを設定する
CBaseOutputPin::DecideBuffersize
をオーバーライドして送信用のアロケータプロパティを設定します。アロケータはバッファの確保や解放を行います。アロケータプロパティを設定しバッファの数とサイズを決めます。
下記のコードは最低限のコードです。実際にはエラーチェックやバッファサイズのアラインメントを合わせることが必要です。添付ソースコードを参照してください。
HRESULT AudioOutPin::DecideBufferSize( IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest) { NOTE1("%S", __FUNCTION__); HRESULT hr; // アロケータに要求するバッファサイズを設定する WAVEFORMATEXTENSIBLE *wfxe=(WAVEFORMATEXTENSIBLE *)m_mt.pbFormat; pRequest->cBuffers=1; pRequest->cbBuffer=wfxe->Format.nAvgBytesPerSec; // アロケータプロパティを設定する ALLOCATOR_PROPERTIES Actual; hr=pAlloc->SetProperties(pRequest, &Actual); // 要求を満たせなかったら E_FAIL を返す if (Actual.cbBuffer<pRequest->cbBuffer) return E_FAIL; return S_OK; }
COutputQueueの作成・解放
フィルタグラフの状態が停止からポーズになるとピンがアクティブになります。このときCBasePin::Active
というメソッドが呼ばれます。出力ピンでこのメソッドをオーバーライドし、COutputQueue
のインスタンスを作成します。停止状態になるとピンが非アクティブになりCBasePin::Inactive
が呼び出されます。このメソッドもオーバーライドしCOutputQueue
のインスタンスを解放します。
Active
とInactive
をオーバーライドするときは、必ず基底クラスのメソッドを呼び出します。
HRESULT AudioOutPin::Active(void) { NOTE1("%S", __FUNCTION__); HRESULT hr=S_OK; if(IsConnected()) { hr=__super::Active(); if(FAILED(hr)) { return hr; } // hrをS_OKにする必要がある hr=S_OK; m_OutQ=new COutputQueue( GetConnected(), &hr ,FALSE, TRUE); } return hr; } HRESULT AudioOutPin::Inactive(void) { NOTE1("%S", __FUNCTION__); HRESULT hr=S_OK; hr=__super::Inactive(); if(m_OutQ) { delete m_OutQ; m_OutQ=NULL; } return hr; }