Media Foundation 変換デコード
Xbox Game Development Kit (GDK) は、Media foundation Source Reader Interface を介して、H264および HEVC ファイル/データストリームのハードウェアおよびソフトウェアによるデコードをサポートしています。 デスクトップ版のSource Readerと比較すると、Xbox GDK 版はデスクトップ版の機能の一部しかサポートしていません。
サポートされているコーデック
ハードウェア デコード
コーデック | 最大解像度/フレーム レート (fps) | プロファイル | 本体タイプ |
---|---|---|---|
H264 | 最大 1080p/30 | ベースライン/メイン/高 | すべての Xbox 本体 |
HEVC | 最大 1080p/30 | メイン/メイン 10 | Xbox One S およびXbox One X |
HEVC | 最大 4K/30 | メイン/メイン 10 | Xbox Series S および Xbox Series X |
ソフトウェア デコード
H264 ソフトウェア デコードは、最大 4096x2160@30 fps (レベル 5.2) までサポートされています。 ただし、性能はゲーム機の種類によって異なり、Xbox Series S/X では > 1080 p の解像度を快適にデコードすることができますのでご注意ください。
HEVC ソフトウェア デコードも 1920 x 1080@30 fps までサポートされていますが、ゲーム機の種類によってパフォーマンスが異なります。 ただし、HEVC のハードウェアデコードは、H264 のソフトウェアデコードに比べて CPU 負荷が大きくなるため、ハードウェア デコードを使用することをお勧めします。
メディア データのデコード
ソース リーダーを使用してメディア データをデコードするには、次の手順に従います。
- ソース リーダーを作成する
- ハードウェア(あるいは、ソフトウェア) アクセラレータを使用する
- 出力形式を列挙します
- 出力形式を設定します
- メディア データを処理する
- グラフィックス (または他の D3D12) のコマンドキューとの同期
- 書式とカラー スペースの変換
リファレンスコードについては、GDK のサンプルに含まれる Mp4Reader のサンプルを参照してください(ここでのコードスニペットは、フォローしやすいように Mp4reader のものを使用しています)。
手順 1: ソース リーダーを作成する
ソース リーダーのインスタンスを作成するには、MFCreateSourceReaderFromByteStream 関数を呼び出します。この関数ではバイト ストリームへのポインターを指定します。 また、この関数は、ソース リゾルバーを使用したメディア ソースの作成も行います。
MFCreateSourceReaderFromByteStream
関数の pByteStream
パラメーターは、ソース リーダーにさまざまなオプションを設定するために使用される IMFAttributes インターフェイスへのポインターを受け取ります (IMFAttributes::Set
メソッドのリファレンス トピックで説明されています)。 このパラメーターを nullptr
に設定すると既定の動作が使用されますが、これは推奨されません。 ソース リーダーでは、少なくとも MF_SOURCE_READER_D3D_MANAGER
属性を常に指定して、ハードウェアで高速化されたデコードを有効にする必要があります。
MFCreateSourceReaderFromByteStream
関数は、IMFSourceReader インターフェイスへのポインターを出力します。
注意 デスクトップのソースリーダーは、同期モードと非同期モードの両方をサポートしています。 Xbox Game Development Kit (GDK) は synchronous のみサポートしており、デフォルトで設定されています。
HLS/Smoothstreaming の基本的なサポートのために、ソースリーダーを作成するための入力と同様に、m3u8 または Smoothstreaming のマニフェストURL を指定することができます。 Mp4 ファイルの入力にはいくつかの制限があります。
- 音声形式は AAC-LC オーディオと AC3 のみに対応しています。
- HEVC データの場合、フォーマット タグは 'hvc1'でなければなりません( 'hev1'はサポートされていません)。
C++
// Initialize the Media Foundation platform.
DX::ThrowIfFailed(MFStartup(MF_VERSION));
// Call the MFCreateDXGIDeviceManager function to create the Direct3D device manager
DX::ThrowIfFailed(MFCreateDXGIDeviceManager(&uResetToken, &pDXVAManager));
// Call the MFResetDXGIDeviceManagerX function with a pointer to the Direct3D device
DX::ThrowIfFailed(MFResetDXGIDeviceManagerX(pDXVAManager.Get(), device, uResetToken));
// Create an attribute store
DX::ThrowIfFailed(pDXVAManager.AsIID(__uuidof(IUnknown), &punkDeviceMgr));
DX::ThrowIfFailed(MFCreateAttributes(&pMFAttributes, 3));
DX::ThrowIfFailed(pMFAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, punkDeviceMgr.Get()));
DX::ThrowIfFailed(pMFAttributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE));
DX::ThrowIfFailed(pMFAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE));
// Don't set the MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING MFAttribute to TRUE. It is too slow.
// Create the source reader.
DX::ThrowIfFailed(MFCreateSourceReaderFromURL(INPUT_FILE_PATH, pMFAttributes.Get(), &m_pReader));
手順 2: ハードウェア(あるいは、ソフトウェア) アクセラレータを使用する
ソース リーダーは、ハードウェアで高速化されたビデオ デコード用の Microsoft DirectX ビデオ アクセラレータ (DXVA) 2.0 と互換性があります。 ソース リーダーで DXVA を使用するには、次の手順を実行します。
- MFCreateDXGIDeviceManager 関数を呼び出して Direct3D デバイス マネージャーを作成します。 この関数は、IMFDXGIDeviceManager インターフェイスへのポインターを受け取ります。
- Direct3D デバイスへのポインターを使用して、
MFResetDXGIDeviceManagerX
のメソッドを呼び出します。 - MFCreateAttributes 関数を呼び出して、属性ストアを作成します。
-
SetUnknown を呼び出して、
MF_SOURCE_READER_D3D_MANAGER
属性を IMFDXGIDeviceManager インターフェイスに設定します。 - また、
MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS
を有効にして、MF_SOURCE_READER_DISABLE_DXVA
を FALSE に設定します。 - ソース リーダーを作成します。 作成関数の
pAttributes
パラメーターに属性ストアを渡します。
ソフトウェア デコード
MF_SOURCE_READER_DISABLE_DXVA
を TRUE に設定するだけで、ソフトウェア デコードを有効にできます。 ソフトウェア デコードでは、ビデオ デコーダのスレッドを細かく制御するために、以下のようなパラメータを設定することができます。例えば、スレッド アフィニティ マスク、ワーカー スレッドの数、スレッドの優先度などです。
C++
// Set some threading parameters for software decode
Microsoft::WRL::ComPtr<IMFTransform> transform;
Microsoft::WRL::ComPtr<IMFAttributes> attributes;
DX::ThrowIfFailed(m_pReader->GetServiceForStream(MF_SOURCE_READER_FIRST_VIDEO_STREAM, GUID_NULL, IID_PPV_ARGS(transform.GetAddressOf())));
transform->GetAttributes(attributes.GetAddressOf());
attributes->SetUINT32(CODECAPI_AVDecVideoThreadAffinityMask, 0x0F); // Use the first 4 cores. Input value is the same as Win32 SetThreadAffinityMask
attributes->SetUINT32(CODECAPI_AVDecNumWorkerThreads, 0x4); // 4 threads
attributes->SetUINT32(CODECAPI_AVPriorityControl, THREAD_PRIORITY_HIGHEST); // Set thread priority. Same as Win32 SetThreadPriority for priorty levels
手順 3: 出力形式を列挙する
すべてのメディア ソースには少なくとも 1 つのストリームがあります。 たとえば、ビデオ ファイルには、ビデオ ストリームとオーディオ ストリームが含まれることがあります。 各ストリームの形式は、IMFMediaType インターフェイスで表されるメディアの種類を使用して記述されます。 メディアの種類の詳細については、「Media Types」をご覧ください。 メディアの種類を調べて、ソース リーダーから取得するデータの形式を理解する必要があります。
最初に、すべてのストリームには既定の形式があります。既定の形式は、IMFSourceReader::GetCurrentMediaType メソッドを呼び出すことによって確認できます。
ストリームごとに、メディア ソースは、そのストリームで使用可能なメディアの種類のリストを提供します。 種類の数はソースによって異なります。 ソースがメディア ファイルの場合、通常は、ストリームごとに 1 つの種類しかありません。 一方、Web カメラは、いくつかの異なる形式でビデオをストリーミングできる場合があります。 その場合、アプリは、使用する形式を、メディアの種類のリストから選択できます。
ストリームのメディアの種類を 1 つ取得するには、IMFSourceReader::GetNativeMediaType メソッドを呼び出します。 このメソッドでは 2 つのインデックス パラメーター (ストリームのインデックスと、ストリームに関するメディアの種類のリストのインデックス) を指定します。 ストリームのすべての種類を列挙するには、ストリームのインデックスを一定に保持したままリストのインデックスをインクリメントします。 リストのインデックスが範囲を超えると、次のコードに示すように、GetNativeMediaType
は MF_E_NO_MORE_TYPES
を返します。
C++
HRESULT EnumerateTypesForStream(IMFSourceReader *pReader, DWORD dwStreamIndex)
{
HRESULT hr = S_OK;
DWORD dwMediaTypeIndex = 0;
while (SUCCEEDED(hr))
{
IMFMediaType *pType = NULL;
hr = pReader->GetNativeMediaType(dwStreamIndex, dwMediaTypeIndex, &pType);
if (hr == MF_E_NO_MORE_TYPES)
{
hr = S_OK;
break;
}
else if (SUCCEEDED(hr))
{
// Examine the media type here.
pType->Release();
}
++dwMediaTypeIndex;
}
return hr;
}
すべてのストリームのメディアの種類を列挙するには、ストリームのインデックスをインクリメントします。 ストリームのインデックスが範囲を超えると、IMFSourceReader::GetNativeMediaType は MF_E_INVALIDSTREAMNUMBER
を返します。
手順 4: 出力形式を設定する
ストリームをデコードするには、必要な非圧縮形式を記述する新しいメディアの種類を作成します。 デコーダーの場合は、メディアの種類を次のように作成します。
- MFCreateMediaType を呼び出して新しいメディアの種類を作成します。
- MF_MT_MAJOR_TYPE 属性を設定してオーディオまたはビデオを指定します。
- MF_MT_SUBTYPE 属性を設定してデコード形式のサブタイプを指定します。 使用できるサブタイプについては、「Audio Subtype GUIDs」および「Video Subtype GUIDs」を参照してください。 Xbox では、8 ビットビデオのデコードには NV12、10 ビットビデオのデコードには P010 のみ対応しています。
- SetCurrentMediaType を呼び出します。
ソース リーダーは自動的にデコーダーを読み込みます。 デコードされた形式の詳細を取得するには、SetCurrentMediaType の呼び出し後に IMFMediaTypeHandler::GetCurrentMediaType を呼び出します。 以下のコードは、ビデオストリームを NV12 に、オーディオ ストリームを浮動小数点オーディオを構成します。
C++
HRESULT ConfigureDecoder(IMFSourceReader *pReader, DWORD dwStreamIndex)
{
ComPtr<IMFMediaType> pNativeType;
ComPtr<IMFMediaType> pType;
GUID majorType, subtype;
// Find the native format of the stream.
DX::ThrowIfFailed(pReader->GetNativeMediaType(dwStreamIndex, 0, &pNativeType));
// Find the major type.
DX::ThrowIfFailed(pNativeType->GetGUID(MF_MT_MAJOR_TYPE, &majorType));
// Define the output type.
DX::ThrowIfFailed(MFCreateMediaType(&pType));
DX::ThrowIfFailed(pType->SetGUID(MF_MT_MAJOR_TYPE, majorType));
// Select a subtype.
if (majorType == MFMediaType_Video)
{
// NV12 for 8 bit (or P010 for 10 bit)are the only supported output types of Xbox One HW decoders
subtype = MFVideoFormat_NV12;
}
else if (majorType == MFMediaType_Audio)
{
subtype = MFAudioFormat_Float;
}
else
{
// Unrecognized type. Skip.
return;
}
DX::ThrowIfFailed(pType->SetGUID(MF_MT_SUBTYPE, subtype));
// Set the uncompressed format.
DX::ThrowIfFailed(pReader->SetCurrentMediaType(dwStreamIndex, nullptr, pType.Get()));
}
手順 5: メディア データを処理する
ソースからメディア データを取得するには、次のコードに示されているように、IMFSourceReader::ReadSample メソッドを呼び出します。
C++
DWORD streamIndex, flags;
LONGLONG llTimeStamp;
hr = pReader->ReadSample(
MF_SOURCE_READER_ANY_STREAM, // Stream index.
0, // Flags.
&streamIndex, // Receives the actual stream index.
&flags, // Receives status flags.
&llTimeStamp, // Receives the time stamp.
&pSample // Receives the sample or nullptr.
);
最初のパラメーターは、データを取得するストリームのインデックスです。
MF_SOURCE_READER_ANY_STREAM
を指定して、任意のストリームから次に利用可能なデータを取得することもできます。 2 番目のパラメーターには、オプションのフラグが含まれます。 これらのフラグの一覧については、「MF_SOURCE_READER_FLAG enumeration」をご覧ください。 3 番目のパラメーターは、実際にデータを生成するストリームのインデックスを受け取ります。 最初のパラメーターを MF_SOURCE_READER_ANY_STREAM
に設定した場合は、この情報が必要です。 4 番目のパラメーターは、ストリームの形式の変更など、データの読み取り中に発生する可能性がある各種イベントを示すステータス フラグを受け取ります。 ステータス フラグの一覧については、「MF_SOURCE_READER_FLAG enumeration」をご覧ください。
メディア ソースが要求されたストリームのデータを生成できる場合、ReadSample の最後のパラメーターは、メディア サンプル オブジェクトの IMFSample インターフェイスへのポインターを受け取ります。 このメディア サンプルを使用して以下の操作を行います。
- メディア データへのポインターを取得する。
- プレゼンテーション時間およびサンプルの継続時間を取得する。
- インターレース、優先フィールド、およびサンプルのその他の側面を表す属性を取得します。
メディア データの内容は、ストリームの形式によって異なります。 非圧縮ビデオ ストリームの場合、各メディア サンプルには単一のビデオ フレームが含まれます。 非圧縮オーディオ ストリームの場合、各メディア サンプルには一連のオーディオ フレームが含まれます。
ReadSample メソッドは、S_OK
を返すことができますが、pSample
パラメーターでメディア サンプルを返すことはまだできません。 たとえば、ファイルの末尾に達すると、ReadSample
は dwFlags
に MF_SOURCE_READERF_ENDOFSTREAM
フラグを設定し、pSample
を nullptr
に設定します。 この場合、pSample
パラメーターが nullptr
に設定されていても、エラーは発生していないので、ReadSample
メソッドは S_OK
を返します。 そのため、逆参照する前に pSample
の値を必ず確認してください。
ビデオサンプルは、ReadSample を呼び出した後に、いくつかの追加処理が必要です。 これには、MF_MT_FRAME_SIZEまたはMF_MT_MINIMUM_DISPLAY_APERTURE属性からのビデオの幅と高さを決定し、同期の処理をすることが含まれます。
次のコード スニペットは、 ReadSample
を呼び出し、最初のビデオ ストリームについて、メソッドから返された情報を確認しています。 オーディオ ストリーム データの扱い方については、Mp4reader サンプルをご参照ください。 次のセクションでは、ハードウェアによるビデオ デコードの動作に必要な同期について説明します。
C++
// Retreive sample from source reader
ComPtr<IMFSample> pOutputSample;
hr = m_pReader->ReadSample(
uint32_t(MF_SOURCE_READER_FIRST_VIDEO_STREAM), // Stream index.
0, // Flags.
&streamIndex, // Receives the actual stream index.
&dwStreamFlags, // Receives status flags.
&llTimestamp, // Receives the time stamp.
&pOutputSample // Receives the sample or nullptr. If this parameter receives a non-NULL pointer, the caller must release the
// interface.
);
if (SUCCEEDED(hr))
{
if (dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
m_videoDone = true;
}
if (dwStreamFlags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED)
{
// The format changed. Reconfigure the decoder.
ConfigureSourceReaderOutput(m_pReader.Get(), streamIndex);
}
if (pOutputSample)
{
if (m_videoWidth == 0 || m_videoHeight == 0
|| (dwStreamFlags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED) || (dwStreamFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED))
{
// Update video width and height
ComPtr<IMFMediaType> pMediaType;
if (SUCCEEDED(m_pReader->GetCurrentMediaType(uint32_t(MF_SOURCE_READER_FIRST_VIDEO_STREAM), &pMediaType)))
{
MFVideoArea videoArea = {};
if (SUCCEEDED(pMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (uint8_t*)&videoArea, sizeof(MFVideoArea), nullptr)))
{
m_videoWidth = UINT(videoArea.Area.cx);
m_videoHeight = UINT(videoArea.Area.cy);
}
else
{
DX::ThrowIfFailed(MFGetAttributeSize(pMediaType.Get(), MF_MT_FRAME_SIZE, &m_videoWidth, &m_videoHeight));
}
}
}
if (m_pOutputVideoSample)
{
DX::ThrowIfFailed(MFD3D12GpuSignalSampleFree(m_pVideoRender->GetVideoProcessCommandQueue(), m_pOutputVideoSample.Get()));
m_pOutputVideoSample.Reset();
}
// The output buffer may still used by decoding ( although decode returns the buffer from CPU), put a wait single on the GPU to wait to the decoding to complete
DX::ThrowIfFailed(MFD3D12GpuWaitForSampleReady(m_pVideoRender->GetVideoProcessCommandQueue(), pOutputSample.Get()));
m_pOutputVideoSample = pOutputSample;
++m_numberOfFramesDecoded;
}
}
シークは 、IMFSourceReader::SetCurrentPosition API でサポートされます。
C++
PROPVARIANT position;
position.vt = VT_I8;
position.hVal.QuadPart = hnsPosition;
m_pReader->SetCurrentPosition(GUID_NULL, position);
手順 6:グラフィックス (または他の D3D12) のコマンド キューとの同期
Xbox GDK では、ハードウェアデコーダーからのビデオサンプルが、グラフィックスやその他の D3D12 キューと正しく同期するかどうかは、呼び出し側の責任となります。 これをサポートする 2 つの新しい API があります。
-
EnqueueResourceReadyWait
は、渡されたコマンド キューに待機時間を追加して、サンプルを処理する前にデコードが完了するのを待つようにします。 これは、ReadSample
の直後、および他のキューがビデオ サンプルの処理を開始する前に呼び出される必要があります。 -
EnqueueResourceRelease
は、デコーダが、渡されたコマンド キューで保留されている操作を確実に待つようにします (コマンド キューに、内部フェンスの Signal を要求します)。 これは、サンプルをプールに戻して再利用するために、他のコマンド キューでの処理がすべて終了した後に呼び出される必要があります。
C++
// For D3D12, application must call MFD3D12GpuSignalForSampleFree after it has finished processing the video sample
HRESULT MFD3D12GpuSignalSampleFree(
_In_ ID3D12CommandQueue* pCmdQueue,
_In_ IMFSample* pVideoSample)
{
ComPtr<IMFMediaBuffer> pBuffer;
HRESULT hr = pVideoSample->GetBufferByIndex(0, &pBuffer);
if (SUCCEEDED(hr))
{
ComPtr<IMFDXGIBuffer> pDXGIBuffer;
hr = pBuffer->QueryInterface<IMFDXGIBuffer>(&pDXGIBuffer);
if (SUCCEEDED(hr))
{
ComPtr<IMFD3D12SynchronizationObjectCommands> pMFSyncObj;
hr = pDXGIBuffer->GetUnknown(MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS(&pMFSyncObj));
if (SUCCEEDED(hr))
{
//GPU signal the sample can be freed for decoding
hr = pMFSyncObj->EnqueueResourceRelease(pCmdQueue);
}
}
}
return hr;
}
// For D3D12, application must call MFD3D12GpuWaitForSampleReady to make sure the GPU waits for decode to complete before process the sample using GPU code
HRESULT MFD3D12GpuWaitForSampleReady(
_In_ ID3D12CommandQueue* pCmdQueue,
_In_ IMFSample* pVideoSample)
{
ComPtr<IMFMediaBuffer> pBuffer;
HRESULT hr = pVideoSample->GetBufferByIndex(0, &pBuffer);
if (SUCCEEDED(hr))
{
ComPtr<IMFDXGIBuffer> pDXGIBuffer;
hr = pBuffer->QueryInterface<IMFDXGIBuffer>(&pDXGIBuffer);
if (SUCCEEDED(hr))
{
ComPtr<IMFD3D12SynchronizationObjectCommands> pMFSyncObj;
hr = pDXGIBuffer->GetUnknown(MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS(&pMFSyncObj));
if (SUCCEEDED(hr))
{
// GPU wait until the decoding completed
hr = pMFSyncObj->EnqueueResourceReadyWait(pCmdQueue);
}
}
}
return hr;
}
ソフトウェア デコードでは、これらの同期呼び出しは必要ありません。
ReadSample
から返されるサンプルには、常に完全にデコードされたフレームが含まれます。
手順 7:書式とカラー スペースの変換
D3D12 Video Processor API を用いて、デコードされた出力のカラー スペース変換や書式変換が可能になりました。 Xbox GDK では、YUV (DXGI_FORMAT_NV12
/DXGI_FORMAT_P010
) から RGB (他の 8 ビット RGB/型なしバリアントを含むDXGI_FORMAT_R10G10B10A2_UNORM
/DXGI_FORMAT_R8G8B8A8_UNORM
) 形式への変換のみがサポートされます。
YUV-RGB フォーマットの変換だけでなく、必要に応じてビデオ プロセッサーを使ってカラー スペースの変換も同時に行うことができます。 サポートされている変換は次のとおりです。
- BT.2020 から BT.709
- BT.709 から BT.2020
適切なカラー スペースの種類については 、DXGI_COLOR_SPACE_TYPE イーナムを参照してください。
ビデオ プロセッサの作成
ID3D12VideoDevice::CreateVideoProcessor を呼び出して、ID3D12VideoProcessor
のインスタンスを作成します。 ビデオ プロセッサは、必要な中間メモリ、キャッシュされた処理データ、またはその他の一時的な作業領域を含む、ビデオ処理セッションのための状態を保持します。 ビデオ プロセッサの作成引数は、実行される操作、または ID3D12VideoProcessCommandList1::ProcessFrames
の時に利用可能な操作を指定します。
C++
D3D12_VIDEO_PROCESS_INPUT_STREAM_DESC inputStreamDesc{};
inputStreamDesc.Format = DXGI_FORMAT_NV12;
inputStreamDesc.ColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
inputStreamDesc.SourceSizeRange = D3D12_VIDEO_SIZE_RANGE{ g_MaxVideoWidth, g_MaxVideoHeight, 1, 1 };
inputStreamDesc.DestinationSizeRange = D3D12_VIDEO_SIZE_RANGE{ g_MaxVideoWidth, g_MaxVideoHeight, 1, 1 };
D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC outputStreamDesc{};
outputStreamDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
outputStreamDesc.ColorSpace = DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709;
hr = pVideoDevice->CreateVideoProcessor(0, &outputStreamDesc, 1, &inputStreamDesc, IID_GRAPHICS_PPV_ARGS(m_pVideoProcessor.GetAddressOf()));
ビデオ プロセッサは、複数のコマンド リストからのコマンドを記録するために使用できますが、一度に 1 つのコマンド リストにしか関連付けられません。 アプリケーションは、ビデオ プロセッサーへのアクセスを同期させる役割を担っています。 また、アプリケーションでは、ビデオ プロセッサに対するビデオ処理コマンドを GPU で実行される順序に記録する必要があります。
IMFSample からの出力テクスチャのクエリ
次のコード スニペットは、ビデオ処理やその他のグラフィックス操作で使用するために IMFSample からデコードされた D3D12 出力テクスチャを問い合わせる方法を示しています
C++
IMFSample* pSample = pOutputDecodedSample;
HRESULT hr = pSample->GetBufferCount(&bufferCount);
if (FAILED(hr))
return hr;
assert(bufferCount == 1);
ComPtr<IMFMediaBuffer> spBuffer;
hr = pSample->GetBufferByIndex(0, spBuffer.GetAddressOf());
if (FAILED(hr))
return hr;
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
hr = spBuffer.Get()->QueryInterface(spDXGIBuffer.GetAddressOf());
if (FAILED(hr))
return hr;
ComPtr<ID3D12Resource> spResourceTexture;
hr = spDXGIBuffer->GetResource(IID_GRAPHICS_PPV_ARGS(spResourceTexture.GetAddressOf()));
if (FAILED(hr))
return hr;
UINT32 uiIndexSrc;
hr = spDXGIBuffer->GetSubresourceIndex(&uiIndexSrc);
if (FAILED(hr))
return hr;
ビデオ プロセッサ コマンドの実行
ビデオ プロセッサ コマンドの作成と実行では、 D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS
コマンド リスト/キュー/アロケータ を使用した D3D12 標準のワーク サブミッション モデルを使用します。 下記のサンプル コードは、それらを作成する方法を示しています。
C++
HRESULT hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS, IID_GRAPHICS_PPV_ARGS(m_pVpCommandAllocator.GetAddressOf()));
if (FAILED(hr))
return hr;
D3D12_COMMAND_QUEUE_DESC descQueue{};
descQueue.Type = D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS;
descQueue.Priority = 0;
descQueue.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
hr = pDevice->CreateCommandQueue(&descQueue, IID_GRAPHICS_PPV_ARGS(m_pVpCommandQueue.GetAddressOf()));
if (FAILED(hr))
return hr;
hr = pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS, m_pVpCommandAllocator.Get(), nullptr, __uuidof(ID3D12CommandList), reinterpret_cast<void**>(m_pVpCommandList.GetAddressOf()));
if (FAILED(hr))
return hr;
ビデオ処理操作のためのすべての入出力引数は、入力引数構造体である D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS と、および出力引数構造体であるD3D12_VIDEO_PROCESS_OUTPUT_STREAM_ARGUMENTS に整理されます。 アプリケーションは ID3D12VideoProcessCommandList::P rocessFrames を呼び出して、実行したいビデオ処理操作を記録する必要があります。
コマンド リストが記録されると、GPU にフレーム処理を任せるために、ビデオ プロセッサのコマンド キューで ID3D12CommandQueue::ExecuteCommandLists
を呼び出します。 なお、Xbox Series S/X では、マルチスレッド アクセスによって予期せぬ動作が発生する可能性があるため、ビデオ プロセッサ コマンド キューとグラフィックス コマンド キューへのアクセスを同期する必要があります。