Mendukung DXVA 2.0 di DirectShow

Topik ini menjelaskan cara mendukung DirectX Video Acceleration (DXVA) 2.0 dalam filter dekoder DirectShow. Secara khusus, ini menjelaskan komunikasi antara dekoder dan perender video. Topik ini tidak menjelaskan cara menerapkan pendekodean DXVA.

Prasyarat

Topik ini mengasumsikan bahwa Anda terbiasa menulis filter DirectShow. Untuk informasi selengkapnya, lihat topik Menulis Filter DirectShow dalam dokumentasi DirectShow SDK. Contoh kode dalam topik ini mengasumsikan bahwa filter dekoder berasal dari kelas CTransformFilter , dengan definisi kelas berikut:

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;
};

Di sisa topik ini, istilah dekoder mengacu pada filter dekoder, yang menerima video terkompresi dan menghasilkan video yang tidak dikompresi. Istilah perangkat dekoder mengacu pada akselerator video perangkat keras yang diterapkan oleh driver grafis.

Berikut adalah langkah-langkah dasar yang harus dilakukan filter dekoder untuk mendukung DXVA 2.0:

  1. Menegosiasikan jenis media.
  2. Temukan konfigurasi dekoder DXVA.
  3. Beri tahu perender video bahwa dekoder menggunakan pendekodean DXVA.
  4. Berikan alokator kustom yang mengalokasikan permukaan Direct3D.

Langkah-langkah ini dijelaskan secara lebih rinci di sisa topik ini.

Catatan Migrasi

Jika Anda bermigrasi dari DXVA 1.0, Anda harus mengetahui beberapa perbedaan signifikan antara kedua versi:

  • DXVA 2.0 tidak menggunakan antarmuka IAMVideoAccelerator dan IAMVideoAcceleratorNotify , karena dekoder dapat mengakses API DXVA 2.0 secara langsung melalui antarmuka IDirectXVideoDecoder .
  • Selama negosiasi jenis media, dekoder tidak menggunakan GUID akselerasi video sebagai subjenis. Sebaliknya, subjenis hanyalah format video yang tidak dikompresi (seperti NV12), seperti halnya pendekodean perangkat lunak.
  • Prosedur untuk mengonfigurasi akselerator telah berubah. Di DXVA 1.0, dekoder memanggil Jalankan dengan struktur DXVA_ConfigPictureDecode untuk mengonfigurasi akselerlator. Di DXVA 2.0, dekoder menggunakan antarmuka IDirectXVideoDecoderService , seperti yang dijelaskan di bagian berikutnya.
  • Dekoder mengalokasikan buffer yang tidak dikompresi. Perender video tidak lagi mengalokasikannya.
  • Alih-alih memanggil IAMVideoAccelerator::D isplayFrame untuk menampilkan bingkai yang didekodekan, dekoder mengirimkan bingkai ke perender dengan memanggil IMemInputPin::Receive, seperti halnya pendekodean perangkat lunak.
  • Dekoder tidak lagi bertanggung jawab untuk memeriksa kapan buffer data aman untuk pembaruan. Oleh karena itu DXVA 2.0 tidak memiliki metode apa pun yang setara dengan IAMVideoAccelerator::QueryRenderStatus.
  • Perpaduan subgambar dilakukan oleh perender video, menggunakan API prosesor video DXVA2.0. Dekode yang menyediakan subgambar (misalnya, dekode DVD) harus mengirim data subgambar pada pin output terpisah.

Untuk operasi pendekodean, DXVA 2.0 menggunakan struktur data yang sama dengan DXVA 1.0.

Filter perender video yang disempurnakan (EVR) mendukung DXVA 2.0. Filter Video Mixing Renderer (VMR-7 dan VMR-9) hanya mendukung DXVA 1.0.

Menemukan Konfigurasi Decoder

Setelah dekoder menegosiasikan jenis media output, decoder harus menemukan konfigurasi yang kompatibel untuk perangkat dekoder DXVA. Anda dapat melakukan langkah ini di dalam metode CBaseOutputPin::CompleteConnect pin output. Langkah ini memastikan bahwa driver grafis mendukung kemampuan yang diperlukan oleh dekoder, sebelum dekoder berkomitmen untuk menggunakan DXVA.

Untuk menemukan konfigurasi untuk perangkat dekoder, lakukan hal berikut:

  1. Kueri pin input perender untuk antarmuka IMFGetService .

  2. Panggil IMFGetService::GetService untuk mendapatkan pointer ke antarmuka IDirect3DDeviceManager9 . GUID layanan MR_VIDEO_ACCELERATION_SERVICE.

  3. Panggil IDirect3DDeviceManager9::OpenDeviceHandle untuk mendapatkan handel ke perangkat Direct3D perender.

  4. Panggil IDirect3DDeviceManager9::GetVideoService dan berikan handel perangkat. Metode ini mengembalikan penunjuk ke antarmuka IDirectXVideoDecoderService .

  5. Panggil IDirectXVideoDecoderService::GetDecoderDeviceGuids. Metode ini mengembalikan array GUID perangkat dekoder.

  6. Ulangi array GUID dekoder untuk menemukan yang didukung filter dekoder. Misalnya, untuk dekoder MPEG-2, Anda akan mencari DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT, atau DXVA2_ModeMPEG2_VLD.

  7. Saat Anda menemukan GUID perangkat dekoder kandidat, teruskan GUID ke metode IDirectXVideoDecoderService::GetDecoderRenderTargets . Metode ini mengembalikan array format target render, yang ditentukan sebagai nilai D3DFORMAT .

  8. Ulangi format target render dan cari format yang cocok dengan format output Anda. Biasanya, perangkat dekoder mendukung satu format target render. Filter dekoder harus tersambung ke perender menggunakan subjenis ini. Dalam panggilan pertama ke CompleteConnect, dekoder dapat menentukan format target render lalu mengembalikan format ini sebagai jenis output pilihan.

  9. Panggil IDirectXVideoDecoderService::GetDecoderConfigurations. Teruskan GUID perangkat dekoder yang sama, bersama dengan struktur DXVA2_VideoDesc yang menjelaskan format yang diusulkan. Metode mengembalikan array struktur DXVA2_ConfigPictureDecode . Setiap struktur menjelaskan satu konfigurasi yang mungkin untuk perangkat dekoder.

  10. Dengan asumsi bahwa langkah-langkah sebelumnya berhasil, simpan handel perangkat Direct3D, GUID perangkat dekoder, dan struktur konfigurasi. Filter akan menggunakan informasi ini untuk membuat perangkat dekoder.

Kode berikut menunjukkan cara menemukan konfigurasi dekoder.

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;
}

Karena contoh ini umum, beberapa logika telah ditempatkan dalam fungsi pembantu yang perlu diimplementasikan oleh dekoder. Kode berikut menunjukkan deklarasi untuk fungsi-fungsi ini:

// 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);

Memberi tahu Perender Video

Jika dekoder menemukan konfigurasi dekoder, langkah selanjutnya adalah memberi tahu perender video bahwa dekoder akan menggunakan akselerasi perangkat keras. Anda dapat melakukan langkah ini di dalam metode CompleteConnect . Langkah ini harus terjadi sebelum alokator dipilih, karena mempengaruhi bagaimana alokator dipilih.

  1. Kueri pin input perender untuk antarmuka IMFGetService .
  2. Panggil IMFGetService::GetService untuk mendapatkan pointer ke antarmuka IDirectXVideoMemoryConfiguration . GUID layanan MR_VIDEO_ACCELERATION_SERVICE.
  3. Panggil IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex dalam perulangan, meningkatkan variabel dwTypeIndex dari nol. Berhenti saat metode mengembalikan nilai DXVA2_SurfaceType_DecoderRenderTarget dalam parameter pdwType . Langkah ini memastikan bahwa perender video mendukung pendekodean yang dipercepat perangkat keras. Langkah ini akan selalu berhasil untuk filter EVR.
  4. Jika langkah sebelumnya berhasil, panggil IDirectXVideoMemoryConfiguration::SetSurfaceType dengan nilai DXVA2_SurfaceType_DecoderRenderTarget. Memanggil SetSurfaceType dengan nilai ini menempatkan perender video ke mode DXVA. Ketika perender video dalam mode ini, dekoder harus menyediakan alokatornya sendiri.

Kode berikut menunjukkan cara memberi tahu perender video.

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;
}

Jika dekoder menemukan konfigurasi yang valid dan berhasil memberi tahu perender video, dekoder dapat menggunakan DXVA untuk pendekodean. Dekoder harus mengimplementasikan alokator kustom untuk pin outputnya, seperti yang dijelaskan di bagian berikutnya.

Mengalokasikan Buffer yang Tidak Dikompresi

Dalam DXVA 2.0, dekoder bertanggung jawab untuk mengalokasikan permukaan Direct3D untuk digunakan sebagai buffer video yang tidak dikompresi. Oleh karena itu, dekoder harus mengimplementasikan alokator kustom yang akan membuat permukaan. Sampel media yang disediakan oleh alokator ini akan menampung pointer ke permukaan Direct3D. EVR mengambil pointer ke permukaan dengan memanggil IMFGetService::GetService pada sampel media. Pengidentifikasi layanan MR_BUFFER_SERVICE.

Untuk menyediakan alokator kustom, lakukan langkah-langkah berikut:

  1. Tentukan kelas untuk sampel media. Kelas ini dapat berasal dari kelas CMediaSample . Di dalam kelas ini, lakukan hal berikut:
    • Simpan pointer ke permukaan Direct3D.
    • Terapkan antarmuka IMFGetService . Dalam metode GetService , jika GUID layanan MR_BUFFER_SERVICE, kueri permukaan Direct3D untuk antarmuka yang diminta. Jika tidak, GetService dapat mengembalikan MF_E_UNSUPPORTED_SERVICE.
    • Ganti metode CMediaSample::GetPointer untuk mengembalikan E_NOTIMPL.
  2. Tentukan kelas untuk alokator. Alokator dapat berasal dari kelas CBaseAllocator . Di dalam kelas ini, lakukan hal berikut.
  3. Di pin output filter Anda, ganti metode CBaseOutputPin::InitAllocator . Di dalam metode ini, buat instans alokator kustom Anda.
  4. Di filter Anda, terapkan metode CTransformFilter::D ecideBufferSize . Parameter pProperties menunjukkan jumlah permukaan yang dibutuhkan EVR. Tambahkan ke nilai ini jumlah permukaan yang diperlukan dekoder Anda, dan panggil IMemAllocator::SetProperties pada alokator.

Kode berikut menunjukkan cara mengimplementasikan kelas sampel media:

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;
};

Kode berikut menunjukkan cara mengimplementasikan metode Alokasi pada alokator.

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;
}

Berikut adalah kode untuk metode Gratis :

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;
}

Untuk informasi selengkapnya tentang menerapkan alokator kustom, lihat topik Menyediakan Alokator Kustom dalam dokumentasi DirectShow SDK.

Decoding

Untuk membuat perangkat dekoder, panggil IDirectXVideoDecoderService::CreateVideoDecoder. Metode mengembalikan penunjuk ke antarmuka IDirectXVideoDecoder dari perangkat dekoder.

Pada setiap bingkai, panggil IDirect3DDeviceManager9::TestDevice untuk menguji handel perangkat. Jika perangkat telah berubah, metode mengembalikan DXVA2_E_NEW_VIDEO_DEVICE. Jika ini terjadi, lakukan hal berikut:

  1. Tutup handel perangkat dengan memanggil IDirect3DDeviceManager9::CloseDeviceHandle.
  2. Lepaskan pointer IDirectXVideoDecoderService dan IDirectXVideoDecoder .
  3. Buka handel perangkat baru.
  4. Negosiasikan konfigurasi dekoder baru, seperti yang dijelaskan di bagian Menemukan Konfigurasi Decoder.
  5. Buat perangkat dekoder baru.

Dengan asumsi bahwa handel perangkat valid, proses pendekodean berfungsi sebagai berikut:

  1. Panggil IDirectXVideoDecoder::BeginFrame.
  2. Lakukan hal berikut ini satu atau beberapa kali:
    1. Panggil IDirectXVideoDecoder::GetBuffer untuk mendapatkan buffer decoder DXVA.
    2. Isi buffer.
    3. Panggil IDirectXVideoDecoder::ReleaseBuffer.
  3. Panggil IDirectXVideoDecoder::Execute untuk melakukan operasi decoding pada bingkai.

DXVA 2.0 menggunakan struktur data yang sama dengan DXVA 1.0 untuk operasi decoding. Untuk kumpulan profil DXVA asli (untuk H.261, H.263, dan MPEG-2), struktur data ini dijelaskan dalam spesifikasi DXVA 1.0.

Dalam setiap pasangan panggilan BeginFrame/Execute , Anda dapat memanggil GetBuffer beberapa kali, tetapi hanya sekali untuk setiap jenis buffer DXVA. Jika Anda menyebutnya dua kali dengan jenis buffer yang sama, Anda akan menimpa data.

Setelah memanggil Jalankan, panggil IMemInputPin::Receive untuk mengirimkan bingkai ke perender video, seperti halnya pendekodean perangkat lunak. Metode Terima bersifat asinkron; setelah kembali, dekoder dapat terus mendekode bingkai berikutnya. Driver tampilan mencegah perintah pendekodean menimpa buffer saat buffer sedang digunakan. Dekoder tidak boleh menggunakan kembali permukaan untuk mendekode bingkai lain sampai perender telah merilis sampel. Ketika perender merilis sampel, alokator menempatkan sampel kembali ke kumpulan sampel yang tersedia. Untuk mendapatkan sampel berikutnya yang tersedia, panggil CBaseOutputPin::GetDeliveryBuffer, yang pada gilirannya memanggil IMemAllocator::GetBuffer. Untuk informasi selengkapnya, lihat topik Gambaran Umum Aliran Data di DirectShow dalam dokumentasi DirectShow.

Akselerasi Video DirectX 2.0