SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

DirectShowフィルタの作成

オーディオチャンネルを分離する
DirectShowフィルタの作成 - 後編

複数の出力ピンを持つDirectShowフィルタの作成方法

  • X ポスト
  • このエントリーをはてなブックマークに追加

ピンを接続できるようにする

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

 まず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のインスタンスを解放します。 

 ActiveInactiveをオーバーライドするときは、必ず基底クラスのメソッドを呼び出します。

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;
}

次のページ
ダウンストリームフィルタへの通知

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
DirectShowフィルタの作成連載記事一覧

もっと読む

この記事の著者

syu5()

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/3090 2008/12/13 13:49

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング