SHOEISHA iD

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

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

DirectShowフィルタの作成

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

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

ダウンロード サンプルコード (6.3 KB)

入力ピンクラスの実装

クラス定義

 フィルタクラスの定義が終わったので、次は入力ピンクラスAudioInPinを定義しましょう。フィルタクラスをCBaseFilterから派生させた場合、基本的に入力ピンクラスはCBaseInputPinから派生させます。いくつかオーバーライドすべきメソッドがあります(表4)。

表4.オーバーライドすべきメソッド
メソッド名 説明
BeginFlush フラッシュの開始時に呼ばれる。
EndFlush フラッシュの終了時に呼ばれる。
EndOfStream ストリーム終了通知を受け取るときに呼ばれる。
Receive サンプルを受信したときに呼ばれる。
GetMediaType 優先メディアタイプを提示する。
CheckMediaType ピンが特定のメディア タイプを受け入れるかどうかを判定する(純粋仮想)。
class AudioInPin : public CBaseInputPin
{
public:
    AudioInPin(CBaseFilter *pFilter
        , CCritSec *pLock
        , HRESULT *phr);
    virtual ~AudioInPin();
    // IPin
    STDMETHODIMP BeginFlush(void);
    STDMETHODIMP EndFlush(void);
    STDMETHODIMP EndOfStream(void);
    STDMETHODIMP Receive(IMediaSample *pSample);
    // CBaseInputPin
    HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
    HRESULT CheckMediaType(const CMediaType *pmt);
};

コンストラクタ・デストラクタ

 入力ピンのコンストラクタでは特に必要な処理はありません。フィルタクラスと同様に、基底クラスであるCBaseInputPinを初期化するだけです。

AudioInPin::AudioInPin(CBaseFilter *pFilter
    , CCritSec *pLock, HRESULT *phr) :
    CBaseInputPin(INPUT_PIN_NAME, pFilter, pLock, phr, INPUT_PIN_NAME)
{
    NOTE1("%S", __FUNCTION__);
}

 デストラクタでは何もすることがないので、コードは割愛します。

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

 今回作成するフィルタの入力ピンとアップストリームフィルタにある出力ピンを接続できるようにしましょう。ピン同士を接続するには、お互いのピンが許容するメディアタイプで接続する必要があります。

 まずGetMediaTypeを実装します。このメソッドでは、このピンが受け入れる優先メディアタイプを提示します。今回は何も提示しません。原則、フィルタは上流から下流に向かって順に接続されるため、上流フィルタから出力するメディアタイプが確定されていくからです。そのため基本的に入力ピンが優先メディアタイプを提示する必要はありません。

HRESULT AudioInPin::GetMediaType(int iPosition, CMediaType *pMediaType) {
    NOTE1("%S",__FUNCTION__);
    if(iPosition<0)
        return E_INVALIDARG;
    return VFW_S_NO_MORE_ITEMS;
}

 次にCheckMediaTypeです。このメソッドは引数として渡されたメディアタイプで接続可能かどうかを判定します。今回はステレオのオーディオストリームのみ接続可能として判定する処理を実装します。

HRESULT AudioInPin::CheckMediaType(const CMediaType *pmt) {
    NOTE1("%S", __FUNCTION__);
    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) {
        if(pmt->Format()==NULL)
            return S_FALSE;
        if(pmt->FormatLength()!=sizeof(WAVEFORMATEXTENSIBLE) &&
            pmt->FormatLength()!=sizeof(WAVEFORMATEX))
        {
            return S_FALSE;
        }
        WAVEFORMATEXTENSIBLE *wfxe=
            (WAVEFORMATEXTENSIBLE *)pmt->Format();
        if((wfxe->Format.wFormatTag==WAVE_FORMAT_EXTENSIBLE ||
            wfxe->Format.wFormatTag==WAVE_FORMAT_PCM) &&
            wfxe->Format.nChannels==2)
        {
            return S_OK;
        }
        return S_FALSE;
    }
    return S_FALSE;
}
WAVEFORMATEXTENSIBLE

 上記コードでは、WAVEFORMATEXだけでなく、多チャンネル、高精度PCMフォーマットを表すときに使われるWAVEFORMATEXTENSIBLEも許容する判定処理を行っています。

 WAVEFORMATEXTENSIBLEではwFormatTagの値がWAVE_FORMAT_EXTENSIBLEになります。オーディオサブタイプのGUIDはwFormatTagによって変化しますが、無圧縮の整数PCMであるため同じ値となります。

 残りのメソッドは、サンプルの転送に関わることなので後編で実装します。

動作確認

 まだ未実装な個所があるので、適当に修正してコンパイルします。その後、GraphEditを使って動作確認をしてみます(図3)。

 ファイルソースフィルタをアップストリームフィルタとして接続できないことに注意してください。ファイルソースフィルタはプルモデルとよばれる出力ピンを持ちますが、作成したフィルタはそれに対応していません。そこでプルモデルの出力ピンと接続できるWave Parserを間に挟みます。

図3. 動作結果
図3. 動作結果

前編のまとめ

 本稿ではCBaseFilterから派生したフィルタクラスを実装しました。次にCBaseInputPinから派生した入力ピンクラスを実装し、アップストリームフィルタに接続するところまでできました。後編では、以下に挙げる残りのタスクを進めていきます。

  • 出力ピンを実装し、接続できるようにする。
  • 出力ピンごとにストリーミングスレッドを作成する。
  • サンプルを転送する。

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

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
DirectShowフィルタの作成連載記事一覧

もっと読む

この記事の著者

syu5()

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3059 2008/10/27 14:00

おすすめ

イベント

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

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

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

メールバックナンバー