[vlc-devel] [PATCH] Support for loading any MFT in case video format is not found from the hardcoded list

Teemu Ikonen kunteemu at gmail.com
Sun Mar 4 19:29:49 CET 2018


Thanks, I took a look into avi.c and decided to remove the orientation hack.

Here is the modified patch. Change to previous is storing a flipped flag
that is used to choose
line order in buffer copy.

---
 modules/codec/mft.c | 110
++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 93 insertions(+), 17 deletions(-)

diff --git a/modules/codec/mft.c b/modules/codec/mft.c
index 24eaaa55cb..9ad000d2a8 100644
--- a/modules/codec/mft.c
+++ b/modules/codec/mft.c
@@ -92,6 +92,8 @@ struct decoder_sys_t

     const GUID* major_type;
     const GUID* subtype;
+    /* Container for a dynamically constructed subtype */
+    GUID custom_subtype;

     /* For asynchronous MFT */
     bool is_async;
@@ -102,6 +104,7 @@ struct decoder_sys_t
     /* Input stream */
     DWORD input_stream_id;
     IMFMediaType *input_type;
+    bool flipped;

     /* Output stream */
     DWORD output_stream_id;
@@ -183,6 +186,20 @@ static const pair_format_guid video_format_table[] =
     { 0, NULL }
 };

+// 8-bit luminance only
+DEFINE_MEDIATYPE_GUID (MFVideoFormat_L8, 50);
+
+/*
+ * Table to map MF Transform raw 3D3 output formats to native VLC FourCC
+ */
+static const pair_format_guid d3d_format_table[] = {
+    { VLC_CODEC_RGB32, &MFVideoFormat_RGB32  },
+    { VLC_CODEC_RGB24, &MFVideoFormat_RGB24  },
+    { VLC_CODEC_RGBA,  &MFVideoFormat_ARGB32 },
+    { VLC_CODEC_GREY,  &MFVideoFormat_L8     },
+    { 0, NULL }
+};
+
 #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4
 DEFINE_GUID(MFAudioFormat_Dolby_AC3, 0xe06d802c, 0xdb46, 0x11cf, 0xb4,
0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea);
 #endif
@@ -210,6 +227,15 @@ 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)
+{
+    for (int i = 0; table[i].fourcc; ++i)
+        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
@@ -272,6 +298,16 @@ static int SetInputType(decoder_t *p_dec, DWORD
stream_id, IMFMediaType **result
         hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_SIZE,
frame_size);
         if (FAILED(hr))
             goto error;
+
+        /* Some transforms like to know the frame rate and may reject the
input type otherwise. */
+        UINT64 frame_ratio_num = p_dec->fmt_in.video.i_frame_rate;
+        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);
+            if(FAILED(hr))
+                goto error;
+        }
     }
     else
     {
@@ -356,7 +392,7 @@ static int SetOutputType(decoder_t *p_dec, DWORD
stream_id, IMFMediaType **resul
      * preference thus we will use the first one unless YV12/I420 is
      * available for video or float32 for audio.
      */
-    int output_type_index = 0;
+    int output_type_index = -1;
     bool found = false;
     for (int i = 0; !found; ++i)
     {
@@ -380,6 +416,10 @@ static int SetOutputType(decoder_t *p_dec, DWORD
stream_id, IMFMediaType **resul
         {
             if (IsEqualGUID(&subtype, &MFVideoFormat_YV12) ||
IsEqualGUID(&subtype, &MFVideoFormat_I420))
                 found = true;
+            /* Transform might offer output in a D3DFMT propietary 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)
+                    output_type_index = i;
         }
         else
         {
@@ -399,9 +439,12 @@ static int SetOutputType(decoder_t *p_dec, DWORD
stream_id, IMFMediaType **resul
     }
     /*
      * It's not an error if we don't find the output type we were
-     * looking for, in this case we use the first available type which
-     * is the "preferred" output type for this MFT.
+     * looking for, in this case we use the first available type.
      */
+    if(output_type_index < 0)
+        /* No output format found we prefer, just pick the first one
preferred
+         * by the MFT */
+        output_type_index = 0;

     hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id,
output_type_index, &output_media_type);
     if (FAILED(hr))
@@ -416,10 +459,21 @@ static int SetOutputType(decoder_t *p_dec, DWORD
stream_id, IMFMediaType **resul
     if (FAILED(hr))
         goto error;

+    p_sys->flipped = false;
     if (p_dec->fmt_in.i_cat == VIDEO_ES)
     {
         video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video );
-        p_dec->fmt_out.i_codec = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat,
subtype.Data1);
+
+        /* Transform might offer output in a D3DFMT propietary FCC */
+        vlc_fourcc_t fcc = GUIDToFormat(d3d_format_table, &subtype);
+        if(fcc) {
+            /* D3D formats are upside down */
+            p_sys->flipped = true;
+        } else {
+            fcc = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat, subtype.Data1);
+        }
+
+        p_dec->fmt_out.i_codec = fcc;
     }
     else
     {
@@ -620,26 +674,42 @@ error:
 }

 /* Copy a packed buffer (no padding) to a picture_t */
-static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t
*p_src)
+static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t
*p_src, bool flip)
 {
     for (int i = 0; i < p_pic->i_planes; ++i)
     {
         uint8_t *p_dst = p_pic->p[i].p_pixels;

-        if (p_pic->p[i].i_visible_pitch == p_pic->p[i].i_pitch)
+        if(flip)
         {
-            /* Plane is packed, only one memcpy is needed. */
-            uint32_t plane_size = p_pic->p[i].i_pitch *
p_pic->p[i].i_visible_lines;
-            memcpy(p_dst, p_src, plane_size);
-            p_src += plane_size;
-            continue;
-        }
+            /* Point p_src to the end of data. */
+            p_src += p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines;

-        for (int i_line = 0; i_line < p_pic->p[i].i_visible_lines;
i_line++)
+            for (int i_line = 0; i_line < p_pic->p[i].i_visible_lines;
i_line++)
+            {
+                /* Point to start of row */
+                p_src -= p_pic->p[i].i_pitch;
+                memcpy(p_dst, p_src, p_pic->p[i].i_visible_pitch);
+                p_dst += p_pic->p[i].i_visible_pitch;
+            }
+        }
+        else
         {
-            memcpy(p_dst, p_src, p_pic->p[i].i_visible_pitch);
-            p_src += p_pic->p[i].i_visible_pitch;
-            p_dst += p_pic->p[i].i_pitch;
+            if (p_pic->p[i].i_visible_pitch == p_pic->p[i].i_pitch)
+            {
+                /* Plane is packed, only one memcpy is needed. */
+                uint32_t plane_size = p_pic->p[i].i_pitch *
p_pic->p[i].i_visible_lines;
+                memcpy(p_dst, p_src, plane_size);
+                p_src += plane_size;
+                continue;
+            }
+
+            for (int i_line = 0; i_line < p_pic->p[i].i_visible_lines;
i_line++)
+            {
+                memcpy(p_dst, p_src, p_pic->p[i].i_visible_pitch);
+                p_src += p_pic->p[i].i_pitch;
+                p_dst += p_pic->p[i].i_visible_pitch;
+            }
         }
     }
 }
@@ -715,7 +785,7 @@ static int ProcessOutputStream(decoder_t *p_dec, DWORD
stream_id)
             goto error;

         if (p_dec->fmt_in.i_cat == VIDEO_ES)
-            CopyPackedBufferToPicture(picture, buffer_start);
+            CopyPackedBufferToPicture(picture, buffer_start,
p_sys->flipped);
         else
             memcpy(aout_buffer->p_buffer, buffer_start, total_length);

@@ -1046,6 +1116,12 @@ static int FindMFT(decoder_t *p_dec)
         category = MFT_CATEGORY_VIDEO_DECODER;
         p_sys->major_type = &MFMediaType_Video;
         p_sys->subtype = FormatToGUID(video_format_table,
p_dec->fmt_in.i_codec);
+        if(!p_sys->subtype) {
+            /* Codec is not well known. Construct a MF transform subtype
from the fourcc */
+            p_sys->custom_subtype = MFVideoFormat_Base;
+            p_sys->custom_subtype.Data1 = p_dec->fmt_in.i_codec;
+            p_sys->subtype = &p_sys->custom_subtype;
+        }
     }
     else
     {
-- 
2.14.1


On Sun, Mar 4, 2018 at 5:45 PM, Jean-Baptiste Kempf <jb at videolan.org> wrote:

> Hello,
>
> On Sun, 4 Mar 2018, at 15:11, Teemu Ikonen wrote:
>
>
> On Sun, Mar 4, 2018 at 2:06 PM, Jean-Baptiste Kempf <jb at videolan.org>
> wrote:
>
>
> Hello,
>
>
> On Sun, 4 Mar 2018, at 11:53, Teemu Ikonen wrote:
>
> Adds support in Media Foundation (MFT) module to use decoders whose FCC is
> not found from the hardcoded list. Improves compatibility and adds support
> for common uncompressed formats decoders might prefer.
>
>
>
> This looks cool, but how do you have examples of such things?
>
>
> Typical use case for them is to allow Windows Media Player to play videos
> with custom vendor codecs (camera and instrument manufacturers, research,
> ..).
> I've done few decoders to support Windows Media Player to play formats
> (e.g. Y800) and noticed it would be easy to extend VLC mft module to use
> any MFT compatible decoder instead of only ones in the hardcoded list.
> (H264, WM9, ..).
>
>
> Sure, but I thought maybe you had more precise examples than Y800 (which
> is just a pixel format, IIRC).
>
> But ok.
>
> Internal formats (like MFVideoFormat_RGB32) are bottom up (negative
> stride). Code just changes the to ORIENT_BOTTOM_LEFT in this case and it
> works, but is this the right thing do?
>
>
> Did you look at the avi code?
>
>
> No. I know that the bitmapinfo header member biHeight in AVI stream format
> can define the orientation but not sure how it applies. AFAIK it's ignored
> if payload FCC is anything else than 'DIB '.
>
>
> In modules/demux/avi/avi.c, we memcpy line by line in those cases (l. 967).
>
> ORIENT should work, though, but not in all cases (transcoding, maybe)
>
> This is more a problem of mapping raw RGB format of MF decoder to VLC RGB
> format. Microsoft recommends that MFT Decoders support NV12 as common
> format but it's optional and custom decoder probably outputs just raw RGB
> that works fine and all the example code does that.
>
>
> Seems good to me.
>
> Thank you for the interest!
>
>
> Thanks for your work.
>
> Best,
>
>
>
>
>
> Best,
>
>
> ---
>  modules/codec/mft.c | 66 ++++++++++++++++++++++++++++++
> +++++++++++++++++++----
>  1 file changed, 62 insertions(+), 4 deletions(-)
>
> diff --git a/modules/codec/mft.c b/modules/codec/mft.c
> index 24eaaa55cb..3cf6aa494d 100644
> --- a/modules/codec/mft.c
> +++ b/modules/codec/mft.c
> @@ -92,6 +92,8 @@ struct decoder_sys_t
>
>      const GUID* major_type;
>      const GUID* subtype;
> +    /* Container for a dynamically constructed subtype */
> +    GUID custom_subtype;
>
>      /* For asynchronous MFT */
>      bool is_async;
> @@ -183,6 +185,20 @@ static const pair_format_guid video_format_table[] =
>      { 0, NULL }
>  };
>
> +// 8-bit luminance only
> +DEFINE_MEDIATYPE_GUID (MFVideoFormat_L8, 50);
> +
> +/*
> + * Table to map MF Transform raw 3D3 output formats to native VLC FourCC
> + */
> +static const pair_format_guid d3d_format_table[] = {
> +    { VLC_CODEC_RGB32, &MFVideoFormat_RGB32  },
> +    { VLC_CODEC_RGB24, &MFVideoFormat_RGB24  },
> +    { VLC_CODEC_RGBA,  &MFVideoFormat_ARGB32 },
> +    { VLC_CODEC_GREY,  &MFVideoFormat_L8     },
> +    { 0, NULL }
> +};
> +
>  #if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 4
>  DEFINE_GUID(MFAudioFormat_Dolby_AC3, 0xe06d802c, 0xdb46, 0x11cf, 0xb4,
> 0xd1, 0x00, 0x80, 0x5f, 0x6c, 0xbb, 0xea);
>  #endif
> @@ -210,6 +226,15 @@ 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)
> +{
> +    for (int i = 0; table[i].fourcc; ++i)
> +        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
> @@ -272,6 +297,16 @@ static int SetInputType(decoder_t *p_dec, DWORD
> stream_id, IMFMediaType **result
>          hr = IMFMediaType_SetUINT64(input_media_type, &MF_MT_FRAME_SIZE,
> frame_size);
>          if (FAILED(hr))
>              goto error;
> +
> +        /* Some transforms like to know the frame rate and may reject the
> input type otherwise. */
> +        UINT64 frame_ratio_num = p_dec->fmt_in.video.i_frame_rate;
> +        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);
> +            if(FAILED(hr))
> +                goto error;
> +        }
>      }
>      else
>      {
> @@ -356,7 +391,7 @@ static int SetOutputType(decoder_t *p_dec, DWORD
> stream_id, IMFMediaType **resul
>       * preference thus we will use the first one unless YV12/I420 is
>       * available for video or float32 for audio.
>       */
> -    int output_type_index = 0;
> +    int output_type_index = -1;
>      bool found = false;
>      for (int i = 0; !found; ++i)
>      {
> @@ -380,6 +415,10 @@ static int SetOutputType(decoder_t *p_dec, DWORD
> stream_id, IMFMediaType **resul
>          {
>              if (IsEqualGUID(&subtype, &MFVideoFormat_YV12) ||
> IsEqualGUID(&subtype, &MFVideoFormat_I420))
>                  found = true;
> +            /* Transform might offer output in a D3DFMT propietary 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)
> +                    output_type_index = i;
>          }
>          else
>          {
> @@ -399,9 +438,12 @@ static int SetOutputType(decoder_t *p_dec, DWORD
> stream_id, IMFMediaType **resul
>      }
>      /*
>       * It's not an error if we don't find the output type we were
> -     * looking for, in this case we use the first available type which
> -     * is the "preferred" output type for this MFT.
> +     * looking for, in this case we use the first available type.
>       */
> +    if(output_type_index < 0)
> +        /* No output format found we prefer, just pick the first one
> preferred
> +         * by the MFT */
> +        output_type_index = 0;
>
>      hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id,
> output_type_index, &output_media_type);
>      if (FAILED(hr))
> @@ -419,7 +461,17 @@ static int SetOutputType(decoder_t *p_dec, DWORD
> stream_id, IMFMediaType **resul
>      if (p_dec->fmt_in.i_cat == VIDEO_ES)
>      {
>          video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video );
> -        p_dec->fmt_out.i_codec = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat,
> subtype.Data1);
> +
> +        /* Transform might offer output in a D3DFMT propietary FCC */
> +        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;
> +        } else {
> +            fcc = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat,
> subtype.Data1);
> +        }
> +
> +        p_dec->fmt_out.i_codec = fcc;
>      }
>      else
>      {
> @@ -1046,6 +1098,12 @@ static int FindMFT(decoder_t *p_dec)
>          category = MFT_CATEGORY_VIDEO_DECODER;
>          p_sys->major_type = &MFMediaType_Video;
>          p_sys->subtype = FormatToGUID(video_format_table,
> p_dec->fmt_in.i_codec);
> +        if(!p_sys->subtype) {
> +            /* Codec is not well known. Construct a MF transform subtype
> from the fourcc */
> +            p_sys->custom_subtype = MFVideoFormat_Base;
> +            p_sys->custom_subtype.Data1 = p_dec->fmt_in.i_codec;
> +            p_sys->subtype = &p_sys->custom_subtype;
> +        }
>      }
>      else
>      {
> --
> 2.14.1
>
> *_______________________________________________*
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
>
>
> --
> Jean-Baptiste Kempf -  President
> +33 672 704 734
>
>
>
>
> --
> Jean-Baptiste Kempf -  President
> +33 672 704 734
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20180304/2c3941c1/attachment-0001.html>


More information about the vlc-devel mailing list