CodeZine(コードジン)

特集ページ一覧

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

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

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/11/10 14:00

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

目次

はじめに

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

対象読者

  • 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();
}

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

バックナンバー

連載:DirectShowフィルタの作成
All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5