[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