このトピックでは、DirectShow デコーダー フィルターで DirectX ビデオ アクセラレーション (DXVA) 2.0 をサポートする方法について説明します。 具体的には、デコーダーとビデオ レンダラーの間の通信について説明します。 このトピックでは、DXVA デコードを実装する方法については説明しません。
[前提条件]
このトピックでは、DirectShow フィルターの記述について理解していることを前提としています。 詳細については、DirectShow SDK ドキュメントの DirectShow フィルターの記述 に関するトピックを参照してください。 このトピックのコード例では、デコーダー フィルターが CTransformFilter クラスから派生し、次のクラス定義があることを前提としています。
class CDecoder : public CTransformFilter
{
public:
static CUnknown* WINAPI CreateInstance(IUnknown *pUnk, HRESULT *pHr);
HRESULT CompleteConnect(PIN_DIRECTION direction, IPin *pPin);
HRESULT InitAllocator(IMemAllocator **ppAlloc);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp);
// TODO: The implementations of these methods depend on the specific decoder.
HRESULT CheckInputType(const CMediaType *mtIn);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
HRESULT CTransformFilter::GetMediaType(int,CMediaType *);
private:
CDecoder(HRESULT *pHr);
~CDecoder();
CBasePin * GetPin(int n);
HRESULT ConfigureDXVA2(IPin *pPin);
HRESULT SetEVRForDXVA2(IPin *pPin);
HRESULT FindDecoderConfiguration(
/* [in] */ IDirectXVideoDecoderService *pDecoderService,
/* [in] */ const GUID& guidDecoder,
/* [out] */ DXVA2_ConfigPictureDecode *pSelectedConfig,
/* [out] */ BOOL *pbFoundDXVA2Configuration
);
private:
IDirectXVideoDecoderService *m_pDecoderService;
DXVA2_ConfigPictureDecode m_DecoderConfig;
GUID m_DecoderGuid;
HANDLE m_hDevice;
FOURCC m_fccOutputFormat;
};
このトピックの残りの部分では、 デコーダー という用語は、圧縮されたビデオを受信し、圧縮されていないビデオを出力するデコーダー フィルターを指します。 デコーダー デバイスという用語は、グラフィックス ドライバーによって実装されるハードウェア ビデオ アクセラレータを指します。
DXVA 2.0 をサポートするためにデコーダー フィルターが実行する必要がある基本的な手順を次に示します。
- メディアの種類をネゴシエートします。
- DXVA デコーダー構成を見つけます。
- デコーダーが DXVA デコードを使用していることをビデオ レンダラーに通知します。
- Direct3D サーフェスを割り当てるカスタム アロケーターを提供します。
これらの手順については、このトピックの残りの部分で詳しく説明します。
移行に関する注意事項
DXVA 1.0 から移行する場合は、2 つのバージョンの大きな違いに注意する必要があります。
- デコーダーは IDirectXVideoDecoder インターフェイスを介して直接 DXVA 2.0 API にアクセスできるため、DXVA 2.0 では IAMVideoAccelerator インターフェイスと IAMVideoAcceleratorNotify インターフェイスは使用されません。
- メディア タイプ ネゴシエーション中、デコーダーはサブタイプとしてビデオ アクセラレーション GUID を使用しません。 代わりに、サブタイプは、ソフトウェアデコードと同様に、非圧縮のビデオ形式 (NV12 など) です。
- アクセラレータを構成する手順が変更されました。 DXVA 1.0 では、デコーダーは DXVA_ConfigPictureDecode 構造体を使用して Execute を呼び出してアクセラレータを構成します。 DXVA 2.0 では、デコーダーは次のセクションで説明するように IDirectXVideoDecoderService インターフェイスを使用します。
- デコーダーは、圧縮されていないバッファーを割り当てます。 ビデオ レンダラーは、それらを割り当てなくなりました。
- デコードされたフレームを表示するために IAMVideoAccelerator::D isplayFrame を呼び出す代わりに、デコーダーはソフトウェアデコードと同様に IMemInputPin::Receive を呼び出してフレームをレンダラーに配信します。
- デコーダーは、データ バッファーが更新に対して安全かどうかを確認する責任を負いません。 そのため、DXVA 2.0 には IAMVideoAccelerator::QueryRenderStatus と同等のメソッドはありません。
- サブPICTURE ブレンドは、DXVA2.0 ビデオ プロセッサ API を使用して、ビデオ レンダラーによって行われます。 サブPICTURE (DVD デコーダーなど) を提供するデコーダーは、別の出力ピンでサブPICTURE データを送信する必要があります。
デコード操作の場合、DXVA 2.0 では DXVA 1.0 と同じデータ構造が使用されます。
拡張ビデオ レンダラー (EVR) フィルターは、DXVA 2.0 をサポートしています。 ビデオ ミキシング レンダラー フィルター (VMR-7 および VMR-9) では、DXVA 1.0 のみがサポートされます。
デコーダー構成の検索
デコーダーは、出力メディアの種類をネゴシエートした後、DXVA デコーダー デバイスの互換性のある構成を見つける必要があります。 この手順は、出力ピンの CBaseOutputPin::CompleteConnect メソッド内で実行できます。 この手順により、デコーダーが DXVA の使用にコミットする前に、グラフィックス ドライバーがデコーダーに必要な機能をサポートすることが保証されます。
デコーダー デバイスの構成を見つけるには、次の操作を行います。
IMFGetService インターフェイスのレンダラーの入力ピンに対してクエリを実行します。
IMFGetService::GetService を呼び出して、IDirect3DDeviceManager9 インターフェイスへのポインターを取得します。 サービス GUID がMR_VIDEO_ACCELERATION_SERVICE。
IDirect3DDeviceManager9::OpenDeviceHandle を呼び出して、レンダラーの Direct3D デバイスへのハンドルを取得します。
IDirect3DDeviceManager9::GetVideoService を呼び出し、デバイス ハンドルを渡します。 このメソッドは、 IDirectXVideoDecoderService インターフェイスへのポインターを返します。
IDirectXVideoDecoderService::GetDecoderDeviceGuids を呼び出します。 このメソッドは、デコーダー デバイス GUID の配列を返します。
デコーダー GUID の配列をループして、デコーダー フィルターがサポートするものを見つけます。 たとえば、MPEG-2 デコーダーの場合は、 DXVA2_ModeMPEG2_MOCOMP、 DXVA2_ModeMPEG2_IDCT、または DXVA2_ModeMPEG2_VLDを検索します。
候補のデコーダー デバイス GUID が見つかると、GUID を IDirectXVideoDecoderService::GetDecoderRenderTargets メソッドに渡します。 このメソッドは、D3DFORMAT値として指定されたレンダー ターゲット形式の配列 を 返します。
レンダー ターゲット形式をループ処理し、出力形式に一致するものを探します。 通常、デコーダー デバイスは単一のレンダー ターゲット形式をサポートします。 デコーダー フィルターは、このサブタイプを使用してレンダラーに接続する必要があります。 CompleteConnect の最初の呼び出しでは、デコーダーはレンダー ターゲットの形式を決定し、この形式を優先出力の種類として返すことができます。
IDirectXVideoDecoderService::GetDecoderConfigurations を呼び出します。 提案された形式を記述する DXVA2_VideoDesc 構造と共に、同じデコーダー デバイス GUID を渡します。 このメソッドは、 DXVA2_ConfigPictureDecode 構造体の配列を返します。 各構造体は、デコーダー デバイスに対して可能な 1 つの構成を記述します。
前の手順が成功したと仮定して、Direct3D デバイス ハンドル、デコーダー デバイス GUID、および構成構造を格納します。 フィルターはこの情報を使用してデコーダー デバイスを作成します。
次のコードは、デコーダー構成を検索する方法を示しています。
HRESULT CDecoder::ConfigureDXVA2(IPin *pPin)
{
UINT cDecoderGuids = 0;
BOOL bFoundDXVA2Configuration = FALSE;
GUID guidDecoder = GUID_NULL;
DXVA2_ConfigPictureDecode config;
ZeroMemory(&config, sizeof(config));
// Variables that follow must be cleaned up at the end.
IMFGetService *pGetService = NULL;
IDirect3DDeviceManager9 *pDeviceManager = NULL;
IDirectXVideoDecoderService *pDecoderService = NULL;
GUID *pDecoderGuids = NULL; // size = cDecoderGuids
HANDLE hDevice = INVALID_HANDLE_VALUE;
// Query the pin for IMFGetService.
HRESULT hr = pPin->QueryInterface(IID_PPV_ARGS(&pGetService));
// Get the Direct3D device manager.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE,
IID_PPV_ARGS(&pDeviceManager)
);
}
// Open a new device handle.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->OpenDeviceHandle(&hDevice);
}
// Get the video decoder service.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->GetVideoService(
hDevice, IID_PPV_ARGS(&pDecoderService));
}
// Get the decoder GUIDs.
if (SUCCEEDED(hr))
{
hr = pDecoderService->GetDecoderDeviceGuids(
&cDecoderGuids, &pDecoderGuids);
}
if (SUCCEEDED(hr))
{
// Look for the decoder GUIDs we want.
for (UINT iGuid = 0; iGuid < cDecoderGuids; iGuid++)
{
// Do we support this mode?
if (!IsSupportedDecoderMode(pDecoderGuids[iGuid]))
{
continue;
}
// Find a configuration that we support.
hr = FindDecoderConfiguration(pDecoderService, pDecoderGuids[iGuid],
&config, &bFoundDXVA2Configuration);
if (FAILED(hr))
{
break;
}
if (bFoundDXVA2Configuration)
{
// Found a good configuration. Save the GUID and exit the loop.
guidDecoder = pDecoderGuids[iGuid];
break;
}
}
}
if (!bFoundDXVA2Configuration)
{
hr = E_FAIL; // Unable to find a configuration.
}
if (SUCCEEDED(hr))
{
// Store the things we will need later.
SafeRelease(&m_pDecoderService);
m_pDecoderService = pDecoderService;
m_pDecoderService->AddRef();
m_DecoderConfig = config;
m_DecoderGuid = guidDecoder;
m_hDevice = hDevice;
}
if (FAILED(hr))
{
if (hDevice != INVALID_HANDLE_VALUE)
{
pDeviceManager->CloseDeviceHandle(hDevice);
}
}
SafeRelease(&pGetService);
SafeRelease(&pDeviceManager);
SafeRelease(&pDecoderService);
return hr;
}
HRESULT CDecoder::FindDecoderConfiguration(
/* [in] */ IDirectXVideoDecoderService *pDecoderService,
/* [in] */ const GUID& guidDecoder,
/* [out] */ DXVA2_ConfigPictureDecode *pSelectedConfig,
/* [out] */ BOOL *pbFoundDXVA2Configuration
)
{
HRESULT hr = S_OK;
UINT cFormats = 0;
UINT cConfigurations = 0;
D3DFORMAT *pFormats = NULL; // size = cFormats
DXVA2_ConfigPictureDecode *pConfig = NULL; // size = cConfigurations
// Find the valid render target formats for this decoder GUID.
hr = pDecoderService->GetDecoderRenderTargets(
guidDecoder,
&cFormats,
&pFormats
);
if (SUCCEEDED(hr))
{
// Look for a format that matches our output format.
for (UINT iFormat = 0; iFormat < cFormats; iFormat++)
{
if (pFormats[iFormat] != (D3DFORMAT)m_fccOutputFormat)
{
continue;
}
// Fill in the video description. Set the width, height, format,
// and frame rate.
DXVA2_VideoDesc videoDesc = {0};
FillInVideoDescription(&videoDesc); // Private helper function.
videoDesc.Format = pFormats[iFormat];
// Get the available configurations.
hr = pDecoderService->GetDecoderConfigurations(
guidDecoder,
&videoDesc,
NULL, // Reserved.
&cConfigurations,
&pConfig
);
if (FAILED(hr))
{
break;
}
// Find a supported configuration.
for (UINT iConfig = 0; iConfig < cConfigurations; iConfig++)
{
if (IsSupportedDecoderConfig(pConfig[iConfig]))
{
// This configuration is good.
*pbFoundDXVA2Configuration = TRUE;
*pSelectedConfig = pConfig[iConfig];
break;
}
}
CoTaskMemFree(pConfig);
break;
} // End of formats loop.
}
CoTaskMemFree(pFormats);
// Note: It is possible to return S_OK without finding a configuration.
return hr;
}
この例はジェネリックであるため、一部のロジックは、デコーダーによって実装する必要があるヘルパー関数に配置されています。 次のコードは、これらの関数の宣言を示しています。
// Returns TRUE if the decoder supports a given decoding mode.
BOOL IsSupportedDecoderMode(const GUID& mode);
// Returns TRUE if the decoder supports a given decoding configuration.
BOOL IsSupportedDecoderConfig(const DXVA2_ConfigPictureDecode& config);
// Fills in a DXVA2_VideoDesc structure based on the input format.
void FillInVideoDescription(DXVA2_VideoDesc *pDesc);
ビデオ レンダラーへの通知
デコーダーがデコーダー構成を見つけた場合、次の手順は、デコーダーがハードウェア アクセラレーションを使用することをビデオ レンダラーに通知することです。 CompleteConnect メソッド内でこの手順を実行できます。 この手順は、アロケーターの選択方法に影響するため、アロケーターを選択する前に実行する必要があります。
- IMFGetService インターフェイスのレンダラーの入力ピンに対してクエリを実行します。
- IMFGetService::GetService を呼び出して、IDirectXVideoMemoryConfiguration インターフェイスへのポインターを取得します。 サービス GUID が MR_VIDEO_ACCELERATION_SERVICE。
- ループ内で IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex を呼び出し、 dwTypeIndex 変数を 0 からインクリメントします。 メソッドが pdwType パラメーターでDXVA2_SurfaceType_DecoderRenderTarget値を返すときに停止します。 この手順により、ビデオ レンダラーでハードウェア高速化デコードがサポートされるようになります。 この手順は、常に EVR フィルターに対して成功します。
- 前の手順が成功した場合は、DXVA2_SurfaceType_DecoderRenderTarget値を指定して IDirectXVideoMemoryConfiguration::SetSurfaceType を呼び出します。 この値で SetSurfaceType を 呼び出すと、ビデオ レンダラーが DXVA モードになります。 ビデオ レンダラーがこのモードの場合、デコーダーは独自のアロケーターを提供する必要があります。
次のコードは、ビデオ レンダラーに通知する方法を示しています。
HRESULT CDecoder::SetEVRForDXVA2(IPin *pPin)
{
HRESULT hr = S_OK;
IMFGetService *pGetService = NULL;
IDirectXVideoMemoryConfiguration *pVideoConfig = NULL;
// Query the pin for IMFGetService.
hr = pPin->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
// Get the IDirectXVideoMemoryConfiguration interface.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE, IID_PPV_ARGS(&pVideoConfig));
}
// Notify the EVR.
if (SUCCEEDED(hr))
{
DXVA2_SurfaceType surfaceType;
for (DWORD iTypeIndex = 0; ; iTypeIndex++)
{
hr = pVideoConfig->GetAvailableSurfaceTypeByIndex(iTypeIndex, &surfaceType);
if (FAILED(hr))
{
break;
}
if (surfaceType == DXVA2_SurfaceType_DecoderRenderTarget)
{
hr = pVideoConfig->SetSurfaceType(DXVA2_SurfaceType_DecoderRenderTarget);
break;
}
}
}
SafeRelease(&pGetService);
SafeRelease(&pVideoConfig);
return hr;
}
デコーダーが有効な構成を検出し、ビデオ レンダラーに正常に通知した場合、デコーダーは DXVA を使用してデコードできます。 デコーダーは、次のセクションで説明するように、出力ピンのカスタム アロケーターを実装する必要があります。
圧縮されていないバッファーの割り当て
DXVA 2.0 では、デコーダーは、圧縮されていないビデオ バッファーとして使用する Direct3D サーフェスを割り当てる役割を担います。 そのため、デコーダーは、サーフェスを作成するカスタム アロケーターを実装する必要があります。 このアロケーターによって提供されるメディア サンプルは、Direct3D サーフェスへのポインターを保持します。 EVR は、メディア サンプルで IMFGetService::GetService を呼び出して、サーフェスへのポインターを取得します。 サービス識別子が MR_BUFFER_SERVICE。
カスタム アロケーターを提供するには、次の手順を実行します。
- メディア サンプルのクラスを定義します。 このクラスは CMediaSample クラスから派生できます。 このクラス内で、次の操作を行います。
- Direct3D サーフェイスへのポインターを格納します。
- IMFGetService インターフェイスを実装します。 GetService メソッドで、サービス GUID がMR_BUFFER_SERVICEされている場合は、要求されたインターフェイスについて Direct3D サーフェスにクエリを実行します。 それ以外の場合、 GetService は MF_E_UNSUPPORTED_SERVICEを返すことができます。
- CMediaSample::GetPointer メソッドをオーバーライドして、E_NOTIMPLを返します。
- アロケーターのクラスを定義します。 アロケーターは CBaseAllocator クラスから派生できます。 このクラス内で、次の操作を行います。
- CBaseAllocator::Alloc メソッドをオーバーライドします。 このメソッド内で 、IDirectXVideoAccelerationService::CreateSurface を呼び出してサーフェスを作成します。 ( IDirectXVideoDecoderService インターフェイスは、 IDirectXVideoAccelerationService からこのメソッドを継承します)。
- CBaseAllocator::Free メソッドをオーバーライドしてサーフェスを解放します。
- フィルターの出力ピンで、 CBaseOutputPin::InitAllocator メソッドを オーバーライドします。 このメソッド内に、カスタム アロケーターのインスタンスを作成します。
- フィルターで、 CTransformFilter::D ecideBufferSize メソッドを 実装します。 pProperties パラメーターは、EVR に必要なサーフェスの数を示します。 デコーダーが必要とするサーフェスの数をこの値に追加し、アロケーターで IMemAllocator::SetProperties を呼び出します。
次のコードは、メディア サンプル クラスを実装する方法を示しています。
class CDecoderSample : public CMediaSample, public IMFGetService
{
friend class CDecoderAllocator;
public:
CDecoderSample(CDecoderAllocator *pAlloc, HRESULT *phr)
: CMediaSample(NAME("DecoderSample"), (CBaseAllocator*)pAlloc, phr, NULL, 0),
m_pSurface(NULL),
m_dwSurfaceId(0)
{
}
// Note: CMediaSample does not derive from CUnknown, so we cannot use the
// DECLARE_IUNKNOWN macro that is used by most of the filter classes.
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
CheckPointer(ppv, E_POINTER);
if (riid == IID_IMFGetService)
{
*ppv = static_cast<IMFGetService*>(this);
AddRef();
return S_OK;
}
else
{
return CMediaSample::QueryInterface(riid, ppv);
}
}
STDMETHODIMP_(ULONG) AddRef()
{
return CMediaSample::AddRef();
}
STDMETHODIMP_(ULONG) Release()
{
// Return a temporary variable for thread safety.
ULONG cRef = CMediaSample::Release();
return cRef;
}
// IMFGetService::GetService
STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppv)
{
if (guidService != MR_BUFFER_SERVICE)
{
return MF_E_UNSUPPORTED_SERVICE;
}
else if (m_pSurface == NULL)
{
return E_NOINTERFACE;
}
else
{
return m_pSurface->QueryInterface(riid, ppv);
}
}
// Override GetPointer because this class does not manage a system memory buffer.
// The EVR uses the MR_BUFFER_SERVICE service to get the Direct3D surface.
STDMETHODIMP GetPointer(BYTE ** ppBuffer)
{
return E_NOTIMPL;
}
private:
// Sets the pointer to the Direct3D surface.
void SetSurface(DWORD surfaceId, IDirect3DSurface9 *pSurf)
{
SafeRelease(&m_pSurface);
m_pSurface = pSurf;
if (m_pSurface)
{
m_pSurface->AddRef();
}
m_dwSurfaceId = surfaceId;
}
IDirect3DSurface9 *m_pSurface;
DWORD m_dwSurfaceId;
};
次のコードは、アロケーターに Alloc メソッドを実装する方法を示しています。
HRESULT CDecoderAllocator::Alloc()
{
CAutoLock lock(this);
HRESULT hr = S_OK;
if (m_pDXVA2Service == NULL)
{
return E_UNEXPECTED;
}
hr = CBaseAllocator::Alloc();
// If the requirements have not changed, do not reallocate.
if (hr == S_FALSE)
{
return S_OK;
}
if (SUCCEEDED(hr))
{
// Free the old resources.
Free();
// Allocate a new array of pointers.
m_ppRTSurfaceArray = new (std::nothrow) IDirect3DSurface9*[m_lCount];
if (m_ppRTSurfaceArray == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
ZeroMemory(m_ppRTSurfaceArray, sizeof(IDirect3DSurface9*) * m_lCount);
}
}
// Allocate the surfaces.
if (SUCCEEDED(hr))
{
hr = m_pDXVA2Service->CreateSurface(
m_dwWidth,
m_dwHeight,
m_lCount - 1,
(D3DFORMAT)m_dwFormat,
D3DPOOL_DEFAULT,
0,
DXVA2_VideoDecoderRenderTarget,
m_ppRTSurfaceArray,
NULL
);
}
if (SUCCEEDED(hr))
{
for (m_lAllocated = 0; m_lAllocated < m_lCount; m_lAllocated++)
{
CDecoderSample *pSample = new (std::nothrow) CDecoderSample(this, &hr);
if (pSample == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
if (FAILED(hr))
{
break;
}
// Assign the Direct3D surface pointer and the index.
pSample->SetSurface(m_lAllocated, m_ppRTSurfaceArray[m_lAllocated]);
// Add to the sample list.
m_lFree.Add(pSample);
}
}
if (SUCCEEDED(hr))
{
m_bChanged = FALSE;
}
return hr;
}
Free メソッドのコードを次に示します。
void CDecoderAllocator::Free()
{
CMediaSample *pSample = NULL;
do
{
pSample = m_lFree.RemoveHead();
if (pSample)
{
delete pSample;
}
} while (pSample);
if (m_ppRTSurfaceArray)
{
for (long i = 0; i < m_lAllocated; i++)
{
SafeRelease(&m_ppRTSurfaceArray[i]);
}
delete [] m_ppRTSurfaceArray;
}
m_lAllocated = 0;
}
カスタム アロケーターの実装の詳細については、DirectShow SDK ドキュメントの カスタム アロケーターの提供 に関するトピックを参照してください。
デコーディング
デコーダー デバイスを作成するには、 IDirectXVideoDecoderService::CreateVideoDecoder を呼び出します。 このメソッドは、デコーダー デバイスの IDirectXVideoDecoder インターフェイスへのポインターを返します。
各フレームで IDirect3DDeviceManager9::TestDevice を呼び出して、デバイス ハンドルをテストします。 デバイスが変更された場合、メソッドはDXVA2_E_NEW_VIDEO_DEVICEを返します。 この場合は、次の操作を行います。
- IDirect3DDeviceManager9::CloseDeviceHandle を呼び出して、デバイス ハンドルを閉じます。
- IDirectXVideoDecoderService ポインターと IDirectXVideoDecoder ポインターを解放します。
- 新しいデバイス ハンドルを開きます。
- デコーダー構成の検索に関するセクションの説明に従って、新しい デコーダー構成をネゴシエートします。
- 新しいデコーダー デバイスを作成します。
デバイス ハンドルが有効であると仮定すると、デコード プロセスは次のように動作します。
- IDirectXVideoDecoder::BeginFrame を呼び出します。
- 次の操作を 1 回以上実行します。
- IDirectXVideoDecoder::GetBuffer を呼び出して、DXVA デコーダー バッファーを取得します。
- バッファを埋めます。
- IDirectXVideoDecoder::ReleaseBuffer を呼び出します。
- IDirectXVideoDecoder::Execute を呼び出して、フレームでデコード操作を実行します。
DXVA 2.0 では、デコード操作に DXVA 1.0 と同じデータ構造が使用されます。 DXVA プロファイルの元のセット (H.261、H.263、MPEG-2 の場合) については、 DXVA 1.0 仕様でこれらのデータ構造について説明します。
BeginFrame/Execute 呼び出しの各ペア内で、GetBuffer を複数回呼び出すことができますが、DXVA バッファーの種類ごとに 1 回だけ呼び出すことができます。 同じバッファー型で 2 回呼び出すと、データが上書きされます。
Execute を呼び出した後、IMemInputPin::Receive を呼び出して、ソフトウェアデコードと同様に、フレームをビデオ レンダラーに配信します。 Receive メソッドは非同期です。が返された後、デコーダーは次のフレームのデコードを続行できます。 ディスプレイ ドライバーは、バッファーの使用中にバッファーを上書きするデコード コマンドを防ぎます。 デコーダーは、レンダラーがサンプルを解放するまで、サーフェスを再利用して別のフレームをデコードしないようにする必要があります。 レンダラーがサンプルを解放すると、アロケーターはサンプルを使用可能なサンプルのプールに戻します。 次に使用可能なサンプルを取得するには、 CBaseOutputPin::GetDeliveryBuffer を呼び出します。次に 、IMemAllocator::GetBuffer を呼び出します。 詳細については、 DirectShow ドキュメントの「DirectShow のデータ フローの概要 」を参照してください。
関連トピック