SHOEISHA iD

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

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

DirectShowフィルタの作成

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

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

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

 ステレオオーディオをL/Rチャンネルで分離するフィルタの作成を通じて、1つの入力ピンと2つの出力ピンを持つDirectShowフィルタの作成方法を解説します。後編では出力ピンとサンプルを転送するところまでを実装し、動作確認します。

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

はじめに

 前編では、フィルタクラスと入力ピンクラスを実装し、アップストリームフィルタと接続できるようになりました。後編では、出力ピンクラスを実装し、オーディオサンプルを転送できるようにします。

対象読者

  • C++言語が分かる方
  • DirectShowアプリケーションを作成したことのある方
  • DirectShowフィルタの作成に興味のある方

前回の記事

 本稿は前編の続きです。前回の記事を先にお読みください。クラス図も前編の記事に示してます。

出力ピンクラスの実装

クラス定義

 出力ピンクラスAudioOutPinを定義しましょう。これはCBaseOutputPinから派生させます。ここでも他のクラスと同様にいくつかオーバーライドすべきメソッドがあります(表1)。

表1.オーバーライドすべきメソッド
メソッド名 説明
NonDelegatingQueryInterface インターフェイスの問い合わせに応える。
Active ピンがアクティブになったとき呼ばれる。
Inactive ピンが非アクティブになっとき呼ばれる。
DeliverBeginFlush フラッシュ処理の開始を入力ピンに要求する。
DeliverEndFlush フラッシュ処理の終了を入力ピンに要求する。
DeliverEndOfStream ストリーム終了通知を入力ピンに出力する。
DeliverNewSegment 新セグメント通知を入力ピンへ出力する。
Deliver サンプルを入力ピンへ出力する。
DecideBufferSize アロケータプロパティを設定してバッファサイズを決める(純粋仮想)。
GetMediaType 優先メディアタイプを提示する。
CheckMediaType ピンが特定のメディア タイプを受け入れるかどうかを判定する(純粋仮想)。

 表1における「入力ピン」とはダウンストリームフィルタの入力ピンのことです。

class AudioOutPin : public CBaseOutputPin
{
    int m_Channel; // 出力ch 0=L 1=R
    COutputQueue* m_OutQ;
    CPosPassThru* m_PosPass;
public:
    AudioOutPin(LPCTSTR name, CBaseFilter *pFilter
                , CCritSec *pLock
                , HRESULT *phr, int ch);
    virtual ~AudioOutPin();
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
    // CBaseOutputPin
    HRESULT Active(void);
    HRESULT Inactive(void);
    HRESULT DeliverBeginFlush(void);
    HRESULT DeliverEndFlush(void);
    HRESULT DeliverEndOfStream(void);
    HRESULT DeliverNewSegment(
        REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
    HRESULT Deliver(IMediaSample *pSample);
    HRESULT DecideBufferSize(
        IMemAllocator *pAlloc
        , ALLOCATOR_PROPERTIES *ppropInputRequest);
    HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
    HRESULT CheckMediaType(const CMediaType *pmt);
};

 上記のコードで使っている2つのクラス、COutputQueueCPosPassThruについて少し説明しておきます。なおいずれも基底クラスライブラリで定義されています。

 COutputQueueとは、内部で新たなストリーミングスレッドを生成することにより、サンプルを非同期的に出力します。その名のとおりキューを持っており、複数サンプルの出力もサポートしています。もし同期的に処理をした場合、ある出力ピンのダウンストリームフィルタで処理をしている間、もう一方のピンの処理が始まりません。たとえば映像と音声を分離するフィルタの場合、映像のデコードやレンダリングを行っている間、音声のレンダリングが行われません。また、フィルタグラフが停止から実行状態に遷移するとき、ポーズ状態を経由しますが、レンダリングフィルタによってはポーズ状態になり最初のサンプルを受信した後、実行状態に遷移するまでロックすることがあります。これは複数のレンダリングフィルタを使った場合にデッドロックが発生する原因となります。

 もう一方のCPosPassThruはシーク処理をアップストリームフィルタに任せるクラスです。詳しくは「シークのサポート」で解説します。

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

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

AudioOutPin::AudioOutPin(LPCTSTR name, CBaseFilter *pFilter
                         , CCritSec *pLock, HRESULT *phr, int ch) :
    CBaseOutputPin(name, pFilter, pLock, phr, name)
    , m_OutQ(NULL), m_Channel(ch)
{
    NOTE1("%S", __FUNCTION__);
}

 デストラクタではCOutputQueueおよびCPosPassThruの解放を行います。

AudioOutPin::~AudioOutPin() {
    NOTE1("%S", __FUNCTION__);
    if(m_OutQ) delete m_OutQ;
    if(m_PosPass) m_PosPass->Release();
}

次のページ
ピンを接続できるようにする

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

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

もっと読む

この記事の著者

syu5()

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング