非同期 MFT
このトピックでは、Media Foundation 変換 (MFT) の非同期データ処理について説明します。
Note
このトピックは、Windows 7 以降に適用されます。
- 非同期 MFT について
- 一般的な要件
- イベント
- ProcessInput
- ProcessOutput
- ドレイン中
- フラッシュ
- マーカー
- 変更の書式設定
- 属性
- 非同期 MFT のロック解除
- MFT のシャットダウン
- 登録と列挙
- 関連トピック
非同期 MFT について
Windows Vista で MFT が導入されたとき、API は 同期 データ処理用に設計されていました。 そのモデルでは、MFT は常に入力の取得を待機しているか、出力の生成を待機しています。
一般的なビデオ デコーダーについて考えてみましょう。 デコードされたフレームを取得するために、クライアントは IMFTransform::P rocessOutput を呼び出します。 デコーダーにフレームをデコードするのに十分なデータがある場合、MFT がフレームをデコードする間、 ProcessOutput はブロックします。 それ以外の場合、 ProcessOutput は MF_E_TRANSFORM_NEED_MORE_INPUTを返し、クライアントが IMFTransform::P rocessInput を呼び出す必要があることを示します。
デコーダーが 1 つのスレッドですべてのデコード操作を実行する場合、このモデルは適切に機能します。 ただし、デコーダーが複数のスレッドを使用してフレームを並列にデコードするとします。 最適なパフォーマンスを得るには、デコード スレッドがアイドル状態になったときに、デコーダーが新しい入力を受け取る必要があります。 ただし、スレッドがデコード操作を完了する速度は、 ProcessInput と ProcessOutput に対するクライアントの呼び出しと正確には一致せず、スレッドは作業を待機します。
Windows 7 では、MFT に対してイベント ドリブン の非同期 処理が導入されています。 このモデルでは、MFT で入力が必要な場合や出力がある場合は常に、クライアントにイベントを送信します。
一般的な要件
このトピックでは、非同期 MFT と同期 MFT の違いについて説明します。 このトピックで説明する場合を除き、2 つの処理モデルは同じです。 (特に、フォーマット ネゴシエーションは同じです)。
非同期 MFT では、次のインターフェイスを実装する必要があります。
イベント
非同期 MFT は、次のイベントを使用して、データ処理の状態を通知します。
Event | 説明 |
---|---|
METransformNeedInput | MFT がより多くの入力を受け入れられるときに送信されます。 |
METransformHaveOutput | MFT に出力があるときに送信されます。 |
METransformDrainComplete | ドレイン操作が完了したときに送信されます。 「ドレイン」を参照してください。 |
METransformMarker | マーカーが処理されるときに送信されます。 「マーカー」を参照してください。 |
これらのイベントは帯域外で送信されます。 MFT のコンテキストでの帯域内イベントと帯域外イベントの違いを理解することが重要です。
元の MFT 設計では、 インバンド イベントが サポートされています。 インバンド イベントには、形式の変更に関する情報など、データ ストリームに関する情報が含まれます。 クライアントは、 IMFTransform::P rocessEvent を呼び出して、MFT にインバンド イベントを送信します。 MFT は、 ProcessOutput メソッドでインバンド イベントをクライアントに送り返すことができます。 (具体的には、イベントは MFT_OUTPUT_DATA_BUFFER 構造体の pEvents メンバーで伝達されます)。
MFT は、 次のように IMFMediaEventGenerator インターフェイスを介して帯域外イベントを送信します。
- MFT は、「Media Event Generators」で説明されているように、IMFMediaEventGenerator インターフェイスを実装します。
- クライアントは、IMFMediaEventGenerator インターフェイスの MFT で IUnknown::QueryInterface を呼び出します。 非同期 MFT では、このインターフェイスを公開する必要があります。 同期 MFT では、このインターフェイスを公開しないでください。
- クライアントは 、IMFMediaEventGenerator::BeginGetEvent と IMFMediaEventGenerator::EndGetEvent を呼び出して、MFT から帯域外イベントを受信します。
ProcessInput
IMFTransform::P rocessInput メソッドは次のように変更されます。
- ストリーミングが開始されると、クライアントは MFT_MESSAGE_NOTIFY_START_OF_STREAM メッセージを送信します。
- ストリーミング中、MFT は METransformNeedInput イベントを送信してデータを要求します。 イベント データはストリーム識別子です。
- METransformNeedInput イベントごとに、クライアントは指定されたストリームに対して ProcessInput を呼び出します。
- ストリーミングの最後に、クライアントは MFT_MESSAGE_NOTIFY_END_OF_STREAM メッセージを使用して ProcessMessage を呼び出すことができます。
実装に関する注意事項:
- MFT は、MFT_MESSAGE_NOTIFY_START_OF_STREAM メッセージを受信するまで METransformNeedInput イベントを送信できません。
- ストリーミング中、MFT は METransformNeedInput イベントをいつでも送信できます。
- MFT は、保留中の METransformNeedInput イベントの数を保持する必要があります。 METransformNeedInput イベントに対応しない ProcessInput の呼び出しは 、MF_E_NOTACCEPTINGを返す必要があります。
- MFT は 、MFT_MESSAGE_NOTIFY_END_OF_STREAM メッセージを受信すると、保留中の METransformNeedInput イベントの数を 0 にリセットします。
- MFT は、MFT_MESSAGE_NOTIFY_END_OF_STREAM メッセージを受信した後に METransformNeedInput イベントを送信することはできません。
- ProcessInput がMFT_MESSAGE_NOTIFY_START_OF_STREAMの前またはMFT_MESSAGE_NOTIFY_END_OF_STREAM後に呼び出された場合、メソッドは MF_E_NOTACCEPTINGを返す必要があります。
ProcessOutput
IMFTransform::P rocessOutput メソッドは次のように変更されます。
- MFT は、出力があるたびに METransformHaveOutput イベントを送信します。
- METransformHaveOutput イベントごとに、クライアントは ProcessOutput を呼び出します。
実装に関する注意事項:
- クライアントが他の時点で ProcessOutput を 呼び出すと、メソッドは E_UNEXPECTEDを返します。
- 非同期 MFT は、ProcessOutput メソッドからMF_E_TRANSFORM_NEED_MORE_INPUTを返すべきではありません。 MFT により多くの入力が必要な場合は、 METransformNeedInput イベントが送信されます 。
ドレイン中
MFT をドレインすると、既に送信されている入力データからできる限り多くの出力が MFT によって生成されます。 非同期 MFT のドレインは、次のように機能します。
- クライアントは 、MFT_MESSAGE_COMMAND_DRAIN メッセージを送信します。
- MFT は、処理するデータがなくなったまで METransformHaveOutput イベントを送信し続けます。 この間 、METransformNeedInput イベントは送信されません。
- MFT は、最後の METransformHaveOutput イベントを送信した後、 METransformDrainComplete イベントを送信します。
ドレインが完了すると、MFT は、クライアントからMFT_MESSAGE_NOTIFY_START_OF_STREAM メッセージを受信するまで、別の METransformNeedInput イベントを送信しません。
フラッシュ
クライアントは、 MFT_MESSAGE_COMMAND_FLUSH メッセージを送信することで MFT をフラッシュできます。 MFT は、保持しているすべての入出力サンプルをドロップします。
MFT は、クライアントからMFT_MESSAGE_NOTIFY_START_OF_STREAMメッセージを受信するまで、別の METransformNeedInput イベントを送信しません。
マーカー
クライアントは、 MFT_MESSAGE_COMMAND_MARKER メッセージを送信することで、ストリーム内のポイントをマークできます。 MFT は次のように応答します。
- MFT は、既存の入力データからできるだけ多くの出力サンプルを生成し、出力サンプルごとに METransformHaveOutput イベントを送信します。
- すべての出力が生成されると、MFT は METransformMarker イベントを送信します。 このイベントは、 すべての METransformHaveOutput イベントの後に送信する必要があります。
たとえば、デコーダーに 4 つの出力サンプルを生成するのに十分な入力データがあるとします。 クライアントが MFT_MESSAGE_COMMAND_MARKER メッセージを送信すると、MFT は 4 つの METransformHaveOutput イベント (出力サンプルごとに 1 つ) をキューに入れ、その後に METransformMarker イベントをキューに入れます。
マーカー メッセージはドレイン メッセージに似ています。 ただし、ドレインはストリームの中断と見なされますが、マーカーは見なされません。 ドレインとマーカーには、次の違いがあります。
排水:
- ドレイン中、MFT は METransformNeedInput イベントを 送信しません。
- MFT は、出力サンプルの作成に使用できない入力データを破棄します。
- 一部の MFT では、データの末尾に "尾" が生成されます。 たとえば、リバーブやエコーなどのオーディオエフェクトは、入力データが停止した後に余分なデータを生成します。 尾部を生成する MFT は、ドレイン操作の終了時に行う必要があります。
- MFT のドレインが完了すると、次の出力サンプルに MFSampleExtension_Discontinuity 属性がマークされ、ストリームの不連続性が示されます。
マーカー:
- MFT は、マーカー イベントを送信する前 に METransformNeedInput イベントを送信し続けます。
- MFT は入力データを破棄しません。 部分的なデータがある場合は、マーカー ポイントの後に処理する必要があります。
- MFT はマーカー ポイントで尾を生成しません。
- MFT は、マーカー ポイントの後に不連続性フラグを設定しません。
変更の書式設定
非同期 MFT では、 ストリーム変更の処理に関するページで説明されているように、動的な形式の変更をサポートする必要があります。
属性
有効な属性ストアを返すには、非同期 MFT で IMFTransform::GetAttributes メソッドを実装する必要があります。 非同期 MFT には、次の属性が適用されます。
属性 | 説明 |
---|---|
MF_TRANSFORM_ASYNC | MFT では、この属性を TRUE (1) に設定する必要があります。 クライアントは、この属性に対してクエリを実行して、MFT が非同期であるかどうかを検出できます。 |
MF_TRANSFORM_ASYNC_UNLOCK | |
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE | MFT では、この属性を TRUE (1) に設定する必要があります。 クライアントでは、この属性が設定されていると想定できます。 |
非同期 MFT のロック解除
非同期 MFT は、元の MFT データ処理モデルと互換性がありません。 非同期 MFT が既存のアプリケーションを壊さないようにするために、次のメカニズムが定義されています。
- クライアントは、MFT で IMFTransform::GetAttributes を呼び出します。
クライアントは、この MF_TRANSFORM_ASYNC 属性の を照会します。 非同期 MFT の場合、この属性の値は **TRUE** です。
MFT のロックを解除するには、クライアントで MF_TRANSFORM_ASYNC_UNLOCK 属性を **TRUE** に設定する必要があります。
クライアントが MFT のロックを解除するまで、すべての IMFTransform メソッドは、次の例外を除き、 MF_E_TRANSFORM_ASYNC_LOCKEDを返す必要があります。
- IMFTransform::GetAttributes (すべての非同期 MFT)
- IMFTransform::GetInputAvailableType (すべての非同期 MFT)
- IMFTransform::GetOutputCurrentType (エンコーダーのみ)
- IMFTransform::SetOutputType (エンコーダーのみ)
- IMFTransform::GetStreamCount (すべての非同期 MFT)
- IMFTransform::GetStreamIDs (すべての非同期 MFT)
次のコードは、非同期 MFT のロックを解除する方法を示しています。
HRESULT UnlockAsyncMFT(IMFTransform *pMFT)
{
IMFAttributes *pAttributes = NULL;
HRESULT hr = hr = pMFT->GetAttributes(&pAttributes);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
pAttributes->Release();
}
return hr;
}
MFT のシャットダウン
非同期 MFT は 、IMFShutdown インターフェイスを実装する必要があります。
- シャットダウン: MFT はイベント キューをシャットダウンする必要があります。 標準イベント キューを使用する場合は、 IMFMediaEventQueue::Shutdown を呼び出します。 必要に応じて、MFT は他のリソースを解放できます。 クライアントは、Shutdown を呼び出した後に MFT を使用しないでください。
- GetShutdownStatus: Shutdown が呼び出された後、MFT は pStatus パラメーターでMFSHUTDOWN_COMPLETED値を返す必要があります。 MFSHUTDOWN_INITIATED値を返さないでください。
登録と列挙
非同期 MFT を登録するには、MFTRegister 関数を呼び出し、Flags パラメーターに MFT_ENUM_FLAG_ASYNCMFT フラグを設定します。 (以前は、このフラグは予約されていました。
非同期 MFT を列挙するには、MFTEnumEx 関数を呼び出し、Flags パラメーターに MFT_ENUM_FLAG_ASYNCMFT フラグを設定します。 下位互換性のために、 MFTEnum 関数は非同期 MFT を列挙しません。 そうしないと、ユーザーのコンピューターに非同期 MFT をインストールすると、既存のアプリケーションが壊れる可能性があります。
関連トピック