ピンを接続できるようにする
このフィルタの出力ピンとダウンストリームフィルタの入力ピンを接続できるようにしましょう。こちらも基本的に入力ピンと同じ作りです。ただし、入力ピンが繋がっていないときは接続できないように制限します。これは入力ピンが接続されるまで出力ピンのメディアタイプが分からないためです。
まず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;
}
