Transform (IMFTransform)

Media Foundation Transform (MFT) はMedia Data処理の一般的なモデルを提供し、デコーダー、エンコーダーやDSP (Digital Signal Processor) で用いられます。

MFTの作成

MFTを作成するには、いくつかの方法があります。

  • MFTEnum()関数を呼ぶ
  • MFTEnumEx()関数を呼ぶ
  • MFTのCLSIDがわかっているならば、単純にCoCreateInstance()を呼ぶ

MFTEnumEx()

MFTEnumEx()で、指定基準に適合するMFTのリストを得られます。

HRESULT MFTEnumEx(
  [in]  GUID                         guidCategory,      // MFTのカテゴリを表すGUID。その値はMFT_CATEGORYで定義されている
  [in]  UINT32                       Flags,             // 処理方法を示す_MFT_ENUM_FLAGの値
  [in]  const MFT_REGISTER_TYPE_INFO *pInputType,       // 入力するMedia Typeに適合する、MFT_REGISTER_TYPE_INFOへのポインタ
  [in]  const MFT_REGISTER_TYPE_INFO *pOutputType,      // 出力するMedia Typeに適合する、MFT_REGISTER_TYPE_INFOへのポインタ
  [out] IMFActivate                  ***pppMFTActivate, // 検索基準に適合したMFTオブジェクトの配列へのポインタ
  [out] UINT32                       *pnumMFTActivate   // MFTオブジェクトの配列の要素の数
);
MFTEnumEx function (mfapi.h) - Win32 apps | Microsoft Learn

Flagsにゼロを指定すると、MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTERと同等となります。MFT_ENUM_FLAG_ALLを指定すると、MFT_ENUM_FLAG_SORTANDFILTER以外のすべてのフラグが指定されます。Flagsに適合するMFTがなくてもS_OKが返されるため、pnumMFTActivateの数を確認するようにします。

_MFT_ENUM_FLAG列挙型
列挙子 内容
MFT_ENUM_FLAG_SYNCMFT 0x00000001 Enumerates V1 MFTs. This is default.
MFT_ENUM_FLAG_ASYNCMFT 0x00000002 Enumerates only software async MFTs also known as V2 MFTs
MFT_ENUM_FLAG_HARDWARE 0x00000004 Enumerates V2 hardware async MFTs
MFT_ENUM_FLAG_FIELDOFUSE 0x00000008 Enumerates MFTs that require unlocking
MFT_ENUM_FLAG_LOCALMFT 0x00000010 Enumerates Locally (in-process) registered MFTs
MFT_ENUM_FLAG_TRANSCODE_ONLY 0x00000020 Enumerates decoder MFTs used by transcode only
MFT_ENUM_FLAG_SORTANDFILTER 0x00000040 Apply system local, do not use and preferred sorting and filtering
MFT_ENUM_FLAG_SORTANDFILTER_APPROVED_ONLY 0x000000C0 Similar to MFT_ENUM_FLAG_SORTANDFILTER, but apply a local policy of: MF_PLUGIN_CONTROL_POLICY_USE_APPROVED_PLUGINS
MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY 0x00000140 Similar to MFT_ENUM_FLAG_SORTANDFILTER, but apply a local policy of: MF_PLUGIN_CONTROL_POLICY_USE_WEB_PLUGINS
MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY_EDGEMODE 0x00000240 Similar to MFT_ENUM_FLAG_SORTANDFILTER, but apply a local policy of: MF_PLUGIN_CONTROL_POLICY_USE_WEB_PLUGINS_EDGEMODE
_MFT_ENUM_FLAG (mfapi.h) - Win32 apps | Microsoft Learn

pInputTypepOutputTypeにNULLを指定すると、すべてのMedia Typeに適合します。

MFT_REGISTER_TYPE_INFO pOutputType[] = { { MFMediaType_Video, MFVideoFormat_RGB32 } };
IMFActivate** ppMFTActivate;
UINT32 numMFTActivate;

HRESULT hr = MFTEnumEx(
    MFT_CATEGORY_VIDEO_PROCESSOR,
    MFT_ENUM_FLAG_ALL,
    NULL,
    pOutputType,
    &ppMFTActivate,
    &numMFTActivate);

IMFTransform* pTransform;
if (0< numMFTActivate)
{
    // IMFTransformのオブジェクトを生成する
    hr = ppMFTActivate[0]->ActivateObject(__uuidof(IMFTransform), (void **)&pTransform);
}

CoTaskMemFree(ppMFTActivate);

CoCreateInstance()

CoCreateInstance()では、次のようにMFTのインスタンスを得られます。

IMFTransform* pTransform;

HRESULT hr = CoCreateInstance(
    CLSID_VideoProcessorMFT,
    NULL,
    CLSCTX_INPROC_SERVER,
    __uuidof(IMFTransform),
    (void**)&pTransform);

ストリーム識別子の取得

対象とするストリームをMFTに指示するための、識別子を取得します。

  1. (任意) GetStreamLimits()
  2. GetStreamCount()
  3. GetStreamIDs()
  4. (任意) AddInputStreams() または DeleteInputStream()
IMFTransform* pTransform = ...

// 入出力のストリームの数を取得する
DWORD dwInputIDArraySize;
DWORD dwOutputIDArraySize;
hr = pTransform->GetStreamCount(&dwInputIDArraySize, &dwOutputIDArraySize);

// ストリーム識別子の配列を取得する
DWORD* pdwInputIDs = new DWORD[dwInputIDArraySize];
DWORD* pdwOutputIDs = new DWORD[dwOutputIDArraySize];
hr = pTransform->GetStreamIDs(dwInputIDArraySize, pdwInputIDs, dwOutputIDArraySize, pdwOutputIDs);

DWORD dwInputStreamID = 0;
DWORD dwOutputStreamID = 0;
if (hr != E_NOTIMPL)
{
    dwInputStreamID = pdwInputIDs[0];
    dwOutputStreamID = pdwOutputIDs[0];
}
delete[] pdwInputIDs;
delete[] pdwOutputIDs;

GetStreamCount()

MFTの入力と出力のストリームの数を得られます。

HRESULT GetStreamCount(
  [out] DWORD *pcInputStreams,
  [out] DWORD *pcOutputStreams
);
IMFTransform::GetStreamCount (mftransform.h) - Win32 apps | Microsoft Learn

返されるストリームには、Media TypeがないかNULLのMedia Typeのストリームの数も含まれます。

GetStreamIDs()

MFTの入力と出力のストリーム識別子を得られます。

HRESULT GetStreamIDs(
  [in]  DWORD dwInputIDArraySize,
  [out] DWORD *pdwInputIDs,
  [in]  DWORD dwOutputIDArraySize,
  [out] DWORD *pdwOutputIDs
);
IMFTransform::GetStreamIDs (mftransform.h) - Win32 apps | Microsoft Learn

E_NOTIMPLが返されるときは、MFTにゼロから始まる連続する識別子を持つ固定数のストリームがあることを意味します。

Media Typeの設定

MFTがデータを処理できるように、入力と出力のストリームごとにMedia Typeを設定しなければなりません。

  1. (任意) GetInputAvailableType()
  2. SetInputType()
  3. (任意) GetOutputAvailableType()
  4. SetOutputType()
DWORD dwFlags = 0;
hr = pTransform->SetInputType(dwInputStreamID, pInputMediaType, dwFlags);
hr = pTransform->SetOutputType(dwOutputStreamID, pOutputMediaType, dwFlags);

MFTによっては入力と出力を設定する順番が要求されることがあり、SetInputType()がMF_E_TRANSFORM_TYPE_NOT_SETを返すならば、先に出力を設定します。

SetInputType()

MFTの入力ストリームのMedia Typeを、設定または 検査できます。

HRESULT SetInputType(
  [in] DWORD        dwInputStreamID,
  [in] IMFMediaType *pType,
  [in] DWORD        dwFlags // MFT_SET_TYPE_TEST_ONLYならば、pTypeを検査して設定しない
);
IMFTransform::SetInputType (mftransform.h) - Win32 apps | Microsoft Learn

バッファ要件の取得

Media Typeを設定したら、ストリームごとにバッファ要件を取得します。

MFT_OUTPUT_STREAM_INFO mftStreamInfo;
ZeroMemory(&mftStreamInfo, sizeof(MFT_OUTPUT_STREAM_INFO));

// デコーダで処理される出力バッファの大きさを取得する
hr = pTransform->GetOutputStreamInfo(dwOutputStreamID, &mftStreamInfo);

GetOutputStreamInfo()

HRESULT GetOutputStreamInfo(
  [in]  DWORD                  dwOutputStreamID,
  [out] MFT_OUTPUT_STREAM_INFO *pStreamInfo
);
IMFTransform::GetOutputStreamInfo (mftransform.h) - Win32 apps | Microsoft Learn

ストリーミング モデル

  • Lazy-read streams … MFT_OUTPUT_STREAM_LAZY_READ
  • Discardable streams … MFT_OUTPUT_STREAM_DISCARDABLE
  • Optional streams … MFT_OUTPUT_STREAM_OPTIONAL
Extensions to the Basic Model - Basic MFT Processing Model - Win32 apps | Microsoft Learn _MFT_OUTPUT_STREAM_INFO_FLAGS (mftransform.h) - Win32 apps | Microsoft Learn

データ処理

  1. ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, ) … ストリーミングの間に必要なリソースの割り当てを、MFTに要求する
  2. ProcessInput()
  3. (任意) GetOutputStatus()
  4. ProcessOutput()
  5. ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, )
  6. ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, )
  7. ProcessOutput()
IMFSample* pSample = ...

// デコーダへ入力を送る
DWORD dwReserved = 0;
hr = pTransform->ProcessInput(dwInputStreamID, pSample, dwReserved);


// 変換出力用のバッファを作成する
MFT_OUTPUT_STREAM_INFO mftStreamInfo;
ZeroMemory(&mftStreamInfo, sizeof(MFT_OUTPUT_STREAM_INFO));

// デコーダで処理される出力バッファの大きさを取得する
hr = pTransform->GetOutputStreamInfo(dwOutputStreamID, &mftStreamInfo);

// 出力サンプルを作成する
IMFSample* pSampleOut = NULL;
IMFMediaBuffer* pBufferOut = NULL;

// 出力サンプル用のバッファを作成する
hr = MFCreateMemoryBuffer(mftStreamInfo.cbSize, &pBufferOut);
hr = MFCreateSample(&pSampleOut);
hr = pSampleOut->AddBuffer(pBufferOut);

MFT_OUTPUT_DATA_BUFFER mftOutputData;
ZeroMemory(&mftOutputData, sizeof(mftOutputData));
mftOutputData.dwStreamID = dwOutputStreamID;
mftOutputData.pSample = pSampleOut;

// デコーダで出力サンプルを生成する
DWORD dwProcessOutput = 0;
DWORD dwStatus = 0;
hr = pTransform->ProcessOutput(dwProcessOutput, dwOutputIDArraySize, &mftOutputData, &dwStatus);

ProcessMessage()

MFTへメッセージを送れます。

HRESULT ProcessMessage(
  [in] MFT_MESSAGE_TYPE eMessage, // 送信するメッセージ
  [in] ULONG_PTR        ulParam   // メッセージ パラメータ。その意味はメッセージに依存する
);
IMFTransform::ProcessMessage (mftransform.h) - Win32 apps | Microsoft Learn

eMessageには、MFT_MESSAGE_TYPEの値を指定します。

MFT_MESSAGE_TYPE列挙型
列挙子 内容
MFT_MESSAGE_NOTIFY_BEGIN_STREAMING ストリーミングが開始することを、MFTに通知する
MFT_MESSAGE_NOTIFY_END_OF_STREAM 入力ストリームが終了したことを、MFTに通知する
MFT_MESSAGE_COMMAND_DRAIN 蓄えたデータの排出を、MFTに要求する
   
MFT_MESSAGE_TYPE (mftransform.h) - Win32 apps | Microsoft Learn

MFT_MESSAGE_COMMAND_DRAIN

MFTは利用できる入力から完全な出力を生成できないとき、入力データを失います。クライアントは一般的に、ソースストリームの最後に達するか、ソースストリームのフォーマットが変更される直前に、MFTに排出を要求します。Draining an MFT - Basic MFT Processing Model - Win32 apps | Microsoft Learn

ProcessMessage()でMFT_MESSAGE_COMMAND_DRAINを送信する以外にも、MF_E_TRANSFORM_NEED_MORE_INPUTが返されるまでProcessOutput()を呼ぶことでも、MFTからデータを排出できます。

ProcessInput()

MFTの入力ストリームへ、データを配送できます。

HRESULT ProcessInput(
  [in] DWORD     dwInputStreamID, // 入力ストリームの識別子
  [in] IMFSample *pSample,        // 入力サンプルへのポインタ
  [in] DWORD     dwFlags          // 予約。必ず0
);
IMFTransform::ProcessInput (mftransform.h) - Win32 apps | Microsoft Learn

ProcessOutput()

現在の入力データから、出力を生成できます。

HRESULT ProcessOutput(
  [in]      DWORD                  dwFlags,
  [in]      DWORD                  cOutputBufferCount, // pOutputSamples配列の要素の数
  [in, out] MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
  [out]     DWORD                  *pdwStatus
);
IMFTransform::ProcessOutput (mftransform.h) - Win32 apps | Microsoft Learn

戻り値によっては、追加の処理が必要となります。

  • MF_E_TRANSFORM_NEED_MORE_INPUT … さらに入力データが必要なため、ProcessInput()を呼ぶ
  • MF_E_TRANSFORM_STREAM_CHANGE … 出力ストリームまたは出力フォーマットが変更されたため、新しいストリーム識別子を問い合わせるか、新しいMedia typeを設定する
Microsoft Learnから検索