Suporte ao DXVA 2.0 no DirectShow

Este tópico descreve como dar suporte à Aceleração de Vídeo DirectX (DXVA) 2.0 em um filtro de decodificador DirectShow. Especificamente, ele descreve a comunicação entre o decodificador e o renderizador de vídeo. Este tópico não descreve como implementar a decodificação DXVA.

Pré-requisitos

Este tópico pressupõe que você esteja familiarizado com a gravação de filtros do DirectShow. Para obter mais informações, consulte o tópico Escrevendo filtros do DirectShow na documentação do SDK do DirectShow. Os exemplos de código neste tópico pressupõem que o filtro de decodificador é derivado da classe CTransformFilter , com a seguinte definição de classe:

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

No restante deste tópico, o termo decodificador refere-se ao filtro de decodificador, que recebe vídeo compactado e gera vídeo descompactado. O termo dispositivo de decodificador refere-se a um acelerador de vídeo de hardware implementado pelo driver gráfico.

Estas são as etapas básicas que um filtro de decodificador deve executar para dar suporte ao DXVA 2.0:

  1. Negociar um tipo de mídia.
  2. Localize uma configuração de decodificador DXVA.
  3. Notifique o renderizador de vídeo de que o decodificador está usando a decodificação DXVA.
  4. Forneça um alocador personalizado que aloca superfícies Direct3D.

Essas etapas são descritas mais detalhadamente no restante deste tópico.

Notas de migração

Se você estiver migrando do DXVA 1.0, deverá estar ciente de algumas diferenças significativas entre as duas versões:

  • O DXVA 2.0 não usa as interfaces IAMVideoAccelerator e IAMVideoAcceleratorNotify , pois o decodificador pode acessar as APIs DXVA 2.0 diretamente por meio da interface IDirectXVideoDecoder .
  • Durante a negociação de tipo de mídia, o decodificador não usa um GUID de aceleração de vídeo como o subtipo. Em vez disso, o subtipo é apenas o formato de vídeo descompactado (como NV12), como com a decodificação de software.
  • O procedimento para configurar o acelerador foi alterado. No DXVA 1.0, o decodificador chama Execute com uma estrutura DXVA_ConfigPictureDecode para configurar o accerlator. No DXVA 2.0, o decodificador usa a interface IDirectXVideoDecoderService , conforme descrito na próxima seção.
  • O decodificador aloca os buffers descompactados. O renderizador de vídeo não os aloca mais.
  • Em vez de chamar IAMVideoAccelerator::D isplayFrame para exibir o quadro decodificado, o decodificador entrega o quadro ao renderizador chamando IMemInputPin::Receive, como com a decodificação de software.
  • O decodificador não é mais responsável por verificar quando os buffers de dados são seguros para atualizações. Portanto, a DXVA 2.0 não tem nenhum método equivalente a IAMVideoAccelerator::QueryRenderStatus.
  • A mesclagem de subpictura é feita pelo renderizador de vídeo, usando as APIs do processador de vídeo DXVA2.0. Os decodificadores que fornecem subpicturas (por exemplo, decodificadores de DVD) devem enviar dados de subpictura em um pin de saída separado.

Para operações de decodificação, a DXVA 2.0 usa as mesmas estruturas de dados que a DXVA 1.0.

O filtro EVR (renderizador de vídeo avançado) dá suporte à DXVA 2.0. Os filtros do Renderizador de Combinação de Vídeo (VMR-7 e VMR-9) dão suporte apenas à DXVA 1.0.

Localizando uma configuração do decodificador

Depois que o decodificador negocia o tipo de mídia de saída, ele deve encontrar uma configuração compatível para o dispositivo de decodificador DXVA. Você pode executar essa etapa dentro do método CBaseOutputPin::CompleteConnect do pino de saída. Essa etapa garante que o driver de gráficos dê suporte aos recursos necessários para o decodificador, antes que o decodificador se confirme usando DXVA.

Para localizar uma configuração para o dispositivo decodificador, faça o seguinte:

  1. Consulte o pin de entrada do renderizador para a interface IMFGetService .

  2. Chame IMFGetService::GetService para obter um ponteiro para a interface IDirect3DDeviceManager9 . O GUID do serviço é MR_VIDEO_ACCELERATION_SERVICE.

  3. Chame IDirect3DDeviceManager9::OpenDeviceHandle para obter um identificador para o dispositivo Direct3D do renderizador.

  4. Chame IDirect3DDeviceManager9::GetVideoService e passe o identificador do dispositivo. Esse método retorna um ponteiro para a interface IDirectXVideoDecoderService .

  5. Chame IDirectXVideoDecoderService::GetDecoderDeviceGuids. Esse método retorna uma matriz de GUIDs de dispositivo de decodificador.

  6. Execute um loop pela matriz de GUIDs do decodificador para localizar os que o filtro de decodificador dá suporte. Por exemplo, para um decodificador MPEG-2, você procuraria DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT ou DXVA2_ModeMPEG2_VLD.

  7. Quando encontrar um GUID de dispositivo de decodificador candidato, passe o GUID para o método IDirectXVideoDecoderService::GetDecoderRenderTargets . Esse método retorna uma matriz de formatos de destino de renderização, especificados como valores D3DFORMAT .

  8. Execute um loop pelos formatos de destino de renderização e procure um que corresponda ao formato de saída. Normalmente, um dispositivo de decodificador dá suporte a um único formato de destino de renderização. O filtro de decodificador deve se conectar ao renderizador usando esse subtipo. Na primeira chamada para CompleteConnect, o decodificador pode determinar o formato de destino de renderização e retornar esse formato como um tipo de saída preferencial.

  9. Chame IDirectXVideoDecoderService::GetDecoderConfigurations. Passe o mesmo GUID do dispositivo de decodificador, juntamente com uma estrutura DXVA2_VideoDesc que descreve o formato proposto. O método retorna uma matriz de estruturas DXVA2_ConfigPictureDecode . Cada estrutura descreve uma configuração possível para o dispositivo decodificador.

  10. Supondo que as etapas anteriores sejam bem-sucedidas, armazene o identificador de dispositivo Direct3D, o GUID do dispositivo decodificador e a estrutura de configuração. O filtro usará essas informações para criar o dispositivo decodificador.

O código a seguir mostra como encontrar uma configuração de decodificador.

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

Como este exemplo é genérico, parte da lógica foi colocada em funções auxiliares que precisariam ser implementadas pelo decodificador. O código a seguir mostra as declarações para essas funções:

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

Notificando o renderizador de vídeo

Se o decodificador encontrar uma configuração de decodificador, a próxima etapa será notificar o renderizador de vídeo de que o decodificador usará a aceleração de hardware. Você pode executar essa etapa dentro do método CompleteConnect . Essa etapa deve ocorrer antes que o alocador seja selecionado, pois afeta a forma como o alocador é selecionado.

  1. Consulte o pin de entrada do renderizador para a interface IMFGetService .
  2. Chame IMFGetService::GetService para obter um ponteiro para a interface IDirectXVideoMemoryConfiguration . O GUID do serviço é MR_VIDEO_ACCELERATION_SERVICE.
  3. Chame IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex em um loop, incrementando a variável dwTypeIndex de zero. Pare quando o método retornar o valor DXVA2_SurfaceType_DecoderRenderTarget no parâmetro pdwType . Esta etapa garante que o renderizador de vídeo dê suporte à decodificação acelerada por hardware. Esta etapa sempre terá êxito para o filtro EVR.
  4. Se a etapa anterior tiver sido bem-sucedida, chame IDirectXVideoMemoryConfiguration::SetSurfaceType com o valor DXVA2_SurfaceType_DecoderRenderTarget. Chamar SetSurfaceType com esse valor coloca o renderizador de vídeo no modo DXVA. Quando o renderizador de vídeo está nesse modo, o decodificador deve fornecer seu próprio alocador.

O código a seguir mostra como notificar o renderizador de vídeo.

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 o decodificador encontrar uma configuração válida e notificar com êxito o renderizador de vídeo, o decodificador poderá usar DXVA para decodificação. O decodificador deve implementar um alocador personalizado para seu pino de saída, conforme descrito na próxima seção.

Alocando buffers descompactados

No DXVA 2.0, o decodificador é responsável por alocar superfícies Direct3D a serem usadas como buffers de vídeo descompactados. Portanto, o decodificador deve implementar um alocador personalizado que criará as superfícies. Os exemplos de mídia fornecidos por esse alocador conterão ponteiros para as superfícies direct3D. O EVR recupera um ponteiro para a superfície chamando IMFGetService::GetService no exemplo de mídia. O identificador de serviço é MR_BUFFER_SERVICE.

Para fornecer o alocador personalizado, execute as seguintes etapas:

  1. Defina uma classe para os exemplos de mídia. Essa classe pode derivar da classe CMediaSample . Dentro dessa classe, faça o seguinte:
    • Armazene um ponteiro para a superfície do Direct3D.
    • Implemente a interface IMFGetService . No método GetService , se o GUID de serviço for MR_BUFFER_SERVICE, consulte a superfície direct3D para obter a interface solicitada. Caso contrário, GetService poderá retornar MF_E_UNSUPPORTED_SERVICE.
    • Substitua o método CMediaSample::GetPointer para retornar E_NOTIMPL.
  2. Defina uma classe para o alocador. O alocador pode derivar da classe CBaseAllocator . Dentro dessa classe, faça o seguinte.
  3. No pin de saída do filtro, substitua o método CBaseOutputPin::InitAllocator . Dentro desse método, crie uma instância do alocador personalizado.
  4. No filtro, implemente o método CTransformFilter::D ecideBufferSize . O parâmetro pProperties indica o número de superfícies que o EVR requer. Adicione a esse valor o número de superfícies exigidas pelo decodificador e chame IMemAllocator::SetProperties no alocador.

O código a seguir mostra como implementar a classe de exemplo de mídia:

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

O código a seguir mostra como implementar o método Alloc no alocador.

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

Este é o código para o método 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;
}

Para obter mais informações sobre como implementar alocadores personalizados, consulte o tópico Fornecendo um alocador personalizado na documentação do SDK do DirectShow.

Decodificação

Para criar o dispositivo decodificador, chame IDirectXVideoDecoderService::CreateVideoDecoder. O método retorna um ponteiro para a interface IDirectXVideoDecoder do dispositivo decodificador.

Em cada quadro, chame IDirect3DDeviceManager9::TestDevice para testar o identificador do dispositivo. Se o dispositivo tiver sido alterado, o método retornará DXVA2_E_NEW_VIDEO_DEVICE. Se isso ocorrer, faça o seguinte:

  1. Feche o identificador do dispositivo chamando IDirect3DDeviceManager9::CloseDeviceHandle.
  2. Libere os ponteiros IDirectXVideoDecoderService e IDirectXVideoDecoder .
  3. Abra um novo identificador de dispositivo.
  4. Negocie uma nova configuração de decodificador, conforme descrito na seção Localizando uma configuração de decodificador.
  5. Crie um novo dispositivo de decodificador.

Supondo que o identificador do dispositivo seja válido, o processo de decodificação funciona da seguinte maneira:

  1. Chame IDirectXVideoDecoder::BeginFrame.
  2. Faça o seguinte uma ou mais vezes:
    1. Chame IDirectXVideoDecoder::GetBuffer para obter um buffer de decodificador DXVA.
    2. Preencha o buffer.
    3. Chame IDirectXVideoDecoder::ReleaseBuffer.
  3. Chame IDirectXVideoDecoder::Execute para executar as operações de decodificação no quadro.

O DXVA 2.0 usa as mesmas estruturas de dados que a DXVA 1.0 para operações de decodificação. Para o conjunto original de perfis DXVA (para H.261, H.263 e MPEG-2), essas estruturas de dados são descritas na especificação DXVA 1.0.

Em cada par de chamadas BeginFrame/Execute , você pode chamar GetBuffer várias vezes, mas apenas uma vez para cada tipo de buffer DXVA. Se você chamá-lo duas vezes com o mesmo tipo de buffer, você substituirá os dados.

Depois de chamar Executar, chame IMemInputPin::Receive para entregar o quadro ao renderizador de vídeo, como com a decodificação de software. O método Receive é assíncrono; depois de retornar, o decodificador pode continuar decodificando o próximo quadro. O driver de exibição impede que comandos de decodificação substituam o buffer enquanto o buffer está em uso. O decodificador não deve reutilizar uma superfície para decodificar outro quadro até que o renderizador libere o exemplo. Quando o renderizador libera o exemplo, o alocador coloca o exemplo de volta em seu pool de amostras disponíveis. Para obter o próximo exemplo disponível, chame CBaseOutputPin::GetDeliveryBuffer, que, por sua vez, chama IMemAllocator::GetBuffer. Para obter mais informações, consulte o tópico Visão geral do Fluxo de Dados no DirectShow na documentação do DirectShow.

Aceleração de Vídeo Do DirectX 2.0