Unterstützung der Direct3D 11-Videodecodierung in Media Foundation

Dieses Thema beschreibt, wie Sie Microsoft Direct3D 11 in einem Microsoft Media Foundation-Decoder unterstützen. Er beschreibt insbesondere die Kommunikation zwischen dem Decoder und dem Video-Renderer. In diesem Thema wird nicht beschrieben, wie die Decodierungsvorgänge implementiert werden.

Überblick

Im Rest dieses Themas werden die folgenden Begriffe verwendet:

  • Softwaredecoder. Der Softwaredecoder ist der Media Foundation Transform (MFT), der komprimierte Videosamples empfängt und unkomprimierte Videobilder ausgibt.
  • Decodergerät. Das Decodergerät ist die Grafikengine und wird vom Grafiktreiber implementiert. Das Decodergerät führt beschleunigte Decodierungsvorgänge durch.
  • Pipeline. Die Pipeline hostet den Softwaredecoder und liefert Puffer an und vom Softwaredecoder. Je nach Anwendung kann es sich bei der Pipeline um die Mediensitzung, den Quellleser oder den Anwendungscode handeln, der direkt in MFT aufruft.

Um die Decodierung mit Direct3D 11 durchzuführen, benötigt der Softwaredecoder einen Zeiger auf ein Direct3D 11-Gerät. Das Direct3D 11-Gerät wird extern zum Softwaredecoder erstellt. In einem Mediensitzungsszenario erstellt der Videorenderer das Direct3D 11-Gerät. In einem Quellleserszenario erstellt in der Regel die Anwendung das Direct3D 11-Gerät.

Der DXGI Geräte-Manager wird zum Freigeben von Direct3D 11 zwischen Komponenten verwendet. Der DXGI Geräte-Manager stellt die IMFDXGIDeviceManager-Schnittstelle zur Verfügung. Die Pipeline legt den IMFDXGIDeviceManager-Zeiger auf dem Softwaredecoder fest, indem die MFT_MESSAGE_SET_D3D_MANAGER-Nachricht gesendet wird.

Das folgende Diagramm zeigt die Beziehung zwischen dem Softwaredecoder, dem Direct3D 11 und der Pipeline.

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

Hier sind die grundlegenden Schritte, die ein Softwaredecoder ausführen muss, um Direct3D 11 in Media Foundation zu unterstützen:

  1. Öffnen Sie ein Handle auf das Direct3D 11-Gerät.
  2. Suchen Sie eine Decoderkonfiguration.
  3. Weisen Sie dekomprimierte Puffer zu.
  4. Decodieren Sie Frames.

Diese Schritte werden im weiteren Verlauf dieses Themas ausführlicher beschrieben.

Öffnen eines Gerätehandles

Der Decoder MFT verwendet den DXGI Geräte-Manager, um ein Handle auf das Direct3D 11-Gerät zu erhalten. Führen Sie die folgenden Schritte aus, um das Gerätehandle zu öffnen:

  1. Der Decoder MFT muss das Attribut MF_SA_D3D11_AWARE mit dem Wert TRUE verfügbar machen.
  2. Das Topologieladeprogramm fragt dieses Attribut durch Aufrufen von IMFTransform::GetAttributes ab. Der Wert TRUE gibt an, dass der MFT Direct3D 11 unterstützt.
  3. Das Topologieladeprogramm ruft IMFTransform::ProcessMessage mit der Nachricht MFT_MESSAGE_SET_D3D_MANAGER auf. Der Parameter ulParam ist ein IUnknown-Zeiger auf den DXGI Geräte-Manager. Erstellen Sie eine Abfrage auf diesen Zeiger für die IMFDXGIDeviceManager-Schnittstelle.
  4. Rufen Sie IMFDXGIDeviceManager::OpenDeviceHandle auf, um ein Handle für das Direct3D 11-Gerät abzurufen.
  5. Rufen Sie zum Abrufen eines Zeigers auf das Direct3D 11-Gerät IMFDXGIDeviceManager::GetVideoService auf. Übergeben Sie das Gerätehandle und den Wert IID_ID3D11Device. Die Methode gibt einen Zeiger auf die ID3D11Device-Schnittstelle zurück.
  6. Rufen Sie IMFDXGIDeviceManager::GetVideoService erneut auf, um einen Zeiger auf die Grafikengine zu erhalten. Übergeben Sie dieses Mal den Gerätehandle und den Wert IID_ID3D11VideoDevice. Die Methode gibt einen Zeiger auf die ID3D11VideoDevice-Schnittstelle zurück.
  7. Rufen Sie ID3D11Device::GetImmediateContext auf, um einen ID3D11DeviceContext-Zeiger zu erhalten.
  8. Rufen Sie QueryInterface im ID3D11DeviceContext auf, um einen ID3D11VideoContext-Zeiger zu erhalten.
  9. Sie sollten den Multithreadschutz im Gerätekontext verwenden, um Deadlock-Probleme zu verhindern, die manchmal auftreten können, wenn Sie ID3D11VideoContext::GetDecoderBuffer oder ID3D11VideoContext::ReleaseDecoderBuffer aufrufen. Um den Multithreadschutz festzulegen, rufen Sie zuerst QueryInterface auf ID3D11Device auf, um einen ID3D10Multithread-Zeiger zu erhalten. Rufen Sie dann ID3D10Multithread::SetMultithreadProtected auf, und übergeben Sie true für bMTProtect.

Suchen einer Decoderkonfiguration

Zum Decodieren muss der Softwaredecoder eine kompatible Konfiguration finden, die vom Decodergerät unterstützt wird, einschließlich eines Renderzielformats. Dieser Schritt erfolgt in der IMFTransform::SetInputType-Methode, wie folgt:

  1. Überprüfen des Eingabemedientyps. Wenn der Typ abgelehnt wird, werden die restlichen Schritte übersprungen und ein Fehlercode zurückgegeben.
  2. Aufrufen von ID3D11VideoDevice::GetVideoDecoderProfileCount, um die Anzahl der unterstützten Profile abzurufen.
  3. Aufrufen von ID3D11VideoDevice::GetVideoDecoderProfile, um die Profile aufzählen und die Profil-GUIDs abzurufen.
  4. Suche nach einer Profil-GUID, die dem Videoformat und den Funktionen des Softwaredecoders entspricht. Beispielsweise würde ein MPEG-2-Decoder nach D3D11_DECODER_PROFILE_MPEG2_MOCOMP,D3D11_DECODER_PROFILE_MPEG2_IDCT, und D3D11_DECODER_PROFILE_MPEG2_VLD suchen.
  5. Wenn eine geeignete Decoder-GUID gefunden wird, wird das Ausgabeformat überprüft, indem die Methode ID3D11VideoDevice::CheckVideoDecoderFormat aufgerufen wird. Übergeben der Decoder-GUID und eines DXGI_FORMAT-Werts, der das Renderzielformat angibt.
  6. Anschließende Suche nach einer geeigneten Konfiguration für den Decoder.
    1. Anrufen von ID3D11VideoDevice::GetVideoDecoderConfigCount, um die Anzahl der Decoderkonfigurationen abzurufen. Übergeben derselben Decodergeräte-GUID zusammen mit einer D3D11_VIDEO_DECODER_DESC-Struktur, die das vorgeschlagene Renderzielformat beschreibt.
    2. Anrufen von ID3D11VideoDevice::GetVideoDecoderConfig, um die Decoderkonfigurationen aufzuzählen.

In der Methode IMFTransform::GetOutputAvailableType wird ein dekomprimiertes Videoformat basierend auf dem vorgeschlagenen Renderzielformat zurückgegeben.

Überprüfen des Medientyp anhand des Renderzielformats in der Methode IMFTransform::SetOutputType.

Fallback auf Softwaredecodierung

Der MFT kann möglicherweise keine Konfiguration finden. Beispielsweise unterstützt der Grafiktreiber möglicherweise nicht die richtigen Funktionen. In diesem Fall muss der MFT wie folgt auf die Softwaredecodierung zurückgreifen.

  1. Die Methoden SetInputType und SetOutputType sollten beide MF_E_UNSUPPORTED_D3D_TYPE zurückgeben.
  2. Als Antwort sendet das Topologieladeprogramm die Nachricht MFT_MESSAGE_SET_D3D_MANAGER mit dem Wert NULL für den Parameter ulParam.
  3. Der MFT gibt seinen Zeiger auf die IMFDXGIDeviceManager-Schnittstelle frei.
  4. Das Topologieladeprogramm gibt den Medientyp neu an.

Zu diesem Zeitpunkt kann der MFT die Softwaredecodierung verwenden.

Zuordnen von dekomprimierten Puffern

Der Decoder ist für die Zuordnung von Direct3D 11-Texturen verantwortlich, die als dekomprimierte Videopuffer verwendet werden. Das Attribut MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT in den Ausgabedatenstromattributen (siehe IMFTransform::GetOutputStreamAttributes) wird verwendet, um zu bestimmen, wie viele Oberflächen der Decoder für den Videorenderer für die Deinterlacierung verwenden soll. Ein Decoder sollte diesen Wert verwenden, um ihn auf einen vernünftigen oberen und unteren Grenzwert zu begrenzen, z. B. 3–32. Informationen zu progressiven Inhalten finden Sie unter MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE.

Legen Sie in der Methode IMFTransform::GetOutputStreamInfo das MFT_OUTPUT_STREAM_PROVIDES_SAMPLES-Flag in der MFT_OUTPUT_STREAM_INFO-Struktur fest. Dieses Flag teilt der Mediensitzung mit, dass der MFT seine eigenen Ausgabebeispiele zuweist. Um die Ausgabebeispiele zuzuweisen, führt der MFT die folgenden Schritte aus:

  1. Erstellen eines 2D-Texturarrays durch Aufrufen von ID3D11Device::CreateTexture2D. In der Struktur D3D11_TEXTURE2D_DESC, festlegen vonArraySize auf die Anzahl der Oberflächen, die der Decoder benötigt. Dies umfasst:

    • Oberflächen für Referenzframes.
    • Oberflächen für Deinterlacing (drei Oberflächen).
    • Oberflächen, die der Decoder für die Pufferung benötigt.

    Die Bindungsflags (BindFlags) sollten das D3D11_BIND_DECODER-Flag und alle Bindungsflage enthalten, die über das Attribut MF_SA_D3D11_BINDFLAGS in den Ausgabedatenstromattributen festgelegt werden.

  2. Rufen Sie für jede Oberfläche im Texturarray ID3D11VideoDevice::CreateVideoDecoderOutputView auf, um eine Videodecoderausgabeansicht zu erstellen. Während der Decodierung werden diese Ausgabeansichten an die Methode ID3D11VideoContext::DecoderBeginFrame übergeben.

  3. Erstellen Sie für jede Oberfläche im Texturarray ein Medienbeispiel wie folgt:

    1. Erstellen Sie einen DXGI-Medienpuffer, indem Sie die Funktion MFCreateDXGISurfaceBuffer aufrufen. Übergeben Sie den Zeiger ID3D11Texture2D und den Offset für jedes Element im Texturarray. Die Funktion gibt einen IMFMediaBuffer-Zeiger zurück.
    2. Erstellen Sie ein leeres Medienbeispiel, indem Sie die Funktion MFCreateVideoSampleFromSurface aufrufen. Legen Sie den Parameter pUnkSurface auf NULL fest. Die Funktion gibt einen IMFSample-Zeiger zurück.
    3. Rufen Sie IMFSample::AddBuffer auf, um dem Beispiel den Medienpuffer hinzuzufügen.

Sie sollten alle Texturen, die Sie erstellen, auf einmal zerstören, anstatt nur einige zu zerstören und den Rest weiter zu verwenden.

Decodierung

Rufen Sie zum Erstellen des Decodergeräts ID3D11VideoDevice::CreateVideoDecoder auf. Die Methode gibt einen Zeiger auf die ID3D11VideoDecoder-Schnittstelle zurück. Die Decodierung sollte innerhalb der Methode IMFTransform::ProcessOutput erfolgen. Rufen Sie auf jedem Frame IMFDXGIDeviceManager::TestDevice auf, um die Verfügbarkeit der DXGI zu testen. Wenn sich das Gerät geändert hat, muss der Softwaredecoder das Decodergerät wie folgt neu erstellen:

  1. Schließen Sie das Gerätehandle, indem Sie IMFDXGIDeviceManager::CloseDeviceHandle aufrufen.
  2. Geben Sie alle Ressourcen frei, die dem vorherigen Direct3D 11-Gerät zugeordnet sind, einschließlich der Schnittstellen ID3D11VideoDecoder, ID3D11VideoContext, ID3D11Texture2D, und ID3D11VideoDecoderOutputView.
  3. Öffnen Sie ein neues Gerätehandle.
  4. Verhandeln Sie eine neue Decoderkonfiguration, wie zuvor unter Suchen einer Decoderkonfiguration beschrieben. Dieser Schritt ist erforderlich, da sich die Gerätefunktionen möglicherweise geändert haben.
  5. Erstellen Sie ein neues Decodergerät.

Wenn der Gerätehandle gültig ist, funktioniert der Decodierungsprozess wie folgt:

  1. Rufen Sie eine verfügbare Oberfläche ab, die derzeit nicht verwendet wird. Zunächst sind alle Oberflächen verfügbar.
  2. Führen Sie eine Abfrage auf das Medienbeispiel für die IMFTrackedSample-Schnittstelle aus.
  3. Rufen Sie IMFTrackedSample::SetAllocator auf, und stellen Sie einen Zeiger auf die IMFAsyncCallback-Schnittstelle bereit. (Der Softwaredecoder muss diese Schnittstelle implementieren.) Wenn der Videorenderer das Beispiel freigibt, wird der Callback aufgerufen. Verwenden Sie diesen Callback, um nachzuverfolgen, welche Beispiele derzeit verfügbar sind und welche verwendet werden.
  4. Rufen Sie ID3D11VideoContext::DecoderBeginFrame auf. Übergeben Sie die Zeiger für das Decodergerät an die Schnittstelle ID3D11VideoDecoder und für die Ausgabeansicht an die Schnittstelle ID3D11VideoDecoderOutputView.
  5. Führen Sie die folgenden Schritte ein- oder mehrmals durch:
    1. Rufen Sie ID3D11VideoContext::GetDecoderBuffer auf, um einen Puffer abzurufen.
    2. Füllen Sie den Puffer.
    3. Rufen Sie ID3D11VideoContext::ReleaseDecoderBuffer auf.
    4. Rufen Sie ID3D11VideoContext::SubmitDecoderBuffer auf. Diese Methode weist das Decodergerät an, die Decodierungsvorgänge für den Frame auszuführen.
  6. Rufen Sie ID3D11VideoContext::DecoderEndFrame auf, um das Ende der Decodierung für den aktuellen Frame zu signalisieren.

Direct3D 11 verwendet für Decodierungsvorgänge die gleichen Datenstrukturen wie DXVA 2.0. Für den ursprünglichen Satz von DXVA-Profilen (für H.261, H.263 und MPEG-2) werden diese Datenstrukturen in der DXVA 1.0-Spezifikation beschrieben.

Innerhalb jedes Paars von Aufrufen von DecoderBeginFrame undSubmitDecoderBuffer können Sie GetDecoderBuffer mehrmals aufrufen, jedoch nur einmal für jeden Puffertyp. Wenn Sie denselben Puffertyp zweimal verwenden, ohne SubmitDecoderBuffer aufzurufen, überschreiben Sie die Daten im Puffer.

Direct3D 11 Video APIs

DirectX Video Acceleration 2.0