次の方法で共有


DirectShow での DXVA 2.0 のサポート

このトピックでは、DirectShow デコーダー フィルターで DirectX Video Acceleration (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 をサポートするためにデコーダー フィルターが実行する必要がある基本的な手順を次に示します。

  1. メディアの種類をネゴシエートします。
  2. DXVA デコーダー構成を見つけます。
  3. デコーダーが DXVA デコードを使用していることをビデオ レンダラーに通知します。
  4. Direct3D サーフェスを割り当てるカスタム アロケーターを指定します。

これらの手順については、このトピックの残りの部分で詳しく説明します。

移行に関するメモ

DXVA 1.0 から移行する場合は、2 つのバージョンの大きな違いに注意する必要があります。

  • DXVA 2.0 では、IDirectXVideoDecoder インターフェイスを介して DXVA 2.0 API に直接アクセスできるため、IAMVideoAccelerator インターフェイスと IAMVideoAcceleratorNotify インターフェイスは使用されません。
  • メディアの種類のネゴシエーション中に、デコーダーはサブタイプとしてビデオ アクセラレーション GUID を使用しません。 代わりに、サブタイプは、ソフトウェアのデコードと同様に、圧縮されていないビデオ形式 (NV12 など) です。
  • アクセラレータを構成する手順が変更されました。 DXVA 1.0 では、デコーダーは DXVA_ConfigPictureDecode 構造体を使用して Execute を呼び出して、アッチェレーターを構成します。 DXVA 2.0 では、デコーダーは次のセクションで説明するように IDirectXVideoDecoderService インターフェイスを使用します。
  • デコーダーは、圧縮されていないバッファーを割り当てます。 ビデオ レンダラーによって割り当てられることがなくなりました。
  • デコードされたフレームを表示するために IAMVideoAccelerator::D isplayFrame を呼び出す代わりに、デコーダーはソフトウェアデコードと同様に IMemInputPin::Receive を呼び出してフレームをレンダラーに配信します。
  • デコーダーは、データ バッファーが更新に対して安全かどうかを確認する責任を負いません。 したがって、DXVA 2.0 には 、IAMVideoAccelerator::QueryRenderStatus と同等のメソッドはありません。
  • サブ画像ブレンドは、DXVA2.0 ビデオ プロセッサ API を使用して、ビデオ レンダラーによって行われます。 サブPICTURE (DVD デコーダーなど) を提供するデコーダーは、サブ画像データを別の出力ピンに送信する必要があります。

デコード操作の場合、DXVA 2.0 では DXVA 1.0 と同じデータ構造が使用されます。

拡張ビデオ レンダラー (EVR) フィルターは、DXVA 2.0 をサポートしています。 Video Mixing Renderer フィルター (VMR-7 および VMR-9) では、DXVA 1.0 のみがサポートされます。

デコーダー構成の検索

デコーダーは、出力メディアの種類をネゴシエートした後、DXVA デコーダー デバイスの互換性のある構成を見つける必要があります。 この手順は、出力ピンの CBaseOutputPin::CompleteConnect メソッド内で実行できます。 この手順により、デコーダーが DXVA の使用にコミットする前に、グラフィックス ドライバーでデコーダーに必要な機能が確実にサポートされます。

デコーダー デバイスの構成を見つけるには、次の操作を行います。

  1. IMFGetService インターフェイスのレンダラーの入力ピンに対してクエリを実行します。

  2. IMFGetService::GetService を呼び出して、IDirect3DDeviceManager9 インターフェイスへのポインターを取得します。 サービス GUID がMR_VIDEO_ACCELERATION_SERVICE。

  3. IDirect3DDeviceManager9::OpenDeviceHandle を呼び出して、レンダラーの Direct3D デバイスへのハンドルを取得します。

  4. IDirect3DDeviceManager9::GetVideoService を呼び出し、デバイス ハンドルを渡します。 このメソッドは、 IDirectXVideoDecoderService インターフェイスへのポインターを返します。

  5. IDirectXVideoDecoderService::GetDecoderDeviceGuids を呼び出します。 このメソッドは、デコーダー デバイス GUID の配列を返します。

  6. デコーダー GUID の配列をループ処理して、デコーダー フィルターがサポートするものを見つけます。 たとえば、MPEG-2 デコーダーの場合は、 DXVA2_ModeMPEG2_MOCOMPDXVA2_ModeMPEG2_IDCTまたはDXVA2_ModeMPEG2_VLDを探します。

  7. 候補デコーダー デバイス GUID が見つかったら、 GUID を IDirectXVideoDecoderService::GetDecoderRenderTargets メソッドに渡します。 このメソッドは、 D3DFORMAT 値として指定されたレンダー ターゲット形式の配列を返します。

  8. レンダー ターゲット形式をループ処理し、出力形式に一致するものを探します。 通常、デコーダー デバイスでは、1 つのレンダー ターゲット形式がサポートされます。 デコーダー フィルターは、このサブタイプを使用してレンダラーに接続する必要があります。 CompleteConnect の最初の呼び出しでは、デコーダーはレンダー ターゲットの形式を決定し、この形式を優先する出力の種類として返すことができます。

  9. IDirectXVideoDecoderService::GetDecoderConfigurations を呼び出します。 提案された形式を記述する DXVA2_VideoDesc 構造と共に、同じデコーダー デバイス GUID を渡します。 メソッドは、 DXVA2_ConfigPictureDecode 構造体の配列を返します。 各構造体は、デコーダー デバイスで使用可能な 1 つの構成について説明します。

  10. 前の手順が成功した場合は、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 メソッド内で実行できます。 この手順は、アロケーターの選択方法に影響するため、アロケーターを選択する前に行う必要があります。

  1. IMFGetService インターフェイスのレンダラーの入力ピンに対してクエリを実行します。
  2. IMFGetService::GetService を呼び出して、IDirectXVideoMemoryConfiguration インターフェイスへのポインターを取得します。 サービス GUID が MR_VIDEO_ACCELERATION_SERVICE
  3. ループ内で IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex を呼び出し、 dwTypeIndex 変数を 0 からインクリメントします。 メソッドが pdwType パラメーターでDXVA2_SurfaceType_DecoderRenderTarget値を返すときに停止します。 この手順により、ビデオ レンダラーでハードウェア高速デコードが確実にサポートされます。 この手順は、常に EVR フィルターに対して成功します。
  4. 前の手順が成功した場合は、値を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

カスタム アロケーターを提供するには、次の手順を実行します。

  1. メディア サンプルのクラスを定義します。 このクラスは CMediaSample クラスから派生できます。 このクラス内で、次の操作を行います。
    • Direct3D サーフェスへのポインターを格納します。
    • IMFGetService インターフェイスを実装します。 GetService メソッドで、サービス GUID がMR_BUFFER_SERVICEされている場合は、要求されたインターフェイスについて Direct3D サーフェイスに対してクエリを実行します。 それ以外の場合、 GetServiceMF_E_UNSUPPORTED_SERVICEを返すことができます。
    • CMediaSample::GetPointer メソッドをオーバーライドして、E_NOTIMPLを返します。
  2. アロケーターのクラスを定義します。 アロケーターは CBaseAllocator クラスから派生できます。 このクラス内で、次の操作を行います。
  3. フィルターの出力ピンで、 CBaseOutputPin::InitAllocator メソッドを オーバーライドします。 このメソッド内に、カスタム アロケーターのインスタンスを作成します。
  4. フィルターで、 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を返します。 これが発生した場合は、次の操作を行います。

  1. IDirect3DDeviceManager9::CloseDeviceHandle を呼び出して、デバイス ハンドルを閉じます。
  2. IDirectXVideoDecoderService ポインターと IDirectXVideoDecoder ポインターを解放します。
  3. 新しいデバイス ハンドルを開きます。
  4. 「デコーダー構成の検索」セクションで説明されているように、新しい デコーダー構成をネゴシエートします
  5. 新しいデコーダー デバイスを作成します。

デバイス ハンドルが有効であると仮定すると、デコード プロセスは次のように機能します。

  1. IDirectXVideoDecoder::BeginFrame を呼び出します。
  2. 次の操作を 1 回以上行います。
    1. IDirectXVideoDecoder::GetBuffer を呼び出して、DXVA デコーダー バッファーを取得します。
    2. バッファーを塗りつぶします。
    3. IDirectXVideoDecoder::ReleaseBuffer を呼び出します。
  3. 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 のData Flowの概要」トピックを参照してください。

DirectX ビデオ アクセラレータ 2.0