Share via


Prendre en charge le décodage vidéo Direct3D 11 dans Media Foundation

Cette rubrique explique comment prendre en charge Microsoft Direct3D 11 dans un décodeur Microsoft Media Foundation. Plus précisément, elle décrit la communication entre le décodeur et l’outil d’affichage vidéo. Cette rubrique ne décrit pas comment implémenter les opérations de décodage.

Vue d’ensemble

Dans la suite de cette rubrique, les termes suivants sont utilisés :

  • Décodeur logiciel. Le décodeur logiciel est la transformation Media Foundation (MFT) qui reçoit des échantillons vidéo compressés et génère des images vidéo décompressées.
  • Périphérique décodeur. Le périphérique décodeur est l’accélérateur vidéo, et il est implémenté par le pilote graphique. Le périphérique décodeur effectue des opérations de décodage accélérées.
  • Pipeline. Le pipeline héberge le décodeur logiciel et fournit des mémoires tampons vers et depuis le décodeur logiciel. En fonction de l’application, le pipeline peut être la session média, le lecteur source ou le code d’application qui appelle directement dans la MFT.

Pour effectuer un décodage avec Direct3D 11, le décodeur logiciel doit avoir un pointeur vers un périphérique Direct3D 11. Le périphérique Direct3D 11 est créé en externe vers le décodeur logiciel. Dans un scénario Session média, l’outil d’affichage vidéo crée le périphérique Direct3D 11. Dans un scénario Lecteur source, c’est généralement l’application qui crée le périphérique Direct3D 11.

Le Gestionnaire de périphériques DXGI est utilisé pour partager Direct3D 11 entre les composants. Le Gestionnaire de périphériques DXGI expose l’interface IMFDXGIDeviceManager. Le pipeline définit le pointeur IMFDXGIDeviceManager sur le décodeur logiciel en envoyant le message MFT_MESSAGE_SET_D3D_MANAGER.

Le diagramme suivant montre la relation entre le décodeur logiciel, Direct3D 11 et le pipeline.

a diagram that shows the software decoder and the dxgi device manager.

Voici les étapes de base qu’un décodeur logiciel doit effectuer pour prendre en charge Direct3D 11 dans Media Foundation :

  1. Ouvrir une poignée sur le périphérique Direct3D 11.
  2. Trouver une configuration de décodeur.
  3. Allouer des mémoires tampons décompressées.
  4. Décoder les trames.

Ces étapes sont décrites plus en détail dans la suite de cette rubrique.

Ouvrir une poignée de périphérique

Le décodeur MFT utilise le Gestionnaire de périphérique DXGI pour obtenir une poignée sur le périphérique Direct3D 11. Pour ouvrir la poignée de périphérique, procédez comme suit :

  1. Le décodeur MFT doit exposer l’attribut MF_SA_D3D11_AWARE avec la valeur TRUE.
  2. Le chargeur de topologie interroge cet attribut en appelant IMFTransform::GetAttributes. La valeur TRUE indique que la MFT prend en charge Direct3D 11.
  3. Le chargeur de topologie appelle IMFTransform::ProcessMessage avec le message MFT_MESSAGE_SET_D3D_MANAGER. Le paramètre ulParam est un pointeur IUnknown vers le gestionnaire de périphériques DXGI. Interrogez ce pointeur pour l’interface IMFDXGIDeviceManager.
  4. Appelez IMFDXGIDeviceManager::OpenDeviceHandle pour obtenir une poignée sur le périphérique Direct3D 11.
  5. Pour obtenir un pointeur vers le périphérique Direct3D 11, appelez IMFDXGIDeviceManager::GetVideoService. Transmettez la poignée de périphérique et la valeur IID_ID3D11Device. La méthode retourne un pointeur vers l’interface ID3D11Device.
  6. Pour obtenir un pointeur vers l’accélérateur vidéo, appelez IMFDXGIDeviceManager::GetVideoService à nouveau. Cette fois, transmettez la poignée de périphérique et la valeur IID_ID3D11VideoDevice. La méthode retourne un pointeur vers l’interface ID3D11VideoDevice.
  7. Appelez ID3D11Device::GetImmediateContext pour obtenir un pointeur ID3D11DeviceContext.
  8. Appelez QueryInterfacesur ID3D11DeviceContext pour obtenir un pointeur ID3D11VideoContext.
  9. Il est recommandé d’utiliser la protection multithread sur le contexte du périphérique pour éviter les problèmes de blocage qui peuvent parfois se produire lorsque vous appelez ID3D11VideoContext::GetDecoderBuffer ou ID3D11VideoContext::ReleaseDecoderBuffer. Pour définir la protection multithread, appelez d’abord QueryInterface sur ID3D11Device pour obtenir un pointeur ID3D10Multithread. Appelez ensuite ID3D10Multithread::SetMultithreadProtected, en transmettant true pour bMTProtect.

Trouver une configuration de décodeur

Pour effectuer le décodage, le décodeur logiciel doit trouver une configuration compatible prise en charge par le périphérique décodeur, y compris un format de cible d’affichage. Cette étape se déroule dans la méthode IMFTransform::SetInputType comme suit.

  1. Validez le type de média d’entrée. Si le type est rejeté, ignorez les étapes restantes et retournez un code d’erreur.
  2. Appelez ID3D11VideoDevice::GetVideoDecoderProfileCount pour obtenir le nombre de profils pris en charge.
  3. Appelez ID3D11VideoDevice::GetVideoDecoderProfile pour lister les profils et obtenir les GUID de profil.
  4. Recherchez un GUID de profil qui correspond au format vidéo et aux capacités du décodeur logiciel. Par exemple, un décodeur MPEG-2 recherchera D3D11_DECODER_PROFILE_MPEG2_MOCOMP,D3D11_DECODER_PROFILE_MPEG2_IDCT et D3D11_DECODER_PROFILE_MPEG2_VLD.
  5. Si un GUID de décodeur approprié est trouvé, vérifiez le format de sortie en appelant la méthode ID3D11VideoDevice::CheckVideoDecoderFormat. Transmettez le GUID du décodeur et une valeur DXGI_FORMAT qui spécifie le format de cible d’affichage.
  6. Ensuite, trouvez une configuration appropriée pour le décodeur.
    1. Appelez ID3D11VideoDevice::GetVideoDecoderConfigCount pour obtenir le nombre de configurations de décodeur. Transmettez le même GUID de périphérique décodeur, ainsi qu’une structure D3D11_VIDEO_DECODER_DESC qui décrit le format de cible d’affichage proposé.
    2. Appelez ID3D11VideoDevice::GetVideoDecoderConfig pour lister les configurations de décodeur.

Dans la méthode IMFTransform::GetOutputAvailableType , retournez un format vidéo décompressé en fonction du format de cible d’affichage proposé.

Dans la méthode IMFTransform::SetOutputType , vérifiez le type de média par rapport au format de cible d’affichage.

Revenir au décodage logiciel

La MFT peut ne pas trouver de configuration. Par exemple, le pilote graphique peut ne pas prendre en charge les fonctionnalités appropriées. Dans ce cas, la MFT doit revenir au décodage logiciel, comme suit.

  1. Les méthodes SetInputType et SetOutputType doivent toutes deux retourner MF_E_UNSUPPORTED_D3D_TYPE.
  2. En réponse, le chargeur de topologie envoie le message MFT_MESSAGE_SET_D3D_MANAGER avec la valeur NULL pour le paramètre ulParam.
  3. La MFT libère son pointeur vers l’interface IMFDXGIDeviceManager.
  4. Le chargeur de topologie renégocie le type de média.

À ce stade, la MFT peut utiliser le décodage logiciel.

Allocation de mémoires tampons décompressées

Le décodeur est chargé d’allouer des textures Direct3D 11 à utiliser comme mémoires tampons vidéo décompressées. L’attribut MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, dans les attributs de flux de sortie (voir IMFTransform::GetOutputStreamAttributes), est utilisé pour déterminer le nombre de surfaces que le décodeur doit allouer à l’outil d’affichage vidéo pour le désentrelacement. Un décodeur doit utiliser cette valeur en la bornant avec certaines limites supérieures et inférieures raisonnables, par exemple 3-32. Pour le contenu progressif, consultez MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE.

Dans la méthode IMFTransform::GetOutputStreamInfo, définissez l’indicateur MFT_OUTPUT_STREAM_PROVIDES_SAMPLES dans la structure MFT_OUTPUT_STREAM_INFO. Cet indicateur avertit la session média que la MFT alloue ses propres échantillons de sortie. Pour allouer les échantillons de sortie, la MFT suit ces étapes :

  1. Créez un groupe de textures 2D en appelant ID3D11Device::CreateTexture2D. Dans la structure D3D11_TEXTURE2D_DESC, définissez ArraySize sur le nombre de surfaces dont le décodeur a besoin. notamment :

    • Surfaces pour les trames de référence.
    • Surfaces pour la désentrelacement (trois surfaces).
    • Surfaces dont le décodeur a besoin pour la mise en mémoire tampon.

    Les indicateurs de liaison (BindFlags) doivent inclure l’indicateur D3D11_BIND_DECODER et tous les indicateurs de liaison définis via l’attribut MF_SA_D3D11_BINDFLAGS dans les attributs de flux de sortie.

  2. Pour chaque surface du groupe de textures, appelez ID3D11VideoDevice::CreateVideoDecoderOutputView pour créer une vue de sortie du décodeur vidéo. Pendant le décodage, ces vues de sortie sont transmises à la méthode ID3D11VideoContext::DecoderBeginFrame.

  3. Pour chaque surface du groupe de textures, créez un échantillon média comme suit :

    1. Créez une mémoire tampon média DXGI en appelant la fonction MFCreateDXGISurfaceBuffer. Transmettez le pointeur ID3D11Texture2D et le décalage pour chaque élément du groupe de textures. La fonction retourne un pointeur IMFMediaBuffer.
    2. Créez un échantillon média vide en appelant la fonction MFCreateVideoSampleFromSurface. Définissez le paramètre pUnkSurface sur NULL. La fonction retourne un pointeur IMFSample.
    3. Appelez IMFSample::AddBuffer pour ajouter la mémoire tampon média à l’échantillon.

Vous devez détruire toutes les textures que vous créez en même temps, plutôt que d’en détruire uniquement certaines et de continuer les autres.

Décodage

Pour créer le périphérique décodeur, appelez ID3D11VideoDevice::CreateVideoDecoder. La méthode retourne un pointeur vers l’interface ID3D11VideoDecoder. Le décodage doit se dérouler dans la méthode IMFTransform::ProcessOutput. Sur chaque trame, appelez IMFDXGIDeviceManager::TestDevice pour tester la disponibilité de DXGI. Si le périphérique a changé, le décodeur logiciel doit recréer le périphérique décodeur, comme suit :

  1. Fermez la poignée de périphérique en appelant IMFDXGIDeviceManager::CloseDeviceHandle.
  2. Publiez toutes les ressources associées au périphérique Direct3D 11 précédent, notamment les interfaces ID3D11VideoDecoder, ID3D11VideoContext, ID3D11Texture2D et ID3D11VideoDecoderOutputView.
  3. Ouvrez une nouvelle poignée de périphérique.
  4. Négociez une nouvelle configuration de décodeur, comme décrit précédemment dans Trouver une configuration de décodeur. Cette étape est nécessaire car les capacités du périphérique peuvent avoir changé.
  5. Créez un périphérique décodeur.

En supposant que la poignée de périphérique soit valide, le processus de décodage fonctionne comme suit :

  1. Obtenez une surface disponible qui n’est pas en cours d’utilisation. Au départ, toutes les surfaces sont disponibles.
  2. Interrogez l’échantillon média pour l’interface IMFTrackedSample.
  3. Appelez IMFTrackedSample::SetAllocator et fournissez un pointeur vers l’interfaceIMFAsyncCallback. (Le décodeur logiciel doit implémenter cette interface.) Lorsque l’outil d’affichage vidéo libère l’échantillon, le rappel est invoqué. Utilisez ce rappel pour suivre les échantillons actuellement disponibles et ceux qui sont en cours d’utilisation.
  4. Appelez ID3D11VideoContext::DecoderBeginFrame. Transmettez les pointeurs à l’interface ID3D11VideoDecoder pour le périphérique décodeur et à l’interface ID3D11VideoDecoderOutputViewpour la vue de sortie.
  5. Effectuez les opérations suivantes une ou plusieurs fois :
    1. Appelez ID3D11VideoContext::GetDecoderBuffer pour obtenir une mémoire tampon.
    2. Remplissez la mémoire tampon.
    3. Appelez ID3D11VideoContext::ReleaseDecoderBuffer.
    4. Appelez ID3D11VideoContext::SubmitDecoderBuffer. Cette méthode indique au périphérique décodeur d’effectuer les opérations de décodage sur la trame.
  6. Appelez ID3D11VideoContext::DecoderEndFrame pour signaler la fin du décodage pour la trame en cours.

Direct3D 11 utilise les mêmes structures de données que DXVA 2.0 pour les opérations de décodage. Pour l’ensemble d’origine des 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 DecoderBeginFrame et SubmitDecoderBuffer, vous pouvez appeler GetDecoderBuffer plusieurs fois, mais une seule fois pour chaque type de mémoire tampon. Si vous utilisez le même type de mémoire tampon deux fois sans appeler SubmitDecoderBuffer, vous remplacerez les données dans la mémoire tampon.

API vidéo Direct3D 11

Accélération vidéo DirectX 2.0