Supporto di DXVA 2.0 in DirectShow

Questo argomento descrive come supportare DirectX Video Acceleration (DXVA) 2.0 in un filtro decodificatore DirectShow. In particolare, descrive la comunicazione tra il decodificatore e il renderer video. Questo argomento non descrive come implementare la decodifica DXVA.

Prerequisiti

In questo argomento si presuppone che si abbia familiarità con la scrittura di filtri DirectShow. Per altre informazioni, vedere l'argomento Scrittura di filtri DirectShow nella documentazione di DirectShow SDK. Gli esempi di codice in questo argomento presuppongono che il filtro decodificatore sia derivato dalla classe CTransformFilter , con la definizione di classe seguente:

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

Nel resto di questo argomento il termine decodificatore fa riferimento al filtro decodificatore , che riceve video compressi e restituisce video non compressi. Il termine dispositivo decodificatore fa riferimento a un acceleratore video hardware implementato dal driver grafico.

Ecco i passaggi di base che un filtro decodificatore deve eseguire per supportare DXVA 2.0:

  1. Negoziare un tipo di supporto.
  2. Trovare una configurazione del decodificatore DXVA.
  3. Notifica al renderer video che il decodificatore usa la decodifica DXVA.
  4. Specificare un allocatore personalizzato che alloca le superfici Direct3D.

Questi passaggi sono descritti in modo più dettagliato nella parte restante di questo argomento.

Note sulla migrazione

Se si esegue la migrazione da DXVA 1.0, è necessario tenere presente alcune differenze significative tra le due versioni:

  • DXVA 2.0 non usa le interfacce IAMVideoAccelerator e IAMVideoAcceleratorNotify, perché il decodificatore può accedere alle API DXVA 2.0 direttamente tramite l'interfaccia IDirectXVideoDecoder.
  • Durante la negoziazione dei tipi di supporti, il decodificatore non usa un GUID di accelerazione video come sottotipo. Il sottotipo è invece solo il formato video non compresso (ad esempio NV12), come con la decodifica software.
  • La procedura per la configurazione dell'acceleratore è stata modificata. In DXVA 1.0 il decodificatore chiama Execute con una struttura DXVA_ConfigPictureDecode per configurare l'accerlator. In DXVA 2.0 il decodificatore usa l'interfaccia IDirectXVideoDecoderService , come descritto nella sezione successiva.
  • Il decodificatore alloca i buffer non compressi. Il renderer video non li alloca più.
  • Anziché chiamare IAMVideoAccelerator::D isplayFrame per visualizzare la cornice decodificata, il decodificatore recapita il frame al renderer chiamando IMemInputPin::Receive, come con la decodifica software.
  • Il decodificatore non è più responsabile del controllo quando i buffer di dati sono sicuri per gli aggiornamenti. Pertanto DXVA 2.0 non ha alcun metodo equivalente a IAMVideoAccelerator::QueryRenderStatus.
  • La fusione di sottopicture viene eseguita dal renderer video usando le API del processore video DXVA2.0. I decodificatori che forniscono sottopicture (ad esempio, decodificatori DVD) devono inviare dati di sottopicture in un pin di output separato.

Per le operazioni di decodifica, DXVA 2.0 usa le stesse strutture di dati di DXVA 1.0.

Il filtro EVR (Enhanced Video Renderer) supporta DXVA 2.0. I filtri del renderer di mix video (VMR-7 e VMR-9) supportano solo DXVA 1.0.

Ricerca di una configurazione del decodificatore

Dopo che il decodificatore negozia il tipo di supporto di output, deve trovare una configurazione compatibile per il dispositivo decodificatore DXVA. È possibile eseguire questo passaggio all'interno del metodo CBaseOutputPin::CompleteConnect del pin di output. Questo passaggio garantisce che il driver grafico supporti le funzionalità necessarie dal decodificatore, prima del commit del decodificatore all'uso di DXVA.

Per trovare una configurazione per il dispositivo decodificatore, eseguire le operazioni seguenti:

  1. Eseguire una query sul pin di input del renderer per l'interfaccia IMFGetService .

  2. Chiamare FMIGetService::GetService per ottenere un puntatore all'interfaccia IDirect3DDeviceManager9 . Il GUID del servizio è MR_VIDEO_ACCELERATION_SERVICE.

  3. Chiamare IDirect3DDeviceManager9::OpenDeviceHandle per ottenere un handle nel dispositivo Direct3D del renderer.

  4. Chiamare IDirect3DDeviceManager9::GetVideoService e passare l'handle del dispositivo. Questo metodo restituisce un puntatore all'interfaccia IDirectXVideoDecoderService .

  5. Chiamare IDirectXVideoDecoderService::GetDecoderDeviceGuids. Questo metodo restituisce una matrice di GUID del dispositivo decodificatore.

  6. Eseguire il ciclo attraverso la matrice di GUID del decodificatore per trovare quelli supportati dal filtro del decodificatore. Ad esempio, per un decodificatore MPEG-2, cercare DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT o DXVA2_ModeMPEG2_VLD.

  7. Quando si trova un GUID del dispositivo decodificatore candidato, passare il GUID al metodo IDirectXVideoDecoderService::GetDecoderRenderTargets . Questo metodo restituisce una matrice di formati di destinazione di rendering, specificati come valori D3DFORMAT .

  8. Eseguire il ciclo attraverso i formati di destinazione di rendering e cercare uno corrispondente al formato di output. In genere, un dispositivo decodificatore supporta un singolo formato di destinazione di rendering. Il filtro decodificatore deve connettersi al renderer usando questo sottotipo. Nella prima chiamata a CompleteConnect il decodificatore può determizzare il formato di destinazione del rendering e quindi restituire questo formato come tipo di output preferito.

  9. Chiamare IDirectXVideoDecoderService::GetDecoderConfigurations. Passare lo stesso GUID del dispositivo decodificatore, insieme a una struttura DXVA2_VideoDesc che descrive il formato proposto. Il metodo restituisce una matrice di strutture DXVA2_ConfigPictureDecode . Ogni struttura descrive una possibile configurazione per il dispositivo decodificatore.

  10. Supponendo che i passaggi precedenti siano riusciti, archiviare l'handle del dispositivo Direct3D, il GUID del dispositivo decodificatore e la struttura di configurazione. Il filtro userà queste informazioni per creare il dispositivo decodificatore.

Il codice seguente illustra come trovare una configurazione del decodificatore.

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

Poiché questo esempio è generico, alcune delle funzioni helper sono state inserite nelle funzioni helper che devono essere implementate dal decodificatore. Il codice seguente mostra le dichiarazioni per queste funzioni:

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

Notifica al renderer video

Se il decodificatore trova una configurazione del decodificatore, il passaggio successivo consiste nel notificare al renderer video che il decodificatore userà l'accelerazione hardware. È possibile eseguire questo passaggio all'interno del metodo CompleteConnect . Questo passaggio deve verificarsi prima che venga selezionato l'allocatore, perché influisce sulla modalità di selezione dell'allocatore.

  1. Eseguire una query sul pin di input del renderer per l'interfaccia IMFGetService .
  2. Chiamare IMFGetService::GetService per ottenere un puntatore all'interfaccia IDirectXVideoMemoryConfiguration . Il GUID del servizio è MR_VIDEO_ACCELERATION_SERVICE.
  3. Chiamare IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex in un ciclo, incrementando la variabile dwTypeIndex da zero. Arresta quando il metodo restituisce il valore DXVA2_SurfaceType_DecoderRenderTarget nel parametro pdwType . Questo passaggio garantisce che il renderer video supporti la decodifica accelerata hardware. Questo passaggio avrà sempre esito positivo per il filtro EVR.
  4. Se il passaggio precedente ha avuto esito positivo, chiamare IDirectXVideoMemoryConfiguration::SetSurfaceType con il valore DXVA2_SurfaceType_DecoderRenderTarget. La chiamata a SetSurfaceType con questo valore inserisce il renderer video in modalità DXVA. Quando il renderer video si trova in questa modalità, il decodificatore deve fornire un proprio allocatore.

Il codice seguente illustra come inviare una notifica al renderer 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;
}

Se il decodificatore trova una configurazione valida e notifica correttamente il renderer video, il decodificatore può usare DXVA per decodificare. Il decodificatore deve implementare un allocatore personalizzato per il pin di output, come descritto nella sezione successiva.

Allocazione di buffer non compressi

In DXVA 2.0 il decodificatore è responsabile dell'allocazione delle superfici Direct3D da usare come buffer video non compressi. Pertanto, il decodificatore deve implementare un allocatore personalizzato che creerà le superfici. Gli esempi multimediali forniti da questo allocatore conterranno puntatori alle superfici Direct3D. EVR recupera un puntatore alla superficie chiamando FMGetService::GetService nell'esempio multimediale. L'identificatore del servizio è MR_BUFFER_SERVICE.

Per fornire l'allocatore personalizzato, seguire questa procedura:

  1. Definire una classe per gli esempi multimediali. Questa classe può derivare dalla classe CMediaSample . All'interno di questa classe, eseguire le operazioni seguenti:
    • Archiviare un puntatore alla superficie Direct3D.
    • Implementare l'interfaccia IMFGetService . Nel metodo GetService , se il GUID del servizio è MR_BUFFER_SERVICE, eseguire una query sulla superficie Direct3D per l'interfaccia richiesta. In caso contrario, GetService può restituire MF_E_UNSUPPORTED_SERVICE.
    • Eseguire l'override del metodo CMediaSample::GetPointer per restituire E_NOTIMPL.
  2. Definire una classe per l'allocatore. L'allocatore può derivare dalla classe CBaseAllocator . All'interno di questa classe, eseguire le operazioni seguenti.
  3. Nel pin di output del filtro eseguire l'override del metodo CBaseOutputPin::InitAllocator . All'interno di questo metodo creare un'istanza dell'allocatore personalizzato.
  4. Nel filtro implementare il metodo CTransformFilter::D ecideBufferSize . Il parametro pProperties indica il numero di superfici richieste dall'EVR. Aggiungere a questo valore il numero di superfici richieste dal decodificatore e chiamare IMemAllocator::SetProperties nell'allocatore.

Il codice seguente illustra come implementare la classe di esempio multimediale:

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

Nel codice seguente viene illustrato come implementare il metodo Alloc nell'allocatore.

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

Ecco il codice per il metodo 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;
}

Per altre informazioni sull'implementazione di allocatori personalizzati, vedere l'argomento Fornire un allocatore personalizzato nella documentazione di DirectShow SDK.

Decodifica

Per creare il dispositivo decodificatore, chiama IDirectXVideoDecoderService::CreateVideoDecoder. Il metodo restituisce un puntatore all'interfaccia IDirectXVideoDecoder del dispositivo decodificatore.

In ogni frame chiamare IDirect3DDeviceManager9::TestDevice per testare l'handle del dispositivo. Se il dispositivo è stato modificato, il metodo restituisce DXVA2_E_NEW_VIDEO_DEVICE. In questo caso, eseguire le operazioni seguenti:

  1. Chiudere l'handle del dispositivo chiamando IDirect3DDeviceManager9::CloseDeviceHandle.
  2. Rilasciare i puntatori IDirectXVideoDecoderService e IDirectXVideoDecoder .
  3. Aprire un nuovo handle del dispositivo.
  4. Negoziare una nuova configurazione del decodificatore, come descritto nella sezione Ricerca di una configurazione del decodificatore.
  5. Creare un nuovo dispositivo decodificatore.

Supponendo che l'handle del dispositivo sia valido, il processo di decodifica funziona come segue:

  1. Chiama IDirectXVideoDecoder::BeginFrame.
  2. Eseguire le operazioni seguenti una o più volte:
    1. Chiama IDirectXVideoDecoder::GetBuffer per ottenere un buffer del decodificatore DXVA.
    2. Riempire il buffer.
    3. Chiama IDirectXVideoDecoder::ReleaseBuffer.
  3. Chiamare IDirectXVideoDecoder::Execute per eseguire le operazioni di decodifica nel frame.

DXVA 2.0 usa le stesse strutture di dati di DXVA 1.0 per le operazioni di decodifica. Per il set originale di profili DXVA (per H.261, H.263 e MPEG-2), queste strutture di dati sono descritte nella specifica DXVA 1.0.

All'interno di ogni coppia di chiamate BeginFrame/Execute è possibile chiamare GetBuffer più volte, ma una sola volta per ogni tipo di buffer DXVA. Se la si chiama due volte con lo stesso tipo di buffer, si sovrascriveranno i dati.

Dopo aver chiamato Execute, chiama IMemInputPin::Receive per recapitare il fotogramma al renderer video, come per la decodifica software. Il metodo Receive è asincrono; dopo la restituzione, il decodificatore può continuare a decodificare il frame successivo. Il driver di visualizzazione impedisce a qualsiasi comando di decodifica di sovrascrivere il buffer mentre il buffer è in uso. Il decodificatore non deve riutilizzare una superficie per decodificare un altro frame finché il renderer non ha rilasciato l'esempio. Quando il renderer rilascia l'esempio, l'allocatore inserisce nuovamente l'esempio nel pool di campioni disponibili. Per ottenere l'esempio disponibile successivo, chiamare CBaseOutputPin::GetDeliveryBuffer, che a sua volta chiama IMemAllocator::GetBuffer. Per altre informazioni, vedere l'argomento Panoramica di Flusso di dati in DirectShow nella documentazione di DirectShow.

Accelerazione video DirectX 2.0