Microsoft DirectX 8.0 |
DMO サンプルは、Microsoft® DirectX® メディア オブジェクト (DMO) のサンプルである。MPEG-1 ビデオ パケットを入力とし、出力ストリームを 2 つ生成する。最初の出力ストリームには、RGB 565 フォーマットのビデオ フレームが含まれている。各フレームは MPEG-1 ビデオから取得したタイム コードを表示し、それがない場合は何も表示しない。2 つめの出力ストリームは、タイム コードの付いた、オプションのテキスト ストリームである。
DMO サンプルは、IMediaObjectImpl 基底クラス テンプレートを使用して、IMediaObject インターフェイスを実装する。このテンプレートの使用法の詳細については、「DMO 基底クラスの使い方」を参照すること。Active Template Library (ATL) は、登録、集合、IUnknown、DLL エントリ ポイントなど、さまざまな COM の詳細を処理する。
ソース :(SDK ルート)\samples\Multimedia\DirectShow\DMO\DMOSample
このプロジェクト ワークスペースでは、Dmosample.dll という名前の DLL を作成する。Regsvr32 ユーティリティを使って DLL を作成する。この DMO の動作を見るには、 Microsoft® DirectShow® GraphEdit ユーティリティを使用する。ただし、MPEG-1 ビデオ ファイルが必要である。次の手順に従って実行する。
グラフを実行すると、タイム コードを表示する [Video] ウィンドウが現れる。
DMO サンプルには、以下のソースおよびヘッダー ファイルが含まれている。
DMO サンプルは、以下のリソース ファイルも使用する。
次の注意は、実装について詳細に説明している。
Dmosample.cpp
このファイルには、ATL が DMO オブジェクトを作成して登録するのに使用するオブジェクト マップが含まれる。また、エクスポートされる DLL 関数も含まれる。このような関数には、エントリ ポイント関数 (DllMain)、および COM に必要な関数 (DllCanUnloadNow、DllGetClassObject、DllRegisterServer、および DllUnregisterServer) がある。
ATL COM AppWizard は、このファイルに含まれるコードの大部分を自動生成する。次の 2 つが追加される。
- DllRegisterServer 関数は、DMORegister を呼び出して、DMO に関するレジストリ情報を追加する。DMO は DMOCATEGORY_VIDEO_DECODER カテゴリに登録される。
- DllUnregisterServer 関数は DMOUnregister を呼び出す。
Resource.h
このヘッダー ファイルで宣言される 1 つの定数 IDR_SAMPLE は、ATL の自動登録メカニズムで使用される。定数 IDR_SAMPLE は、テキスト リソースを識別する。これはリソース ファイル Sample.rgs で定義され、リソース ファイル Dmosample.rc によりインポートされる。ヘッダー ファイル Sample.h には、次の行がある。
DECLARE_REGISTRY_RESOURCEID(IDR_SAMPLE)これにより、ATL は IDR_SAMPLE リソースに宣言された登録情報を使用できる。
Sample.h
DEFINE_GUID マクロは、DMO のクラス識別子 (CLSID) を宣言する。
CSample クラスは次のクラスから派生する。
- IMediaObjectImpl。DMO 基底クラス。テンプレート パラメータは、DMO が 1 つの入力ストリームと 2 つの出力ストリームを持つことを指定する。
- CComObjectRootEx。スレッド モデルを宣言する ATL クラス。テンプレート パラメータ CComMultiThreadModel は、スレッド対応オブジェクトを作成し、Lock メソッドと Unlock メソッドを提供する。
- CComCoClass。標準 COM オブジェクトを宣言する ATL クラス。
CSample は、 カスタム マーシャリングを実行するフリー スレッド マーシャラ オブジェクトを集める。COM ライブラリが、サンプル プロセス内の複数のスレッドにまたがって CSample ポインタをマーシャリングする場合、まったく同じポインタが返される。COM ライブラリが複数のプロセスまたは複数のマシンにまたがってオブジェクトをマーシャリングしようとすると、エラーが発生する。ATL は、フリー スレッド マーシャラを集成するために必要なすべてのコードを追加する。このコードは、FinalConstruct メソッドと FinalRelease メソッドに現れる。COM マップ内の COM_INTERFACE_ENTRY_AGGREGATE エントリは、フリー スレッド マーシャラに IMarshal インターフェイスを委任する。
CSample クラスは、次のメンバ変数を宣言する。
m_pUnkMarshaler フリー スレッド マーシャラ オブジェクトへのポインタ。 m_pBuffer 入力バッファへのポインタ。DMO はすべての入力を処理するまで、バッファの参照カウントを保持する。 m_pbData 入力バッファ内の次のバイトへのポインタ。 m_cbData 未処理のバイト数。 m_rtFrame 最後の出力フレームのタイム スタンプ。 m_StreamState MPEG データを解析する、CStreamState ヘルパ クラスのインスタンス。 m_bPicture DMO が出力するピクチャ情報を持っているかどうかを示す、ブール型フラグ。
Sample.cpp
このファイルは、CSample クラスにメソッドを実装する。
InternalGetInputStreamInfo
DMO は、任意のバウンダリに整列された任意のバイト数を処理できるので、このメソッドはゼロ フラグを返す。
InternalGetOutputStreamInfo
最初の出力ストリームは、固定サイズのサンプル全体を一度に作成する。これは、ビデオ デコーダでよく行われる。2 番目の出力ストリームはオプションである。返されるフラグは、これらの属性を示す。
入力タイプは、FORMAT_MPEGVide フォーマット タイプの MPEG-1 ビデオ ペイロードでなければならない。入力タイプの設定後、メソッドはフォーマットの変更を受け付けない。
このメソッドは、出力フォーマットを検証する。出力ストリームは次の 2 つである。
- ストリーム 0。このストリームでサポートされる唯一のメディア タイプは RGB-565 である。実際のビデオ デコーダは通常、複数のフォーマットをサポートする。また、出力のフレーム サイズは、入力のフレーム サイズと一致しなければならない。これは、実際のビデオ デコーダの多くに当てはまる。このストリームは、入力タイプが設定されてからでないと設定できない。
- ストリーム 1。メディア タイプは MEDIATYPE_Text でなければならない。
タイプの設定後、新しいタイプが現在のタイプに一致しない場合、メソッドは失敗する。DMO がストリーミング中にフォーマット変更を処理できない場合は、同様のコードを含める必要がある。実際、サンプル DMO は、1 度に 1 つの出力フレームを生成するので、フォーマット変更を容易に受け入れることができる。
InternalGetInputType
このメソッドは、タイプを返さない。このため、あらゆるインデックス値が範囲外となり、戻り値は DMO_E_NO_MORE_ITEMS である。詳細については、「IMediaObject::GetInputType」を参照すること。
InternalGetOutputType
入力タイプが設定されていない場合、このメソッドはタイプを返さない。設定されている場合、各ストリームに 1 つのタイプが返される。ストリーム 0 の場合、入力サイズに等しいフレーム サイズの RGB-565 が返される。ストリーム 1 の場合、MEDIATYPE_Text が返される。
InternalGetInputSizeInfo
入力ストリームの最小バッファ サイズは 1 バイトであり、整列要件はない。ストリームはルックアヘッドを実行しない。
InternalGetOutputSizeInfo
ストリーム 0 の場合、バッファは出力サンプルを保持できるサイズが必要である。ストリーム 1 の場合、バッファはタイム スタンプ付きのテキスト文字列を保持できるサイズが必要である。
InternalFlush
このメソッドは、m_pBuffer (ATL スマート ポインタ) を NULL に設定することで、入力バッファを解放する。また、CStreamState オブジェクトをリセットする InternalDiscontinuity メソッドも呼び出す。
InternalProcessInput
このメソッドは、可能な限り多くの入力データを処理する。処理は次の手順で実行される。
- Calls IMediaBuffer::GetBufferAndLength メソッドを呼び出して、入力データへのポインタと入力データのサイズを取得する。
- 入力バッファへの参照カウントを保持する。m_pBuffer 変数は、ATL スマート ポインタなので、この変数に値を設定すると、IUnknown::AddRef メソッドを呼び出す効果を持つ。
- タイム スタンプを CStreamState オブジェクトに渡す。サンプルにタイム スタンプがない場合は、値 INVALID_TIME を使用する。
- プロセス ヘルパ メソッドを呼び出して、データを処理する。
InternalProcessOutput
出力するデータがない場合、このメソッドは S_FALSE を返す。データがある場合、出力データを生成する。ストリーム 0 の場合、次の手順で実行される。
- 出力バッファが出力データを保持するのに十分なサイズであることを確認する。ない場合、メソッドはエラーを返す。
- OurFillRect メソッドを呼び出して、背景を描画し、DrawOurText メソッドを呼び出して、テキストを描画する。
- タイム スタンプを設定する。このフレームに有効なタイム スタンプがある場合は、それを使用する。ない場合は、前のタイム スタンプを平均フレーム レートでインクリメントする。
- Process メソッドを再び呼び出して、入力バッファに残っていればすべてのデータを処理する。これにより出力データが増えた場合、DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE フラグを設定する。
ストリーム 1 はオプションであるので、呼び出し側はストリーム 1 用のバッファを割り当てていないことがある。ストリーム 1 に出力バッファがないとしても、DMO はタイム コードをテキスト文字列として書き込む。タイム スタンプと処理フラグはストリーム 0 のものを参照する。
DMO に前の入力バッファの参照カウントがまだある場合、DMO はそれ以上の入力を受け付けない。
Process
このプライベート メソッドは、CStreamState オブジェクトを更新しながら、入力データを 1 度に 1 バイトずつ順に処理する。入力データを処理し終えるまでに CStreamState オブジェクトがピクチャ バウンダリを見つけると、Process メソッドは S_OK を返す。ピクチャ バウンダリがない場合は、S_FALSE を返す。