Prise en charge de DXVA 2.0 dans DirectShow

Cette rubrique explique comment prendre en charge DirectX Video Acceleration (DXVA) 2.0 dans un filtre de décodeur DirectShow. Plus précisément, il décrit la communication entre le décodeur et le convertisseur vidéo. Cette rubrique ne décrit pas comment implémenter le décodage DXVA.

Prérequis

Cette rubrique suppose que vous êtes familiarisé avec l’écriture de filtres DirectShow. Pour plus d’informations, consultez la rubrique Écriture de filtres DirectShow dans la documentation du Kit de développement logiciel (SDK) DirectShow. Les exemples de code de cette rubrique supposent que le filtre de décodeur est dérivé de la classe CTransformFilter , avec la définition de classe suivante :

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

Dans le reste de cette rubrique, le terme décodeur fait référence au filtre de décodeur, qui reçoit la vidéo compressée et génère de la vidéo non compressée. Le terme périphérique de décodeur fait référence à un accélérateur vidéo matériel implémenté par le pilote graphique.

Voici les étapes de base qu’un filtre de décodeur doit effectuer pour prendre en charge DXVA 2.0 :

  1. Négocier un type de média.
  2. Recherchez une configuration de décodeur DXVA.
  3. Informez le convertisseur vidéo que le décodeur utilise le décodage DXVA.
  4. Fournissez un répartiteur personnalisé qui alloue des surfaces Direct3D.

Ces étapes sont décrites plus en détail dans le reste de cette rubrique.

Migration Notes

Si vous effectuez une migration à partir de DXVA 1.0, vous devez connaître certaines différences significatives entre les deux versions :

  • DXVA 2.0 n’utilise pas les interfaces IAMVideoAccelerator et IAMVideoAcceleratorNotify , car le décodeur peut accéder aux API DXVA 2.0 directement via l’interface IDirectXVideoDecoder .
  • Pendant la négociation du type multimédia, le décodeur n’utilise pas de GUID d’accélération vidéo comme sous-type. Au lieu de cela, le sous-type est simplement le format vidéo non compressé (tel que NV12), comme avec le décodage logiciel.
  • La procédure de configuration de l’accélérateur a changé. Dans DXVA 1.0, le décodeur appelle Execute avec une structure DXVA_ConfigPictureDecode pour configurer l’accélérateur. Dans DXVA 2.0, le décodeur utilise l’interface IDirectXVideoDecoderService , comme décrit dans la section suivante.
  • Le décodeur alloue les mémoires tampons non compressées. Le convertisseur vidéo ne les alloue plus.
  • Au lieu d’appeler IAMVideoAccelerator::D isplayFrame pour afficher l’image décodée, le décodeur remet l’image au convertisseur en appelant IMemInputPin::Receive, comme avec le décodage logiciel.
  • Le décodeur n’est plus responsable de vérifier si les mémoires tampons de données sont sécurisées pour les mises à jour. Par conséquent, DXVA 2.0 n’a pas de méthode équivalente à IAMVideoAccelerator::QueryRenderStatus.
  • Le mélange de sous-images est effectué par le convertisseur vidéo, à l’aide des API du processeur vidéo DXVA2.0. Les décodeurs qui fournissent des sous-images (par exemple, les décodeurs DVD) doivent envoyer des données de sous-image sur une broche de sortie distincte.

Pour les opérations de décodage, DXVA 2.0 utilise les mêmes structures de données que DXVA 1.0.

Le filtre de convertisseur vidéo amélioré (EVR) prend en charge DXVA 2.0. Les filtres du convertisseur de mixage vidéo (VMR-7 et VMR-9) prennent uniquement en charge DXVA 1.0.

Recherche d’une configuration de décodeur

Une fois que le décodeur a négocié le type de média de sortie, il doit trouver une configuration compatible pour le périphérique décodeur DXVA. Vous pouvez effectuer cette étape à l’intérieur de la méthode CBaseOutputPin::CompleteConnect de la broche de sortie. Cette étape garantit que le pilote graphique prend en charge les fonctionnalités nécessaires au décodeur, avant que le décodeur ne valide l’utilisation de DXVA.

Pour trouver une configuration pour l’appareil de décodeur, procédez comme suit :

  1. Interrogez la broche d’entrée du convertisseur pour l’interface IMFGetService .

  2. Appelez IMFGetService::GetService pour obtenir un pointeur vers l’interface IDirect3DDeviceManager9 . Le GUID de service est MR_VIDEO_ACCELERATION_SERVICE.

  3. Appelez IDirect3DDeviceManager9::OpenDeviceHandle pour obtenir un handle sur l’appareil Direct3D du convertisseur.

  4. Appelez IDirect3DDeviceManager9::GetVideoService et passez le handle de l’appareil. Cette méthode retourne un pointeur vers l’interface IDirectXVideoDecoderService .

  5. Appelez IDirectXVideoDecoderService::GetDecoderDeviceGuids. Cette méthode retourne un tableau de GUID d’appareil de décodeur.

  6. Effectuez une boucle dans le tableau des GUID du décodeur pour rechercher ceux que le filtre de décodeur prend en charge. Par exemple, pour un décodeur MPEG-2, vous recherchez DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT ou DXVA2_ModeMPEG2_VLD.

  7. Lorsque vous trouvez un GUID d’appareil de décodeur candidat, passez le GUID à la méthode IDirectXVideoDecoderService::GetDecoderRenderTargets . Cette méthode retourne un tableau de formats cibles de rendu, spécifiés sous forme de valeurs D3DFORMAT .

  8. Effectuez une boucle dans les formats cibles de rendu et recherchez-en un qui correspond à votre format de sortie. En règle générale, un appareil de décodeur prend en charge un format cible de rendu unique. Le filtre de décodeur doit se connecter au convertisseur à l’aide de ce sous-type. Dans le premier appel à CompleteConnect, le décodeur peut déterminer le format cible de rendu, puis renvoyer ce format en tant que type de sortie préféré.

  9. Appelez IDirectXVideoDecoderService::GetDecoderConfigurations. Transmettez le même GUID d’appareil de décodeur, ainsi qu’une structure DXVA2_VideoDesc qui décrit le format proposé. La méthode retourne un tableau de structures DXVA2_ConfigPictureDecode . Chaque structure décrit une configuration possible pour l’appareil de décodeur.

  10. En supposant que les étapes précédentes réussissent, stockez le handle d’appareil Direct3D, le GUID de l’appareil décodeur et la structure de configuration. Le filtre utilise ces informations pour créer l’appareil de décodeur.

Le code suivant montre comment rechercher une configuration de décodeur.

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

Étant donné que cet exemple est générique, une partie de la logique a été placée dans des fonctions d’assistance qui doivent être implémentées par le décodeur. Le code suivant montre les déclarations pour ces fonctions :

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

Notification du convertisseur vidéo

Si le décodeur trouve une configuration de décodeur, l’étape suivante consiste à informer le convertisseur vidéo que le décodeur utilisera l’accélération matérielle. Vous pouvez effectuer cette étape à l’intérieur de la méthode CompleteConnect . Cette étape doit se produire avant que l’allocator soit sélectionné, car elle affecte la façon dont l’allocator est sélectionné.

  1. Interrogez la broche d’entrée du convertisseur pour l’interface IMFGetService .
  2. Appelez IMFGetService::GetService pour obtenir un pointeur vers l’interface IDirectXVideoMemoryConfiguration . Le GUID de service est MR_VIDEO_ACCELERATION_SERVICE.
  3. Appelez IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex dans une boucle, incrémentant la variable dwTypeIndex à partir de zéro. Arrêtez lorsque la méthode retourne la valeur DXVA2_SurfaceType_DecoderRenderTarget dans le paramètre pdwType . Cette étape garantit que le convertisseur vidéo prend en charge le décodage accéléré par le matériel. Cette étape réussit toujours pour le filtre EVR.
  4. Si l’étape précédente a réussi, appelez IDirectXVideoMemoryConfiguration::SetSurfaceType avec la valeur DXVA2_SurfaceType_DecoderRenderTarget. L’appel de SetSurfaceType avec cette valeur place le convertisseur vidéo en mode DXVA. Lorsque le convertisseur vidéo est dans ce mode, le décodeur doit fournir son propre allocateur.

Le code suivant montre comment notifier le convertisseur vidéo.

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

Si le décodeur trouve une configuration valide et avertit correctement le convertisseur vidéo, le décodeur peut utiliser DXVA pour le décodage. Le décodeur doit implémenter un allocateur personnalisé pour sa broche de sortie, comme décrit dans la section suivante.

Allocation de mémoires tampons non compressées

Dans DXVA 2.0, le décodeur est responsable de l’allocation des surfaces Direct3D à utiliser comme tampons vidéo non compressés. Par conséquent, le décodeur doit implémenter un outil d’allocation personnalisé qui créera les surfaces. Les exemples multimédias fournis par cet allocateur contiennent des pointeurs vers les surfaces Direct3D. L’EVR récupère un pointeur vers la surface en appelant IMFGetService::GetService sur l’exemple multimédia. L’identificateur de service est MR_BUFFER_SERVICE.

Pour fournir l’allocateur personnalisé, effectuez les étapes suivantes :

  1. Définissez une classe pour les exemples multimédias. Cette classe peut dériver de la classe CMediaSample . Dans cette classe, procédez comme suit :
    • Stockez un pointeur vers la surface Direct3D.
    • Implémentez l’interface IMFGetService . Dans la méthode GetService , si le GUID de service est MR_BUFFER_SERVICE, interrogez la surface Direct3D pour l’interface demandée. Sinon, GetService peut retourner MF_E_UNSUPPORTED_SERVICE.
    • Remplacez la méthode CMediaSample::GetPointer pour retourner E_NOTIMPL.
  2. Définissez une classe pour l’allocateur. L’allocateur peut dériver de la classe CBaseAllocator . Dans cette classe, procédez comme suit.
  3. Dans le code de sortie de votre filtre, remplacez la méthode CBaseOutputPin::InitAllocator . À l’intérieur de cette méthode, créez un instance de votre allocateur personnalisé.
  4. Dans votre filtre, implémentez la méthode CTransformFilter::D ecideBufferSize . Le paramètre pProperties indique le nombre de surfaces requis par l’EVR. Ajoutez à cette valeur le nombre de surfaces requises par votre décodeur et appelez IMemAllocator::SetProperties sur l’allocateur.

Le code suivant montre comment implémenter l’exemple de classe multimé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;
};

Le code suivant montre comment implémenter la méthode Alloc sur l’allocateur.

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

Voici le code de la méthode 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;
}

Pour plus d’informations sur l’implémentation d’allocateurs personnalisés, consultez la rubrique Fournir un allocateur personnalisé dans la documentation du Kit de développement logiciel (SDK) DirectShow.

Décodage

Pour créer l’appareil de décodeur, appelez IDirectXVideoDecoderService::CreateVideoDecoder. La méthode retourne un pointeur vers l’interface IDirectXVideoDecoder du périphérique de décodeur.

Sur chaque image, appelez IDirect3DDeviceManager9::TestDevice pour tester le handle d’appareil. Si l’appareil a changé, la méthode retourne DXVA2_E_NEW_VIDEO_DEVICE. Si cela se produit, procédez comme suit :

  1. Fermez le handle d’appareil en appelant IDirect3DDeviceManager9::CloseDeviceHandle.
  2. Relâchez les pointeurs IDirectXVideoDecoderService et IDirectXVideoDecoder .
  3. Ouvrez un nouveau handle d’appareil.
  4. Négociez une nouvelle configuration de décodeur, comme décrit dans la section Recherche d’une configuration de décodeur.
  5. Créez un appareil de décodeur.

En supposant que le handle d’appareil est valide, le processus de décodage fonctionne comme suit :

  1. Appelez IDirectXVideoDecoder::BeginFrame.
  2. Effectuez les opérations suivantes une ou plusieurs fois :
    1. Appelez IDirectXVideoDecoder::GetBuffer pour obtenir une mémoire tampon de décodeur DXVA.
    2. Remplissez la mémoire tampon.
    3. Appelez IDirectXVideoDecoder::ReleaseBuffer.
  3. Appelez IDirectXVideoDecoder::Execute pour effectuer les opérations de décodage sur le frame.

DXVA 2.0 utilise les mêmes structures de données que DXVA 1.0 pour les opérations de décodage. Pour l’ensemble d’origine de profils DXVA (pour H.261, H.263 et MPEG-2), ces structures de données sont décrites dans la spécification DXVA 1.0.

Dans chaque paire d’appels BeginFrame/Execute , vous pouvez appeler GetBuffer plusieurs fois, mais une seule fois pour chaque type de mémoire tampon DXVA. Si vous l’appelez deux fois avec le même type de mémoire tampon, vous remplacerez les données.

Après avoir appelé Execute, appelez IMemInputPin::Receive pour remettre l’image au convertisseur vidéo, comme avec le décodage logiciel. La méthode Receive est asynchrone ; une fois qu’il est retourné, le décodeur peut continuer à décoder l’image suivante. Le pilote d’affichage empêche les commandes de décodage de remplacer la mémoire tampon pendant l’utilisation de la mémoire tampon. Le décodeur ne doit pas réutiliser une surface pour décoder une autre image tant que le convertisseur n’a pas libéré l’exemple. Lorsque le convertisseur libère l’exemple, l’allocateur le replace dans son pool d’exemples disponibles. Pour obtenir l’exemple disponible suivant, appelez CBaseOutputPin::GetDeliveryBuffer, qui à son tour appelle IMemAllocator::GetBuffer. Pour plus d’informations, consultez la rubrique Vue d’ensemble de Data Flow dans DirectShow dans la documentation DirectShow.

Accélération vidéo DirectX 2.0