[vlc-commits] [Git][videolan/vlc][master] 13 commits: mft: don't keep the output type

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Jan 17 08:33:10 UTC 2022



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
f825a3a3 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: don't keep the output type

We never use it

- - - - -
b9e2ec07 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: only check the expect flags for video

- - - - -
37e7fa05 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: send messages when we're done with the MFT

- - - - -
7bd3788c by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: compile as C++ so we can use some more headers

Using COM interfaces is better in C++ anyway.

It also makes it usable with the GDK (Xbox).

- - - - -
de853afa by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: use include codecapi.h to get the actual CODECAPI_xxx defines

Only works with mingw when compiled in C++

- - - - -
bd881907 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: use WRL for COM objects

Requires to use decoder_sys_t as an object.

- - - - -
58b0e9e1 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: handle the ProcessOutput error return values first

So we don't need to check for S_OK after.

Plus hr is modified afterwards and may end up in the code that was supposed to
be for this specific call.

- - - - -
7dbf9541 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: reindent after previous changes

No functional changes.

- - - - -
2d730baa by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: use methods to flush/drain/start/stop streams

This way we can always check we're in the proper state to do it.

- - - - -
bf800738 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: use the newer GUID for low delay handling

We may not really need it at all though and it's supposed to degrade quality.

CODECAPI_AVLowLatencyMode is not always defined.

- - - - -
8f30cf2e by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: use the size of the audio buffer to read the indexed buffer

In case there is more than one we should not read all of them each time.

This is currently a buffer we provide so it should not happen.

- - - - -
0da111aa by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: allow releasing the decoder sys asynchronously

The decoder may need to be released with the last picture.

- - - - -
a4445b32 by Steve Lhomme at 2022-01-17T08:18:03+00:00
mft: add D3D11 output support

MFCreateDXGIDeviceManager is only available on Win8+ so we bring back the DLL loading.

- - - - -


3 changed files:

- modules/codec/Makefile.am
- modules/codec/mft.c → modules/codec/mft.cpp
- po/POTFILES.in


Changes:

=====================================
modules/codec/Makefile.am
=====================================
@@ -590,10 +590,13 @@ codec_LTLIBRARIES += libdmo_plugin.la
 endif
 endif
 
-libmft_plugin_la_SOURCES = codec/mft.c
+libmft_plugin_la_SOURCES = codec/mft.cpp
 if HAVE_WIN32
-libmft_plugin_la_LIBADD = $(LIBCOM) -luuid -lmfuuid -lmfplat libvlc_hxxxhelper.la
+libmft_plugin_la_LIBADD = $(LIBCOM) -luuid -lmfuuid -lmfplat libvlc_hxxxhelper.la libd3d11_common.la
 codec_LTLIBRARIES += libmft_plugin.la
+if HAVE_WINSTORE
+libmft_plugin_la_LIBADD += -ld3d11
+endif
 endif
 
 libgstdecode_plugin_la_SOURCES = codec/gstreamer/gstdecode.c \


=====================================
modules/codec/mft.c → modules/codec/mft.cpp
=====================================
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * mft.c : Media Foundation Transform audio/video decoder
+ * mft.cpp : Media Foundation Transform audio/video decoder
  *****************************************************************************
  * Copyright (C) 2014 VLC authors and VideoLAN
  *
@@ -33,19 +33,29 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_codec.h>
+extern "C" {
 #include "hxxx_helper.h"
+}
+
+#include "../video_chroma/d3d11_fmt.h"
 
-#define COBJMACROS
 #include <initguid.h>
 #include <mfapi.h>
 #include <mftransform.h>
 #include <mferror.h>
 #include <mfobjects.h>
+#include <codecapi.h>
 
 
 #define _VIDEOINFOHEADER_
 #include <vlc_codecs.h>
 
+#include <atomic>
+#include <new>
+
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
 static int  Open(vlc_object_t *);
 static void Close(vlc_object_t *);
 
@@ -62,34 +72,151 @@ vlc_module_begin()
     set_callbacks(Open, Close)
 vlc_module_end()
 
-typedef struct
+typedef HRESULT (WINAPI *pf_MFCreateDXGIDeviceManager)(UINT *, IMFDXGIDeviceManager **);
+
+struct decoder_sys_t
 {
-    IMFTransform *mft;
+    ComPtr<IMFTransform> mft;
 
-    const GUID* major_type;
-    const GUID* subtype;
+    const GUID* major_type = nullptr;
+    const GUID* subtype = nullptr;
     /* Container for a dynamically constructed subtype */
     GUID custom_subtype;
 
+    // Direct3D
+    vlc_video_context  *vctx_out = nullptr;
+    HRESULT (WINAPI *fptr_MFCreateDXGIDeviceManager)(UINT *resetToken, IMFDXGIDeviceManager **ppDeviceManager);
+    UINT dxgi_token = 0;
+    ComPtr<IMFDXGIDeviceManager> dxgi_manager;
+    HANDLE d3d_handle = 0;
+
+    // D3D11
+    ComPtr<ID3D11Texture2D> cached_tex;
+    ID3D11ShaderResourceView *cachedSRV[32][DXGI_MAX_SHADER_VIEW] = {{nullptr}};
+
     /* For asynchronous MFT */
-    bool is_async;
-    IMFMediaEventGenerator *event_generator;
-    int pending_input_events;
-    int pending_output_events;
+    bool is_async = false;
+    ComPtr<IMFMediaEventGenerator> event_generator;
+    int pending_input_events = 0;
+    int pending_output_events = 0;
 
     /* Input stream */
-    DWORD input_stream_id;
-    IMFMediaType *input_type;
+    DWORD input_stream_id = 0;
+    ComPtr<IMFMediaType> input_type;
 
     /* Output stream */
-    DWORD output_stream_id;
-    IMFSample *output_sample;
-    IMFMediaType *output_type;
+    DWORD output_stream_id = 0;
+    ComPtr<IMFSample> output_sample;
 
     /* H264 only. */
-    struct hxxx_helper hh;
-    bool   b_xps_pushed; ///< (for xvcC) parameter sets pushed (SPS/PPS/VPS)
-} decoder_sys_t;
+    struct hxxx_helper hh = {};
+    bool   b_xps_pushed = false; ///< (for xvcC) parameter sets pushed (SPS/PPS/VPS)
+
+    std::atomic<size_t>  refcount{1};
+
+
+    void AddRef()
+    {
+        refcount++;
+    }
+
+    bool Release()
+    {
+        if (--refcount == 0)
+        {
+            DoRelease();
+            return true;
+        }
+        return false;
+    }
+
+    void DoRelease()
+    {
+        mft->SetInputType(input_stream_id, nullptr, 0);
+        mft->SetOutputType(output_stream_id, nullptr, 0);
+
+        if (output_sample.Get())
+            output_sample->RemoveAllBuffers();
+
+        if (vctx_out)
+            mft->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)0);
+
+        endStreaming();
+
+        for (size_t i=0; i < ARRAY_SIZE(cachedSRV); i++)
+        {
+            for (size_t j=0; j < ARRAY_SIZE(cachedSRV[i]); j++)
+            {
+                if (cachedSRV[i][j] != nullptr)
+                    cachedSRV[i][j]->Release();
+            }
+        }
+
+        if (vctx_out && dxgi_manager.Get())
+        {
+            if (d3d_handle)
+                dxgi_manager->CloseDeviceHandle(d3d_handle);
+        }
+
+        if (vctx_out)
+            vlc_video_context_Release(vctx_out);
+
+        delete this;
+
+        MFShutdown();
+    }
+
+    bool isStreaming = false;
+    HRESULT beginStreaming()
+    {
+        assert(!isStreaming);
+        HRESULT hr = mft->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, (ULONG_PTR)0);
+        isStreaming = SUCCEEDED(hr);
+        return hr;
+    }
+    HRESULT endStreaming()
+    {
+        assert(isStreaming);
+        HRESULT hr = mft->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, (ULONG_PTR)0);
+        isStreaming = SUCCEEDED(hr);
+        return hr;
+    }
+    bool streamStarted = false;
+    HRESULT startStream()
+    {
+        assert(!streamStarted);
+        HRESULT hr = mft->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, (ULONG_PTR)0);
+        streamStarted = SUCCEEDED(hr);
+        return hr;
+    }
+    HRESULT endStream()
+    {
+        assert(streamStarted);
+        HRESULT hr = mft->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, (ULONG_PTR)0);
+        if (SUCCEEDED(hr))
+            streamStarted = false;
+        return hr;
+    }
+    HRESULT flushStream()
+    {
+        HRESULT hr = mft->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+        if (streamStarted)
+        {
+            streamStarted = false;
+            startStream();
+        }
+        return hr;
+    }
+};
+
+struct mf_d3d11_pic_ctx
+{
+    struct d3d11_pic_context ctx;
+    IMFMediaBuffer *out_media;
+    decoder_sys_t  *mfdec;
+};
+#define MF_D3D11_PICCONTEXT_FROM_PICCTX(pic_ctx)  \
+    container_of(pic_ctx, mf_d3d11_pic_ctx, ctx.s)
 
 static const int pi_channels_maps[9] =
 {
@@ -197,38 +324,30 @@ static const GUID *FormatToGUID(const pair_format_guid table[], vlc_fourcc_t fou
     return NULL;
 }
 
-static vlc_fourcc_t GUIDToFormat(const pair_format_guid table[], const GUID* guid)
+static vlc_fourcc_t GUIDToFormat(const pair_format_guid table[], const GUID & guid)
 {
     for (int i = 0; table[i].fourcc; ++i)
-        if (IsEqualGUID(table[i].guid, guid))
+        if (IsEqualGUID(*table[i].guid, guid))
             return table[i].fourcc;
 
     return 0;
 }
 
-/*
- * Low latency mode for Windows 8. Without this option, the H264
- * decoder will fill *all* its internal buffers before returning a
- * frame. Because of this behavior, the decoder might return no frame
- * for more than 500 ms, making it unusable for playback.
- */
-DEFINE_GUID(CODECAPI_AVLowLatencyMode, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee);
-
-static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
+static int SetInputType(decoder_t *p_dec, DWORD stream_id, ComPtr<IMFMediaType> & result)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    *result = NULL;
+    result.Reset();
 
-    IMFMediaType *input_media_type = NULL;
+    ComPtr<IMFMediaType> input_media_type;
 
     /* Search a suitable input type for the MFT. */
     int input_type_index = 0;
     bool found = false;
     for (int i = 0; !found; ++i)
     {
-        hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, i, &input_media_type);
+        hr = p_sys->mft->GetInputAvailableType(stream_id, i, input_media_type.GetAddressOf());
         if (hr == MF_E_NO_MORE_TYPES)
             break;
         else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
@@ -240,23 +359,22 @@ static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result
             goto error;
 
         GUID subtype;
-        hr = IMFMediaType_GetGUID(input_media_type, &MF_MT_SUBTYPE, &subtype);
+        hr = input_media_type->GetGUID(MF_MT_SUBTYPE, &subtype);
         if (FAILED(hr))
             goto error;
 
-        if (IsEqualGUID(&subtype, p_sys->subtype))
+        if (IsEqualGUID(subtype, *p_sys->subtype))
             found = true;
 
         if (found)
             input_type_index = i;
 
-        IMFMediaType_Release(input_media_type);
-        input_media_type = NULL;
+        input_media_type.Reset();
     }
     if (!found)
         goto error;
 
-    hr = IMFTransform_GetInputAvailableType(p_sys->mft, stream_id, input_type_index, &input_media_type);
+    hr = p_sys->mft->GetInputAvailableType(stream_id, input_type_index, input_media_type.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
@@ -265,7 +383,7 @@ static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result
         UINT64 width = p_dec->fmt_in.video.i_width;
         UINT64 height = p_dec->fmt_in.video.i_height;
         UINT64 frame_size = (width << 32) | height;
-        hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_SIZE, frame_size);
+        hr = input_media_type->SetUINT64(MF_MT_FRAME_SIZE, frame_size);
         if (FAILED(hr))
             goto error;
 
@@ -274,43 +392,43 @@ static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result
         UINT64 frame_ratio_dem = p_dec->fmt_in.video.i_frame_rate_base;
         if(frame_ratio_num && frame_ratio_dem) {
             UINT64 frame_rate = (frame_ratio_num << 32) | frame_ratio_dem;
-            hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_RATE, frame_rate);
+            hr = input_media_type->SetUINT64(MF_MT_FRAME_RATE, frame_rate);
             if(FAILED(hr))
                 goto error;
         }
     }
     else
     {
-        hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_ORIGINAL_WAVE_FORMAT_TAG, p_sys->subtype->Data1);
+        hr = input_media_type->SetUINT32(MF_MT_ORIGINAL_WAVE_FORMAT_TAG, p_sys->subtype->Data1);
         if (FAILED(hr))
             goto error;
         if (p_dec->fmt_in.audio.i_rate)
         {
-            hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, p_dec->fmt_in.audio.i_rate);
+            hr = input_media_type->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, p_dec->fmt_in.audio.i_rate);
             if (FAILED(hr))
                 goto error;
         }
         if (p_dec->fmt_in.audio.i_channels)
         {
-            hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_NUM_CHANNELS, p_dec->fmt_in.audio.i_channels);
+            hr = input_media_type->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, p_dec->fmt_in.audio.i_channels);
             if (FAILED(hr))
                 goto error;
         }
         if (p_dec->fmt_in.audio.i_bitspersample)
         {
-            hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, p_dec->fmt_in.audio.i_bitspersample);
+            hr = input_media_type->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, p_dec->fmt_in.audio.i_bitspersample);
             if (FAILED(hr))
                 goto error;
         }
         if (p_dec->fmt_in.audio.i_blockalign)
         {
-            hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, p_dec->fmt_in.audio.i_blockalign);
+            hr = input_media_type->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, p_dec->fmt_in.audio.i_blockalign);
             if (FAILED(hr))
                 goto error;
         }
         if (p_dec->fmt_in.i_bitrate)
         {
-            hr = IMFMediaType_SetUINT32(input_media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, p_dec->fmt_in.i_bitrate / 8);
+            hr = input_media_type->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, p_dec->fmt_in.i_bitrate / 8);
             if (FAILED(hr))
                 goto error;
         }
@@ -319,43 +437,39 @@ static int SetInputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result
     if (p_dec->fmt_in.i_extra > 0)
     {
         UINT32 blob_size = 0;
-        hr = IMFMediaType_GetBlobSize(input_media_type, &MF_MT_USER_DATA, &blob_size);
+        hr = input_media_type->GetBlobSize(MF_MT_USER_DATA, &blob_size);
         /*
          * Do not overwrite existing user data in the input type, this
          * can cause the MFT to reject the type.
          */
         if (hr == MF_E_ATTRIBUTENOTFOUND)
         {
-            hr = IMFMediaType_SetBlob(input_media_type, &MF_MT_USER_DATA,
-                                      p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
+            hr = input_media_type->SetBlob(MF_MT_USER_DATA,
+                                      static_cast<const UINT8*>(p_dec->fmt_in.p_extra), p_dec->fmt_in.i_extra);
             if (FAILED(hr))
                 goto error;
         }
     }
 
-    hr = IMFTransform_SetInputType(p_sys->mft, stream_id, input_media_type, 0);
+    hr = p_sys->mft->SetInputType(stream_id, input_media_type.Get(), 0);
     if (FAILED(hr))
         goto error;
 
-    *result = input_media_type;
+    result.Swap(input_media_type);
 
     return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in SetInputType()");
-    if (input_media_type)
-        IMFMediaType_Release(input_media_type);
     return VLC_EGENERIC;
 }
 
-static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result)
+static int SetOutputType(decoder_t *p_dec, DWORD stream_id)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    *result = NULL;
-
-    IMFMediaType *output_media_type = NULL;
+    ComPtr<IMFMediaType> output_media_type;
 
     /*
      * Enumerate available output types. The list is ordered by
@@ -366,7 +480,7 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
     bool found = false;
     for (int i = 0; !found; ++i)
     {
-        hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, i, &output_media_type);
+        hr = p_sys->mft->GetOutputAvailableType(stream_id, i, output_media_type.GetAddressOf());
         if (hr == MF_E_NO_MORE_TYPES)
             break;
         else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET)
@@ -378,34 +492,33 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
             goto error;
 
         GUID subtype;
-        hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
+        hr = output_media_type->GetGUID(MF_MT_SUBTYPE, &subtype);
         if (FAILED(hr))
             goto error;
 
         if (p_dec->fmt_in.i_cat == VIDEO_ES)
         {
-            if (IsEqualGUID(&subtype, &MFVideoFormat_NV12) || IsEqualGUID(&subtype, &MFVideoFormat_YV12) || IsEqualGUID(&subtype, &MFVideoFormat_I420))
+            if (IsEqualGUID(subtype, MFVideoFormat_NV12) || IsEqualGUID(subtype, MFVideoFormat_YV12) || IsEqualGUID(subtype, MFVideoFormat_I420))
                 found = true;
             /* Transform might offer output in a D3DFMT proprietary FCC. If we can
              * use it, fall back to it in case we do not find YV12 or I420 */
-            else if(output_type_index < 0 && GUIDToFormat(d3d_format_table, &subtype) > 0)
+            else if(output_type_index < 0 && GUIDToFormat(d3d_format_table, subtype) > 0)
                     output_type_index = i;
         }
         else
         {
             UINT32 bits_per_sample;
-            hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample);
+            hr = output_media_type->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample);
             if (FAILED(hr))
                 continue;
-            if (bits_per_sample == 32 && IsEqualGUID(&subtype, &MFAudioFormat_Float))
+            if (bits_per_sample == 32 && IsEqualGUID(subtype, MFAudioFormat_Float))
                 found = true;
         }
 
         if (found)
             output_type_index = i;
 
-        IMFMediaType_Release(output_media_type);
-        output_media_type = NULL;
+        output_media_type.Reset();
     }
     /*
      * It's not an error if we don't find the output type we were
@@ -416,16 +529,16 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
          * by the MFT */
         output_type_index = 0;
 
-    hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, output_type_index, &output_media_type);
+    hr = p_sys->mft->GetOutputAvailableType(stream_id, output_type_index, output_media_type.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
-    hr = IMFTransform_SetOutputType(p_sys->mft, stream_id, output_media_type, 0);
+    hr = p_sys->mft->SetOutputType(stream_id, output_media_type.Get(), 0);
     if (FAILED(hr))
         goto error;
 
     GUID subtype;
-    hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype);
+    hr = output_media_type->GetGUID(MF_MT_SUBTYPE, &subtype);
     if (FAILED(hr))
         goto error;
 
@@ -434,7 +547,7 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
         video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video );
 
         /* Transform might offer output in a D3DFMT proprietary FCC */
-        vlc_fourcc_t fcc = GUIDToFormat(d3d_format_table, &subtype);
+        vlc_fourcc_t fcc = GUIDToFormat(d3d_format_table, subtype);
         if(fcc) {
             /* D3D formats are upside down */
             p_dec->fmt_out.video.orientation = ORIENT_BOTTOM_LEFT;
@@ -449,17 +562,17 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
         p_dec->fmt_out.audio = p_dec->fmt_in.audio;
 
         UINT32 bitspersample = 0;
-        hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bitspersample);
+        hr = output_media_type->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitspersample);
         if (SUCCEEDED(hr) && bitspersample)
             p_dec->fmt_out.audio.i_bitspersample = bitspersample;
 
         UINT32 channels = 0;
-        hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels);
+        hr = output_media_type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &channels);
         if (SUCCEEDED(hr) && channels)
             p_dec->fmt_out.audio.i_channels = channels;
 
         UINT32 rate = 0;
-        hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate);
+        hr = output_media_type->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate);
         if (SUCCEEDED(hr) && rate)
             p_dec->fmt_out.audio.i_rate = rate;
 
@@ -470,70 +583,66 @@ static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **resul
         p_dec->fmt_out.audio.i_physical_channels = pi_channels_maps[p_dec->fmt_out.audio.i_channels];
     }
 
-    *result = output_media_type;
-
     return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in SetOutputType()");
-    if (output_media_type)
-        IMFMediaType_Release(output_media_type);
     return VLC_EGENERIC;
 }
 
-static int AllocateInputSample(decoder_t *p_dec, DWORD stream_id, IMFSample** result, DWORD size)
+static int AllocateInputSample(decoder_t *p_dec, DWORD stream_id, ComPtr<IMFSample> & result, DWORD size)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    *result = NULL;
+    result.Reset();
 
-    IMFSample *input_sample = NULL;
-    IMFMediaBuffer *input_media_buffer = NULL;
+    ComPtr<IMFSample> input_sample;
+    ComPtr<IMFMediaBuffer> input_media_buffer;
+    DWORD allocation_size;
 
     MFT_INPUT_STREAM_INFO input_info;
-    hr = IMFTransform_GetInputStreamInfo(p_sys->mft, stream_id, &input_info);
+    hr = p_sys->mft->GetInputStreamInfo(stream_id, &input_info);
     if (FAILED(hr))
         goto error;
 
-    hr = MFCreateSample(&input_sample);
+    hr = MFCreateSample(input_sample.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
-    DWORD allocation_size = __MAX(input_info.cbSize, size);
-    hr = MFCreateMemoryBuffer(allocation_size, &input_media_buffer);
+    allocation_size = __MAX(input_info.cbSize, size);
+    hr = MFCreateMemoryBuffer(allocation_size, input_media_buffer.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
-    hr = IMFSample_AddBuffer(input_sample, input_media_buffer);
-    IMFMediaBuffer_Release(input_media_buffer);
+    hr = input_sample->AddBuffer(input_media_buffer.Get());
     if (FAILED(hr))
         goto error;
 
-    *result = input_sample;
+    result.Swap(input_sample);
 
     return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in AllocateInputSample()");
-    if (input_sample)
-        IMFSample_Release(input_sample);
-    if (input_media_buffer)
-        IMFMediaBuffer_Release(input_media_buffer);
     return VLC_EGENERIC;
 }
 
-static int AllocateOutputSample(decoder_t *p_dec, DWORD stream_id, IMFSample **result)
+static int AllocateOutputSample(decoder_t *p_dec, DWORD stream_id, ComPtr<IMFSample> & result)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    *result = NULL;
+    result.Reset();
 
-    IMFSample *output_sample = NULL;
+    ComPtr<IMFSample> output_sample;
 
     MFT_OUTPUT_STREAM_INFO output_info;
-    hr = IMFTransform_GetOutputStreamInfo(p_sys->mft, stream_id, &output_info);
+    ComPtr<IMFMediaBuffer> output_media_buffer;
+    DWORD allocation_size;
+    DWORD alignment;
+
+    hr = p_sys->mft->GetOutputStreamInfo(stream_id, &output_info);
     if (FAILED(hr))
         goto error;
 
@@ -543,51 +652,52 @@ static int AllocateOutputSample(decoder_t *p_dec, DWORD stream_id, IMFSample **r
         return VLC_SUCCESS;
     }
 
-    DWORD expected_flags = 0;
     if (p_dec->fmt_in.i_cat == VIDEO_ES)
-        expected_flags |= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
+    {
+        const DWORD expected_flags =
+                          MFT_OUTPUT_STREAM_WHOLE_SAMPLES
                         | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
                         | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
-    if ((output_info.dwFlags & expected_flags) != expected_flags)
-        goto error;
+        if ((output_info.dwFlags & expected_flags) != expected_flags)
+            goto error;
+    }
 
-    hr = MFCreateSample(&output_sample);
+    hr = MFCreateSample(output_sample.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
-    IMFMediaBuffer *output_media_buffer = NULL;
-    DWORD allocation_size = output_info.cbSize;
-    DWORD alignment = output_info.cbAlignment;
+    allocation_size = output_info.cbSize;
+    alignment = output_info.cbAlignment;
     if (alignment > 0)
-        hr = MFCreateAlignedMemoryBuffer(allocation_size, alignment - 1, &output_media_buffer);
+        hr = MFCreateAlignedMemoryBuffer(allocation_size, alignment - 1, output_media_buffer.GetAddressOf());
     else
-        hr = MFCreateMemoryBuffer(allocation_size, &output_media_buffer);
+        hr = MFCreateMemoryBuffer(allocation_size, output_media_buffer.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
-    hr = IMFSample_AddBuffer(output_sample, output_media_buffer);
+    hr = output_sample->AddBuffer(output_media_buffer.Get());
     if (FAILED(hr))
         goto error;
 
-    *result = output_sample;
+    result.Swap(output_sample);
 
     return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in AllocateOutputSample()");
-    if (output_sample)
-        IMFSample_Release(output_sample);
     return VLC_EGENERIC;
 }
 
 static int ProcessInputStream(decoder_t *p_dec, DWORD stream_id, block_t *p_block)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr = S_OK;
-    IMFSample *input_sample = NULL;
+    ComPtr<IMFSample> input_sample;
 
     block_t *p_xps_blocks = NULL;
     DWORD alloc_size = p_block->i_buffer;
+    vlc_tick_t ts;
+    ComPtr<IMFMediaBuffer> input_media_buffer;
 
     if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
     {
@@ -606,16 +716,15 @@ static int ProcessInputStream(decoder_t *p_dec, DWORD stream_id, block_t *p_bloc
         }
     }
 
-    if (AllocateInputSample(p_dec, stream_id, &input_sample, alloc_size))
+    if (AllocateInputSample(p_dec, stream_id, input_sample, alloc_size))
         goto error;
 
-    IMFMediaBuffer *input_media_buffer = NULL;
-    hr = IMFSample_GetBufferByIndex(input_sample, 0, &input_media_buffer);
+    hr = input_sample->GetBufferByIndex(0, input_media_buffer.GetAddressOf());
     if (FAILED(hr))
         goto error;
 
     BYTE *buffer_start;
-    hr = IMFMediaBuffer_Lock(input_media_buffer, &buffer_start, NULL, NULL);
+    hr = input_media_buffer->Lock(&buffer_start, NULL, NULL);
     if (FAILED(hr))
         goto error;
 
@@ -625,38 +734,34 @@ static int ProcessInputStream(decoder_t *p_dec, DWORD stream_id, block_t *p_bloc
     }
     memcpy(buffer_start, p_block->p_buffer, p_block->i_buffer);
 
-    hr = IMFMediaBuffer_Unlock(input_media_buffer);
+    hr = input_media_buffer->Unlock();
     if (FAILED(hr))
         goto error;
 
-    hr = IMFMediaBuffer_SetCurrentLength(input_media_buffer, p_block->i_buffer);
+    hr = input_media_buffer->SetCurrentLength(p_block->i_buffer);
     if (FAILED(hr))
         goto error;
 
-    vlc_tick_t ts = p_block->i_pts == VLC_TICK_INVALID ? p_block->i_dts : p_block->i_pts;
+    ts = p_block->i_pts == VLC_TICK_INVALID ? p_block->i_dts : p_block->i_pts;
 
     /* Convert from microseconds to 100 nanoseconds unit. */
-    hr = IMFSample_SetSampleTime(input_sample, MSFTIME_FROM_VLC_TICK(ts));
+    hr = input_sample->SetSampleTime(MSFTIME_FROM_VLC_TICK(ts));
     if (FAILED(hr))
         goto error;
 
-    hr = IMFTransform_ProcessInput(p_sys->mft, stream_id, input_sample, 0);
+    hr = p_sys->mft->ProcessInput(stream_id, input_sample.Get(), 0);
     if (FAILED(hr))
     {
         msg_Dbg(p_dec, "Failed to process input stream %lu (error 0x%lX)", stream_id, hr);
         goto error;
     }
 
-    IMFMediaBuffer_Release(input_media_buffer);
-    IMFSample_Release(input_sample);
     block_ChainRelease(p_xps_blocks);
 
     return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in ProcessInputStream(). (hr=0x%lX)\n", hr);
-    if (input_sample)
-        IMFSample_Release(input_sample);
     block_ChainRelease(p_xps_blocks);
     return VLC_EGENERIC;
 }
@@ -686,181 +791,331 @@ static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t *p_src)
     }
 }
 
-static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id, bool *keep_reading)
+static void d3d11mf_pic_context_destroy(picture_context_t *ctx)
+{
+    mf_d3d11_pic_ctx *pic_ctx = MF_D3D11_PICCONTEXT_FROM_PICCTX(ctx);
+    decoder_sys_t *mfdec = pic_ctx->mfdec;
+    pic_ctx->out_media->Release();
+    static_assert(offsetof(mf_d3d11_pic_ctx, ctx.s) == 0, "Cast assumption failure");
+    d3d11_pic_context_destroy(ctx);
+    mfdec->Release();
+}
+
+static picture_context_t *d3d11mf_pic_context_copy(picture_context_t *ctx)
+{
+    mf_d3d11_pic_ctx *src_ctx = MF_D3D11_PICCONTEXT_FROM_PICCTX(ctx);
+    mf_d3d11_pic_ctx *pic_ctx = static_cast<mf_d3d11_pic_ctx *>(malloc(sizeof(*pic_ctx)));
+    if (unlikely(pic_ctx==nullptr))
+        return nullptr;
+    *pic_ctx = *src_ctx;
+    vlc_video_context_Hold(pic_ctx->ctx.s.vctx);
+    pic_ctx->out_media->AddRef();
+    pic_ctx->mfdec->AddRef();
+    for (int i=0;i<DXGI_MAX_SHADER_VIEW; i++)
+    {
+        pic_ctx->ctx.picsys.resource[i]  = src_ctx->ctx.picsys.resource[i];
+        pic_ctx->ctx.picsys.renderSrc[i] = src_ctx->ctx.picsys.renderSrc[i];
+    }
+    AcquireD3D11PictureSys(&pic_ctx->ctx.picsys);
+    return &pic_ctx->ctx.s;
+}
+
+static mf_d3d11_pic_ctx *CreatePicContext(ID3D11Texture2D *texture, UINT slice,
+                                          ComPtr<IMFMediaBuffer> &media_buffer,
+                                          decoder_sys_t *mfdec,
+                                          ID3D11ShaderResourceView *renderSrc[DXGI_MAX_SHADER_VIEW],
+                                          vlc_video_context *vctx)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    mf_d3d11_pic_ctx *pic_ctx = static_cast<mf_d3d11_pic_ctx *>(calloc(1, sizeof(*pic_ctx)));
+    if (unlikely(pic_ctx==nullptr))
+        return nullptr;
+
+    media_buffer.CopyTo(&pic_ctx->out_media);
+    pic_ctx->mfdec = mfdec;
+    pic_ctx->mfdec->AddRef();
+
+    pic_ctx->ctx.s.copy = d3d11mf_pic_context_copy;
+    pic_ctx->ctx.s.destroy = d3d11mf_pic_context_destroy;
+    pic_ctx->ctx.s.vctx = vlc_video_context_Hold(vctx);
+
+    pic_ctx->ctx.picsys.slice_index = slice;
+    for (int i=0;i<DXGI_MAX_SHADER_VIEW; i++)
+    {
+        pic_ctx->ctx.picsys.texture[i] = texture;
+        pic_ctx->ctx.picsys.renderSrc[i] = renderSrc ? renderSrc[i] : NULL;
+    }
+    AcquireD3D11PictureSys(&pic_ctx->ctx.picsys);
+    return pic_ctx;
+}
+
+static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id, bool & keep_reading)
+{
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
-    picture_t *picture = NULL;
-    block_t *aout_buffer = NULL;
 
     DWORD output_status = 0;
-    MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL };
-    hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status);
+    MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample.Get(), 0, NULL };
+    hr = p_sys->mft->ProcessOutput(0, 1, &output_buffer, &output_status);
     if (output_buffer.pEvents)
-        IMFCollection_Release(output_buffer.pEvents);
-    /* Use the returned sample since it can be provided by the MFT. */
-    IMFSample *output_sample = output_buffer.pSample;
-    IMFMediaBuffer *output_media_buffer = NULL;
+        output_buffer.pEvents->Release();
 
-    *keep_reading = false;
+    keep_reading = false;
     if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
         return VLC_SUCCESS;
 
-    if (hr == S_OK)
+    if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET)
     {
-        if (!output_sample)
-            return VLC_SUCCESS;
+        if (SetOutputType(p_dec, p_sys->output_stream_id))
+            return VLC_EGENERIC;
 
-        LONGLONG sample_time;
-        hr = IMFSample_GetSampleTime(output_sample, &sample_time);
-        if (FAILED(hr))
-            goto error;
-        /* Convert from 100 nanoseconds unit to microseconds. */
-        vlc_tick_t samp_time = VLC_TICK_FROM_MSFTIME(sample_time);
+        /* Reallocate output sample. */
+        if (AllocateOutputSample(p_dec, p_sys->output_stream_id, p_sys->output_sample))
+            return VLC_EGENERIC;
+        // there's an output ready, keep trying
+        keep_reading = hr == MF_E_TRANSFORM_STREAM_CHANGE;
+        return VLC_SUCCESS;
+    }
+
+    /* An error not listed above occurred */
+    if (FAILED(hr))
+    {
+        msg_Dbg(p_dec, "Failed to process output stream %lu (error 0x%lX)", stream_id, hr);
+        return VLC_EGENERIC;
+    }
 
-        DWORD output_count = 0;
-        hr = IMFSample_GetBufferCount(output_sample, &output_count);
-        if (unlikely(FAILED(hr)))
+    if (output_buffer.pSample == nullptr)
+        return VLC_SUCCESS;
+
+    LONGLONG sample_time;
+    hr = output_buffer.pSample->GetSampleTime(&sample_time);
+    if (FAILED(hr))
+        return VLC_EGENERIC;
+    /* Convert from 100 nanoseconds unit to vlc ticks. */
+    vlc_tick_t samp_time = VLC_TICK_FROM_MSFTIME(sample_time);
+
+    DWORD output_count = 0;
+    hr = output_buffer.pSample->GetBufferCount(&output_count);
+    if (unlikely(FAILED(hr)))
+        return VLC_EGENERIC;
+
+    ComPtr<IMFSample> output_sample = output_buffer.pSample;
+
+    for (DWORD buf_index = 0; buf_index < output_count; buf_index++)
+    {
+        picture_t *picture = NULL;
+        ComPtr<IMFMediaBuffer> output_media_buffer;
+        hr = output_sample->GetBufferByIndex(buf_index, output_media_buffer.GetAddressOf());
+        if (FAILED(hr))
             goto error;
 
-        for (DWORD buf_index = 0; buf_index < output_count; buf_index++)
+        if (p_dec->fmt_in.i_cat == VIDEO_ES)
         {
-            hr = IMFSample_GetBufferByIndex(output_sample, buf_index, &output_media_buffer);
-            if (FAILED(hr))
-                goto error;
-
-            if (p_dec->fmt_in.i_cat == VIDEO_ES)
+            mf_d3d11_pic_ctx *pic_ctx = nullptr;
+            UINT sliceIndex = 0;
+            ComPtr<IMFDXGIBuffer> spDXGIBuffer;
+            hr = output_media_buffer.As(&spDXGIBuffer);
+            if (SUCCEEDED(hr))
             {
-                if (decoder_UpdateVideoFormat(p_dec))
-                    return VLC_SUCCESS;
-                picture = decoder_NewPicture(p_dec);
-                if (!picture)
-                    return VLC_SUCCESS;
-
-                UINT32 interlaced = false;
-                hr = IMFSample_GetUINT32(output_sample, &MFSampleExtension_Interlaced, &interlaced);
-                if (FAILED(hr))
-                    picture->b_progressive = true;
-                else
-                    picture->b_progressive = !interlaced;
+                ID3D11Texture2D *d3d11Res;
+                void *pv;
+                hr = spDXGIBuffer->GetResource(__uuidof(d3d11Res), &pv);
+                if (SUCCEEDED(hr))
+                {
+                    d3d11Res = static_cast<ID3D11Texture2D *>(pv);
+                    hr = spDXGIBuffer->GetSubresourceIndex(&sliceIndex);
+                    if (!p_sys->vctx_out)
+                    {
+                        vlc_decoder_device *dec_dev = decoder_GetDecoderDevice(p_dec);
+                        d3d11_decoder_device_t *dev_sys = GetD3D11OpaqueDevice(dec_dev);
+                        if (dev_sys != NULL)
+                        {
+                            D3D11_TEXTURE2D_DESC desc;
+                            d3d11Res->GetDesc(&desc);
+
+                            p_sys->vctx_out = D3D11CreateVideoContext( dec_dev, desc.Format );
+                            vlc_decoder_device_Release(dec_dev);
+                            if (unlikely(p_sys->vctx_out == NULL))
+                            {
+                                msg_Err(p_dec, "failed to create a video context");
+                                d3d11Res->Release();
+                                return VLC_EGENERIC;
+                            }
+                            p_dec->fmt_out.video.i_width = desc.Width;
+                            p_dec->fmt_out.video.i_height = desc.Height;
+
+                            const d3d_format_t *cfg = nullptr;
+                            for (const d3d_format_t *output_format = DxgiGetRenderFormatList();
+                                    output_format->name != NULL; ++output_format)
+                            {
+                                if (output_format->formatTexture == desc.Format &&
+                                    is_d3d11_opaque(output_format->fourcc))
+                                {
+                                    cfg = output_format;
+                                    break;
+                                }
+                            }
+
+                            p_dec->fmt_out.i_codec = cfg->fourcc;
+                            p_dec->fmt_out.video.i_chroma = cfg->fourcc;
+
+                            // pre allocate all the SRV for that texture
+                            for (size_t slice=0; slice < desc.ArraySize; slice++)
+                            {
+                                ID3D11Texture2D *tex[DXGI_MAX_SHADER_VIEW] = {
+                                    d3d11Res, d3d11Res, d3d11Res, d3d11Res
+                                };
+
+                                if (D3D11_AllocateResourceView(p_dec, dev_sys->d3d_dev.d3ddevice, cfg, tex, slice, p_sys->cachedSRV[slice]) != VLC_SUCCESS)
+                                {
+                                    d3d11Res->Release();
+                                    goto error;
+                                }
+                            }
+                            p_sys->cached_tex = d3d11Res;
+                        }
+                    }
+                    else if (p_sys->cached_tex.Get() != d3d11Res)
+                    {
+                        msg_Err(p_dec, "separate texture not supported");
+                        d3d11Res->Release();
+                        goto error;
+                    }
+
+                    pic_ctx = CreatePicContext(d3d11Res, sliceIndex, output_media_buffer, p_sys, p_sys->cachedSRV[sliceIndex], p_sys->vctx_out);
+                    d3d11Res->Release();
+
+                    if (unlikely(pic_ctx == nullptr))
+                        goto error;
+                }
+            }
 
-                picture->date = samp_time;
+            if (decoder_UpdateVideoOutput(p_dec, p_sys->vctx_out))
+            {
+                if (pic_ctx)
+                    d3d11mf_pic_context_destroy(&pic_ctx->ctx.s);
+                return VLC_EGENERIC;
+            }
 
-                BYTE *buffer_start;
-                hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL);
-                if (FAILED(hr))
-                    goto error;
+            picture = decoder_NewPicture(p_dec);
+            if (!picture)
+            {
+                if (pic_ctx)
+                    d3d11mf_pic_context_destroy(&pic_ctx->ctx.s);
+                return VLC_EGENERIC;
+            }
 
-                CopyPackedBufferToPicture(picture, buffer_start);
+            UINT32 interlaced = false;
+            hr = output_sample->GetUINT32(MFSampleExtension_Interlaced, &interlaced);
+            if (FAILED(hr))
+                picture->b_progressive = true;
+            else
+                picture->b_progressive = !interlaced;
 
-                hr = IMFMediaBuffer_Unlock(output_media_buffer);
-                if (FAILED(hr))
-                    goto error;
+            picture->date = samp_time;
 
-                decoder_QueueVideo(p_dec, picture);
+            if (pic_ctx)
+            {
+                picture->context = &pic_ctx->ctx.s;
             }
             else
             {
-                if (decoder_UpdateAudioFormat(p_dec))
-                    goto error;
-                if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0)
-                    goto error;
+            BYTE *buffer_start;
+            hr = output_media_buffer->Lock(&buffer_start, NULL, NULL);
+            if (FAILED(hr))
+            {
+                picture_Release(picture);
+                goto error;
+            }
 
-                DWORD total_length = 0;
-                hr = IMFSample_GetTotalLength(output_sample, &total_length);
-                if (FAILED(hr))
-                    goto error;
+            CopyPackedBufferToPicture(picture, buffer_start);
 
-                int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8);
-                aout_buffer = decoder_NewAudioBuffer(p_dec, samples);
-                if (!aout_buffer)
-                    return VLC_SUCCESS;
-                if (aout_buffer->i_buffer < total_length)
-                    goto error;
+            hr = output_media_buffer->Unlock();
+            if (FAILED(hr))
+            {
+                picture_Release(picture);
+                goto error;
+            }
+            }
 
-                aout_buffer->i_pts = samp_time;
+            decoder_QueueVideo(p_dec, picture);
+        }
+        else
+        {
+            block_t *aout_buffer = NULL;
+            if (decoder_UpdateAudioFormat(p_dec))
+                goto error;
+            if (p_dec->fmt_out.audio.i_bitspersample == 0 || p_dec->fmt_out.audio.i_channels == 0)
+                goto error;
 
-                BYTE *buffer_start;
-                hr = IMFMediaBuffer_Lock(output_media_buffer, &buffer_start, NULL, NULL);
-                if (FAILED(hr))
-                    goto error;
+            DWORD total_length = 0;
+            hr = output_media_buffer->GetCurrentLength(&total_length);
+            if (FAILED(hr))
+                goto error;
 
-                memcpy(aout_buffer->p_buffer, buffer_start, total_length);
+            int samples = total_length / (p_dec->fmt_out.audio.i_bitspersample * p_dec->fmt_out.audio.i_channels / 8);
+            aout_buffer = decoder_NewAudioBuffer(p_dec, samples);
+            if (!aout_buffer)
+                return VLC_SUCCESS;
+            if (aout_buffer->i_buffer < total_length)
+            {
+                block_Release(aout_buffer);
+                goto error;
+            }
 
-                hr = IMFMediaBuffer_Unlock(output_media_buffer);
-                if (FAILED(hr))
-                    goto error;
+            aout_buffer->i_pts = samp_time;
 
-                decoder_QueueAudio(p_dec, aout_buffer);
+            BYTE *buffer_start;
+            hr = output_media_buffer->Lock(&buffer_start, NULL, NULL);
+            if (FAILED(hr))
+            {
+                block_Release(aout_buffer);
+                goto error;
             }
 
-            if (p_sys->output_sample)
+            memcpy(aout_buffer->p_buffer, buffer_start, total_length);
+
+            hr = output_media_buffer->Unlock();
+            if (FAILED(hr))
             {
-                /* Sample is not provided by the MFT: clear its content. */
-                hr = IMFMediaBuffer_SetCurrentLength(output_media_buffer, 0);
-                if (FAILED(hr))
-                    goto error;
+                block_Release(aout_buffer);
+                goto error;
             }
 
-            IMFMediaBuffer_Release(output_media_buffer);
-            output_media_buffer = NULL;
+            decoder_QueueAudio(p_dec, aout_buffer);
         }
 
-        if (!p_sys->output_sample)
+        if (p_sys->output_sample.Get())
         {
-            /* Sample is provided by the MFT: decrease refcount. */
-            IMFSample_Release(output_sample);
+            /* Sample is not provided by the MFT: clear its content. */
+            hr = output_media_buffer->SetCurrentLength(0);
+            if (FAILED(hr))
+                goto error;
         }
-
-        *keep_reading = true;
-        return VLC_SUCCESS;
     }
 
-    if (hr == MF_E_TRANSFORM_STREAM_CHANGE || hr == MF_E_TRANSFORM_TYPE_NOT_SET)
+    if (p_sys->output_sample.Get() == nullptr)
     {
-        if (p_sys->output_type)
-            IMFMediaType_Release(p_sys->output_type);
-        if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
-            goto error;
-
-        /* Reallocate output sample. */
-        if (p_sys->output_sample)
-        {
-            IMFSample_Release(p_sys->output_sample);
-            p_sys->output_sample = NULL;
-        }
-        if (AllocateOutputSample(p_dec, p_sys->output_stream_id, &p_sys->output_sample))
-            goto error;
-        // there's an output ready, keep trying
-        *keep_reading = hr == MF_E_TRANSFORM_STREAM_CHANGE;
-        return VLC_SUCCESS;
+        /* Sample is provided by the MFT: decrease refcount. */
+        output_sample->Release();
     }
 
-    /* An error not listed above occurred */
-    msg_Dbg(p_dec, "Failed to process output stream %lu (error 0x%lX)", stream_id, hr);
+    keep_reading = true;
+    return VLC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in ProcessOutputStream()");
-    if (output_media_buffer)
-        IMFMediaBuffer_Release(output_media_buffer);
-    if (picture)
-        picture_Release(picture);
-    if (aout_buffer)
-        block_Release(aout_buffer);
     return VLC_EGENERIC;
 }
 
 static void Flush(decoder_t *p_dec)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    HRESULT hr;
-
-    hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_COMMAND_FLUSH, 0);
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
+    p_sys->flushStream();
 }
 
 static int DecodeSync(decoder_t *p_dec, block_t *p_block)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
 
     if (p_block && p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
     {
@@ -871,7 +1126,7 @@ static int DecodeSync(decoder_t *p_dec, block_t *p_block)
     if (p_block == NULL)
     {
         HRESULT hr;
-        hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_COMMAND_DRAIN, 0);
+        hr = p_sys->mft->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
         if (FAILED(hr))
             return VLC_EGENERIC;
     }
@@ -880,7 +1135,7 @@ static int DecodeSync(decoder_t *p_dec, block_t *p_block)
     bool keep_reading;
     int err;
     do {
-        err = ProcessOutputStream(p_dec, p_sys->output_stream_id, &keep_reading);
+        err = ProcessOutputStream(p_dec, p_sys->output_stream_id, keep_reading);
     } while (err == VLC_SUCCESS && keep_reading);
     if (err != VLC_SUCCESS)
         goto error;
@@ -902,16 +1157,15 @@ error:
 
 static HRESULT DequeueMediaEvent(decoder_t *p_dec)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    IMFMediaEvent *event = NULL;
-    hr = IMFMediaEventGenerator_GetEvent(p_sys->event_generator, MF_EVENT_FLAG_NO_WAIT, &event);
+    ComPtr<IMFMediaEvent> event;
+    hr = p_sys->event_generator->GetEvent(MF_EVENT_FLAG_NO_WAIT, event.GetAddressOf());
     if (FAILED(hr))
         return hr;
     MediaEventType event_type;
-    hr = IMFMediaEvent_GetType(event, &event_type);
-    IMFMediaEvent_Release(event);
+    hr = event->GetType(&event_type);
     if (FAILED(hr))
         return hr;
 
@@ -927,7 +1181,7 @@ static HRESULT DequeueMediaEvent(decoder_t *p_dec)
 
 static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
     if (!p_block) /* No Drain */
@@ -952,7 +1206,7 @@ static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
         bool keep_reading;
         int err;
         do {
-            err = ProcessOutputStream(p_dec, p_sys->output_stream_id, &keep_reading);
+            err = ProcessOutputStream(p_dec, p_sys->output_stream_id, keep_reading);
         } while (err == VLC_SUCCESS && keep_reading);
         if (err != VLC_SUCCESS)
             goto error;
@@ -977,7 +1231,7 @@ static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
             bool keep_reading;
             int err;
             do {
-                err = ProcessOutputStream(p_dec, p_sys->output_stream_id, &keep_reading);
+                err = ProcessOutputStream(p_dec, p_sys->output_stream_id, keep_reading);
             } while (err == VLC_SUCCESS && keep_reading);
             if (err != VLC_SUCCESS)
                 goto error;
@@ -1001,38 +1255,59 @@ error:
 
 static void DestroyMFT(decoder_t *p_dec);
 
+static int SetD3D11(decoder_t *p_dec, d3d11_device_t *d3d_dev)
+{
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
+    HRESULT hr;
+    hr = p_sys->fptr_MFCreateDXGIDeviceManager(&p_sys->dxgi_token, p_sys->dxgi_manager.GetAddressOf());
+    if (FAILED(hr))
+        return VLC_EGENERIC;
+
+    hr = p_sys->dxgi_manager->ResetDevice(d3d_dev->d3ddevice, p_sys->dxgi_token);
+    if (FAILED(hr))
+        return VLC_EGENERIC;
+
+    hr = p_sys->dxgi_manager->OpenDeviceHandle(&p_sys->d3d_handle);
+    if (FAILED(hr))
+        return VLC_EGENERIC;
+
+    hr = p_sys->mft->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)p_sys->dxgi_manager.Get());
+    if (FAILED(hr))
+        return VLC_EGENERIC;
+
+    return VLC_SUCCESS;
+}
+
 static int InitializeMFT(decoder_t *p_dec)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
-    IMFAttributes *attributes = NULL;
-    hr = IMFTransform_GetAttributes(p_sys->mft, &attributes);
+    ComPtr<IMFAttributes> attributes;
+    hr = p_sys->mft->GetAttributes(attributes.GetAddressOf());
     if (hr != E_NOTIMPL && FAILED(hr))
         goto error;
     if (SUCCEEDED(hr))
     {
         UINT32 is_async = false;
-        hr = IMFAttributes_GetUINT32(attributes, &MF_TRANSFORM_ASYNC, &is_async);
+        hr = attributes->GetUINT32(MF_TRANSFORM_ASYNC, &is_async);
         if (hr != MF_E_ATTRIBUTENOTFOUND && FAILED(hr))
             goto error;
         p_sys->is_async = is_async;
         if (p_sys->is_async)
         {
-            hr = IMFAttributes_SetUINT32(attributes, &MF_TRANSFORM_ASYNC_UNLOCK, true);
+            hr = attributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, true);
             if (FAILED(hr))
                 goto error;
-            void *pv;
-            hr = IMFTransform_QueryInterface(p_sys->mft, &IID_IMFMediaEventGenerator, &pv);
+            hr = p_sys->mft.As(&p_sys->event_generator);
             if (FAILED(hr))
                 goto error;
-            p_sys->event_generator = pv;
         }
     }
 
     DWORD input_streams_count;
     DWORD output_streams_count;
-    hr = IMFTransform_GetStreamCount(p_sys->mft, &input_streams_count, &output_streams_count);
+    hr = p_sys->mft->GetStreamCount(&input_streams_count, &output_streams_count);
     if (FAILED(hr))
         goto error;
     if (input_streams_count != 1 || output_streams_count != 1)
@@ -1041,7 +1316,7 @@ static int InitializeMFT(decoder_t *p_dec)
         goto error;
     }
 
-    hr = IMFTransform_GetStreamIDs(p_sys->mft, 1, &p_sys->input_stream_id, 1, &p_sys->output_stream_id);
+    hr = p_sys->mft->GetStreamIDs(1, &p_sys->input_stream_id, 1, &p_sys->output_stream_id);
     if (hr == E_NOTIMPL)
     {
         /*
@@ -1056,34 +1331,67 @@ static int InitializeMFT(decoder_t *p_dec)
     else if (FAILED(hr))
         goto error;
 
-    if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type))
+    if (SetInputType(p_dec, p_sys->input_stream_id, p_sys->input_type))
         goto error;
 
-    if (SetOutputType(p_dec, p_sys->output_stream_id, &p_sys->output_type))
+    if (attributes.Get() && p_dec->fmt_in.i_cat == VIDEO_ES)
+    {
+        if (p_sys->fptr_MFCreateDXGIDeviceManager)
+        {
+            vlc_decoder_device *dec_dev = decoder_GetDecoderDevice(p_dec);
+            if (dec_dev != nullptr)
+            {
+                d3d11_decoder_device_t *devsys11 = GetD3D11OpaqueDevice(dec_dev);
+                if (devsys11 != nullptr)
+                {
+                    UINT32 can_d3d11;
+                    hr = attributes->GetUINT32(MF_SA_D3D11_AWARE, &can_d3d11);
+                    if (SUCCEEDED(hr) && can_d3d11)
+                    {
+                        SetD3D11(p_dec, &devsys11->d3d_dev);
+
+                        IMFAttributes *outputAttr = NULL;
+                        hr = p_sys->mft->GetOutputStreamAttributes(p_sys->output_stream_id, &outputAttr);
+                        if (SUCCEEDED(hr))
+                        {
+                            hr = outputAttr->SetUINT32(MF_SA_D3D11_BINDFLAGS, D3D11_BIND_SHADER_RESOURCE);
+                        }
+                    }
+                }
+                vlc_decoder_device_Release(dec_dev);
+            }
+        }
+    }
+
+    if (SetOutputType(p_dec, p_sys->output_stream_id))
         goto error;
 
     /*
      * The input type was not set by the previous call to
      * SetInputType, try again after setting the output type.
      */
-    if (!p_sys->input_type)
-        if (SetInputType(p_dec, p_sys->input_stream_id, &p_sys->input_type) || !p_sys->input_type)
+    if (p_sys->input_type.Get() == nullptr)
+        if (SetInputType(p_dec, p_sys->input_stream_id, p_sys->input_type) || p_sys->input_type.Get() == nullptr)
             goto error;
 
     /* This call can be a no-op for some MFT decoders, but it can potentially reduce starting time. */
-    hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, (ULONG_PTR)0);
+    hr = p_sys->beginStreaming();
     if (FAILED(hr))
         goto error;
 
     /* This event is required for asynchronous MFTs, optional otherwise. */
-    hr = IMFTransform_ProcessMessage(p_sys->mft, MFT_MESSAGE_NOTIFY_START_OF_STREAM, (ULONG_PTR)0);
+    hr = p_sys->startStream();
     if (FAILED(hr))
         goto error;
 
-    if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
+    if (attributes.Get() && p_dec->fmt_in.i_codec == VLC_CODEC_H264)
     {
         /* It's not an error if the following call fails. */
-        IMFAttributes_SetUINT32(attributes, &CODECAPI_AVLowLatencyMode, true);
+#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
+        attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE);
+#else
+        attributes->SetUINT32(MF_LOW_LATENCY, TRUE);
+#endif
 
         hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec), p_dec->fmt_in.i_codec, 0, 0);
         hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
@@ -1098,35 +1406,18 @@ error:
 
 static void DestroyMFT(decoder_t *p_dec)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
 
-    if (p_sys->event_generator)
-        IMFMediaEventGenerator_Release(p_sys->event_generator);
-    if (p_sys->input_type)
-        IMFMediaType_Release(p_sys->input_type);
-    if (p_sys->output_sample)
-    {
-        IMFSample_RemoveAllBuffers(p_sys->output_sample);
-    }
-    if (p_sys->output_type)
-        IMFMediaType_Release(p_sys->output_type);
-    if (p_sys->mft)
-        IMFTransform_Release(p_sys->mft);
+    if (p_sys->mft.Get())
+        p_sys->endStream();
 
     if (p_dec->fmt_in.i_codec == VLC_CODEC_H264)
         hxxx_helper_clean(&p_sys->hh);
-
-    p_sys->event_generator = NULL;
-    p_sys->input_type = NULL;
-    p_sys->output_type = NULL;
-    p_sys->mft = NULL;
-
-    MFShutdown();
 }
 
 static int FindMFT(decoder_t *p_dec)
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
     HRESULT hr;
 
     /* Try to create a MFT using MFTEnumEx. */
@@ -1169,16 +1460,16 @@ static int FindMFT(decoder_t *p_dec)
     void *pv;
     for (UINT32 i = 0; i < activate_objects_count; ++i)
     {
-        hr = IMFActivate_ActivateObject(activate_objects[i], &IID_IMFTransform, &pv);
-        IMFActivate_Release(activate_objects[i]);
+        hr = activate_objects[i]->ActivateObject(__uuidof(p_sys->mft.Get()), &pv);
+        activate_objects[i]->Release();
         if (FAILED(hr))
             continue;
-        p_sys->mft = pv;
+        p_sys->mft = static_cast<IMFTransform *>(pv);
 
         if (InitializeMFT(p_dec) == VLC_SUCCESS)
         {
             for (++i; i < activate_objects_count; ++i)
-                IMFActivate_Release(activate_objects[i]);
+                activate_objects[i]->Release();
             CoTaskMemFree(activate_objects);
             return VLC_SUCCESS;
         }
@@ -1188,12 +1479,23 @@ static int FindMFT(decoder_t *p_dec)
     return VLC_EGENERIC;
 }
 
-static int LoadMFTLibrary()
+static int LoadMFTLibrary(decoder_sys_t *p_sys)
 {
     HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
     if (FAILED(hr))
         return VLC_EGENERIC;
 
+#if _WIN32_WINNT < _WIN32_WINNT_WIN8
+    HINSTANCE mfplat_dll = LoadLibrary(TEXT("mfplat.dll"));
+    if (mfplat_dll)
+    {
+        p_sys->fptr_MFCreateDXGIDeviceManager = (pf_MFCreateDXGIDeviceManager)GetProcAddress(mfplat_dll, "MFCreateDXGIDeviceManager");
+        // we still have the DLL automatically loaded after this
+        FreeLibrary(mfplat_dll);
+    }
+#else // Win8+
+    p_sys->fptr_MFCreateDXGIDeviceManager = &MFCreateDXGIDeviceManager;
+#endif // Win8+
 
     return VLC_SUCCESS;
 }
@@ -1203,21 +1505,21 @@ static int Open(vlc_object_t *p_this)
     decoder_t *p_dec = (decoder_t *)p_this;
     decoder_sys_t *p_sys;
 
-    p_sys = p_dec->p_sys = calloc(1, sizeof(*p_sys));
-    if (!p_sys)
+    p_sys = new (std::nothrow) decoder_sys_t();
+    if (unlikely(p_sys == nullptr))
         return VLC_ENOMEM;
+    p_dec->p_sys = p_sys;
 
     if( FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
     {
-        free(p_sys);
+        delete p_sys;
         return VLC_EGENERIC;
     }
 
-    if (LoadMFTLibrary())
+    if (LoadMFTLibrary(p_sys))
     {
         msg_Err(p_dec, "Failed to load MFT library.");
-        free(p_sys);
-        return VLC_EGENERIC;
+        goto error;
     }
 
     if (FindMFT(p_dec))
@@ -1227,7 +1529,7 @@ static int Open(vlc_object_t *p_this)
     }
 
     /* Only one output sample is needed, we can allocate one and reuse it. */
-    if (AllocateOutputSample(p_dec, p_sys->output_stream_id, &p_sys->output_sample))
+    if (AllocateOutputSample(p_dec, p_sys->output_stream_id, p_sys->output_sample))
         goto error;
 
     p_dec->pf_decode = p_sys->is_async ? DecodeAsync : DecodeSync;
@@ -1243,11 +1545,11 @@ error:
 static void Close(vlc_object_t *p_this)
 {
     decoder_t *p_dec = (decoder_t *)p_this;
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    decoder_sys_t *p_sys = static_cast<decoder_sys_t*>(p_dec->p_sys);
 
     DestroyMFT(p_dec);
 
-    free(p_sys);
+    p_sys->Release();
 
     CoUninitialize();
 }


=====================================
po/POTFILES.in
=====================================
@@ -315,7 +315,7 @@ modules/codec/libass.c
 modules/codec/libmpeg2.c
 modules/codec/lpcm.c
 modules/codec/mad.c
-modules/codec/mft.c
+modules/codec/mft.cpp
 modules/codec/mpg123.c
 modules/codec/oggspots.c
 modules/codec/omxil/mediacodec.c



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ae7d4a9f87b26622baf2fb945856f3a01b7e491f...a4445b326682bcca68e6b1278bda0beedf504aa7

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ae7d4a9f87b26622baf2fb945856f3a01b7e491f...a4445b326682bcca68e6b1278bda0beedf504aa7
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list