カクタスソフトウェア
カクタスソフトウェア
サウンド MIDI マルチメディア アプリケーション

プロセスの実行

メディアタイプの設定が終わればいつでもプロセスを実行することができます。プロセスの実行には、入力と出力を個々に行う一般的な処理と、入出力を1つのバッファで行うインプレイス処理の2つがあります。

一般的な処理

入力処理と出力処理を分離して行うのは、入出力でメディアタイプが異なる場合や、生成されるデータサイズが異なる場合があるためです。特に入出力でデータサイズが異なる場合、1回の入力処理で複数回の出力処理が必要になる場合(あるいはその逆)があります。

以下に一般的な手順を示します。入力データが準備できしだいプロセス処理を繰り返し呼び出します。

プロセス処理()
{
    データを入力バッファに設定
    入力処理を実行
    エラー処理

    while (1)
    {
        出力処理を実行
        エラー処理
        出力データを取り込む
        if (INCOMPLETEフラグ)   continue;
        else                    break;
    }
}

入力処理

入力処理は、IMediaObject::ProcessInput関数を用います。

HRESULT ProcessInput(
    DWORD           dwInputStreamIndex,
    IMediaBuffer*   pBuffer,
    DWORD           dwFlags, 
    REFERENCE_TIME  rtTimestamp, 
    REFERENCE_TIME  rtTimelength);

dwInputStreamIndex

DMOが複数のストリームを支援するとき、ストリームを識別するためのインデックスです。ストリームが1つしかないときはゼロを指定します。ストリームの数はIMediaObject::GetStreamCount関数で取得することができます。

通常オーディオエフェクター用DMOのストリーム数は1です。

pBuffer

IMediaBufferインターフェースへのポインターです。DMOで用いるバッファはIMediaBufferインターフェースを支援する必要があります。以下にIMediaBufferインターフェースを支援するクラス例を示します。

class CMediaBuffer : public IMediaBuffer
{
public:
    CMediaBuffer(DWORD cbMaxLength);
    ~CMediaBuffer();

    HRESULT GetBufferAndLength(BYTE** ppBuffer, DWORD* pcbLength);
    HRESULT GetMaxLength(DWORD* pcbMaxLength);
    HRESULT SetLength(DWORD cbLength);
}

MaxLengthはコンストラクタでアロケートされた利用可能なバッファサイズです。Lengthは有効なデータサイズで、MaxLength以下でなければなりません。バッファはデストラクタで開放するようにします。

C++による実装例がMSDN「IMediaBufferの実装」にありますので参照して下さい。またC#で実装した例を本書のセクション「DMOSys」で紹介しています。あわせて参照して下さい。

dwFlags

DMO_INPUT_DATA_BUFFER_FLAGS列挙型フラグを指定します。

フラグ 意味
DMO_INPUT_DATA_BUFFERF_SYNCPOINT 0x1 データの先頭が同期ポイントである。
DMO_INPUT_DATA_BUFFERF_TIME 0x2 バッファのタイムスタンプが有効である。
DMO_INPUT_DATA_BUFFERF_TIMELENGTH 0x4 バッファが示す時間が有効である。

rtTimestamp

DMO_INPUT_DATA_BUFFERF_TIMEフラグが指定されたとき、タイムスタンプの値を示します。

rtTimelength

DMO_INPUT_DATA_BUFFERF_TIMELENGTHフラグが指定されたとき、バッファの時間を示します。

エラーコード

コード 意味
DMO_E_INVALIDSTREAMINDEX 無効なストリームインデックス
DMO_E_NOTACCEPTING これ以上入力を受け付けられない
S_FALSE 出力が生成されなかった
S_OK 正常終了

DMO_E_NOTACCEPTINGは、内部バッファが一杯という意味なので、入力処理をスルーし出力処理のみを行います。S_FALSEは今回の入力で生成された出力はないという意味なので、入力処理のみを行います。S_OKは入力処理が正常終了したので出力処理に進みます。

出力処理

出力処理には、IMediaObject::ProcessOutput関数を用います。

HRESULT ProcessOutput(
    DWORD           dwFlags,
    DWORD           cOutputBufferCount,
    DMO_OUTPUT_DATA_BUFFER* pOutputBuffers,
    DWORD*          pdwStatus);

dwFlags

DMO_PROCESS_OUTPUT_FLAGS列挙型フラグを指定します。

フラグ 意味
DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER 0x1 出力バッファがNULLのとき、出力を破棄する

cOutputBufferCount

出力用バッファ配列の数。バッファの数はDMOが支援しているストリームの数に等しくなければなりません。ストリームの数はIMediaObject::GetStreamCount関数で取得します。

pOutputBuffers

DMO_OUTPUT_DATA_BUFFER構造体の配列へのポインターです。配列の数はcOutputBufferCountで示します。

pdwStatus

予約済みの変数です。利用しません。

エラーコード

コード 意味
E_FAIL 失敗
E_INVALIDARG 引数が無効です
E_POINTER ポインタが無効です
S_FALSE 出力が生成されなかった
S_OK 正常終了

DMO_OUTPUT_DATA_BUFFER構造体

ProcessOutput関数で出力用パラメータを格納します。

typedef struct _DMO_OUTPUT_DATA_BUFFER {
    IMediaBuffer    *pBuffer;
    DWORD           dwStatus;
    REFERENCE_TIME  rtTimestamp; 
    REFERENCE_TIME  rtTimelength;
} DMO_OUTPUT_DATA_BUFFER, *PDMO_OUTPUT_DATA_BUFFER;

pBuffer

IMediaBufferインターフェースへのポインターです。

dwStatus

IMediaBufferの容量を超えて出力すべきデータが残っているとき、dwStatusにはDMO_OUTPUT_DATA_BUFFERF_INCOMPLETEフラグが設定されます。アプリケーションはこのフラグが立っていたら、引き続きProcessOutput関数を実行しデータを取り込む必要があります。

rtTimestamp、rtTimelength

ProcessInput関数を参照して下さい。

インプレイス処理

インプレイス処理とは、入力バッファと出力バッファを共用する方法です。出力データは入力データに上書きされます。メモリの利用効率が高く、一般的な処理より高速で動作します。インプレイス処理が可能な場合、IMediaObjectはIMediaObjectInPlaceインターフェスを支援します。インプレイス処理を行うには以下の条件を満たす必要があります。

インプレイス処理が可能な場合でもIMediaObjectインターフェースは実装されているので、通常の入出力処理を行うことができます。ただしインプレイス処理が可能な状況でも、IMediaObjectInPlaceインターフェスが支援されるという保障はありません。

インプレイス処理が可能な場合、通常の入出力処理とインプレイス処理のどちらで処理を行っても構いませんが、一方で処理を始めたら最後まで同じ方法で処理して下さい。

インプレイス処理は、IMediaObjectInPlace::Process関数を用います。

HRESULT Process(
    ULONG           ulSize,
    BYTE            *pData,
    REFERENCE_TIME  refTimeStart,
    DWORD           dwFlags);

ulSize

入力データのサイズです。単位はバイト。入力データがないときはバッファのサイズを示します。

pData

バッファへのポインターです。入力データを設定し関数を実行します。正常終了すると出力が得られます。

インプレイス処理ではIMediaBufferインターフェースを用いません。Process関数は直接バッファのアドレスを保持します。

refTimeStart

タイムスタンプの値を示します。

利用しないときはゼロで良いと思いますが、執筆時点で詳しい資料が見つかっていません。

dwFlags

_DMO_INPLACE_PROCESS_FLAGS列挙型フラグを指定します。通常はDMO_INPLACE_NORMALを指定し、エフェクトテールを取得するときは、DMO_INPLACE_ZEROを指定します。

フラグ 意味
DMO_INPLACE_NORMAL 0x0 有効な入力データがある
DMO_INPLACE_ZERO 0x1 入力データはない

エラーコード

コード 意味
E_FAIL 失敗。
S_FALSE 成功。エフェクトテールが残っている。
S_OK 成功。すべてのデータが処理された。

エフェクトテール

例えばリバーブは入力が無音になった後もしばらく残響が残ります。残響の様なエフェクトによって入力サイズを超えて生成されたデータをエフェクトテールと言います。

Process関数がS_FALSEを戻したときはエフェクトテールが残っているので以下の処理を行います。

エフェクトテールを受け取るためのバッファを用意し、バッファサイズとポインターをセットします。バッファはゼロクリアしておくこと。フラグにはDMO_INPLACE_ZEROを設定します。Process関数を実行しエフェクトテールを取得します。関数がS_OKを戻すまでこの処理を繰り返します。

生成されたエフェクトテールのサイズを厳密に求めることはできません。分解能はエフェクトテールを受け取るために用意したバッファサイズとなります。

実行スレッド

DMOはシングルスレッドで動作します。プロセスの実行はDMOオブジェクトを作成したのと同じスレッドで行って下さい。プロセスの実行タイミングが別のスレッドによって作成されるときは、スレッドメッセージやInvokeなどの手段を用いてオブジェクトを作成したスレッドから実行できるよう工夫する必要があります。

ドキュメントの先頭へ

カクタスソフトウェア 技術協力 資料室 資料室の広場 SourceForge.jp お問い合わせ