• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "gstmfconfig.h"
26 
27 #include "gstmfutils.h"
28 #include <wrl.h>
29 
30 /* *INDENT-OFF* */
31 using namespace Microsoft::WRL;
32 
33 G_BEGIN_DECLS
34 
35 GST_DEBUG_CATEGORY_EXTERN (gst_mf_utils_debug);
36 #define GST_CAT_DEFAULT gst_mf_utils_debug
37 
38 G_END_DECLS
39 
40 #define MAKE_RAW_FORMAT_CAPS(format) \
41     "video/x-raw, format = (string) " format
42 
43 /* No GUID is defined for "Y16 " in mfapi.h, but it's used by several devices */
44 DEFINE_MEDIATYPE_GUID (MFVideoFormat_Y16, FCC ('Y16 '));
45 
46 static struct
47 {
48   const GUID &mf_format;
49   const gchar *caps_string;
50   GstVideoFormat format;
51 } raw_video_format_map[] = {
52   /* NOTE: when adding new format, gst_mf_update_video_info_with_stride() must
53    * be updated as well */
54   {MFVideoFormat_RGB32,  MAKE_RAW_FORMAT_CAPS ("BGRx"),  GST_VIDEO_FORMAT_BGRx},
55   {MFVideoFormat_ARGB32, MAKE_RAW_FORMAT_CAPS ("BGRA"),  GST_VIDEO_FORMAT_BGRA},
56   {MFVideoFormat_RGB565, MAKE_RAW_FORMAT_CAPS ("RGB16"), GST_VIDEO_FORMAT_RGB16},
57   {MFVideoFormat_RGB555, MAKE_RAW_FORMAT_CAPS ("RGB15"), GST_VIDEO_FORMAT_RGB15},
58   {MFVideoFormat_RGB24,  MAKE_RAW_FORMAT_CAPS ("BGR"),   GST_VIDEO_FORMAT_BGR},
59 
60   /* packed YUV */
61   {MFVideoFormat_YUY2,   MAKE_RAW_FORMAT_CAPS ("YUY2"),  GST_VIDEO_FORMAT_YUY2},
62   {MFVideoFormat_YVYU,   MAKE_RAW_FORMAT_CAPS ("YVYU"),  GST_VIDEO_FORMAT_YVYU},
63   {MFVideoFormat_UYVY,   MAKE_RAW_FORMAT_CAPS ("UYVY"),  GST_VIDEO_FORMAT_UYVY},
64   {MFVideoFormat_AYUV,   MAKE_RAW_FORMAT_CAPS ("VUYA"),  GST_VIDEO_FORMAT_VUYA},
65 
66   /* semi-planar */
67   {MFVideoFormat_NV12,   MAKE_RAW_FORMAT_CAPS ("NV12"),  GST_VIDEO_FORMAT_NV12},
68   {MFVideoFormat_P010,   MAKE_RAW_FORMAT_CAPS ("P010_10LE"),  GST_VIDEO_FORMAT_P010_10LE},
69   {MFVideoFormat_P016,   MAKE_RAW_FORMAT_CAPS ("P016_LE"),  GST_VIDEO_FORMAT_P016_LE},
70 
71   /* planar */
72   {MFVideoFormat_I420,   MAKE_RAW_FORMAT_CAPS ("I420"),  GST_VIDEO_FORMAT_I420},
73   {MFVideoFormat_IYUV,   MAKE_RAW_FORMAT_CAPS ("I420"),  GST_VIDEO_FORMAT_I420},
74   {MFVideoFormat_YV12,   MAKE_RAW_FORMAT_CAPS ("YV12"),  GST_VIDEO_FORMAT_YV12},
75 
76   /* complex format */
77   {MFVideoFormat_v210,   MAKE_RAW_FORMAT_CAPS ("v210"),  GST_VIDEO_FORMAT_v210},
78   {MFVideoFormat_v216,   MAKE_RAW_FORMAT_CAPS ("v216"),  GST_VIDEO_FORMAT_v216},
79 
80   /* gray */
81   {MFVideoFormat_Y16,    MAKE_RAW_FORMAT_CAPS ("GRAY16_LE"),  GST_VIDEO_FORMAT_GRAY16_LE},
82 };
83 
84 static struct
85 {
86   const GUID &mf_format;
87   const gchar *caps_string;
88 } encoded_video_format_map[] = {
89   {MFVideoFormat_H264, "video/x-h264"},
90   {MFVideoFormat_HEVC, "video/x-h265"},
91   {MFVideoFormat_H265, "video/x-h265"},
92   {MFVideoFormat_VP80, "video/x-vp8"},
93   {MFVideoFormat_VP90, "video/x-vp9"},
94   {MFVideoFormat_MJPG, "image/jpeg"},
95 };
96 /* *INDENT-ON* */
97 
98 GstVideoFormat
gst_mf_video_subtype_to_video_format(const GUID * subtype)99 gst_mf_video_subtype_to_video_format (const GUID * subtype)
100 {
101   gint i;
102   for (i = 0; i < G_N_ELEMENTS (raw_video_format_map); i++) {
103     if (IsEqualGUID (raw_video_format_map[i].mf_format, *subtype))
104       return raw_video_format_map[i].format;
105   }
106 
107   return GST_VIDEO_FORMAT_UNKNOWN;
108 }
109 
110 const GUID *
gst_mf_video_subtype_from_video_format(GstVideoFormat format)111 gst_mf_video_subtype_from_video_format (GstVideoFormat format)
112 {
113   gint i;
114   for (i = 0; i < G_N_ELEMENTS (raw_video_format_map); i++) {
115     if (raw_video_format_map[i].format == format)
116       return &raw_video_format_map[i].mf_format;
117   }
118 
119   return NULL;
120 }
121 
122 static GstCaps *
gst_mf_media_type_to_video_caps(IMFMediaType * media_type)123 gst_mf_media_type_to_video_caps (IMFMediaType * media_type)
124 {
125   HRESULT hr;
126   GstCaps *caps = NULL;
127   gint i;
128   guint32 width = 0;
129   guint32 height = 0;
130   guint32 num, den;
131   guint32 val;
132   gchar *str;
133   GUID subtype;
134   GstVideoChromaSite chroma_site;
135   GstVideoColorimetry colorimetry;
136   gboolean raw_format = TRUE;
137 
138   hr = media_type->GetGUID (MF_MT_SUBTYPE, &subtype);
139   if (FAILED (hr)) {
140     GST_WARNING ("Failed to get subtype, hr: 0x%x", (guint) hr);
141     return NULL;
142   }
143 
144   for (i = 0; i < G_N_ELEMENTS (raw_video_format_map); i++) {
145     if (IsEqualGUID (raw_video_format_map[i].mf_format, subtype)) {
146       caps = gst_caps_from_string (raw_video_format_map[i].caps_string);
147       break;
148     }
149   }
150 
151   if (!caps) {
152     for (i = 0; i < G_N_ELEMENTS (encoded_video_format_map); i++) {
153       if (IsEqualGUID (encoded_video_format_map[i].mf_format, subtype)) {
154         caps = gst_caps_from_string (encoded_video_format_map[i].caps_string);
155         raw_format = FALSE;
156         break;
157       }
158     }
159   }
160 
161   if (!caps) {
162     GST_WARNING ("Unknown format %" GST_FOURCC_FORMAT,
163         GST_FOURCC_ARGS (subtype.Data1));
164     return NULL;
165   }
166 
167   hr = MFGetAttributeSize (media_type, MF_MT_FRAME_SIZE, &width, &height);
168   if (FAILED (hr) || !width || !height) {
169     GST_WARNING ("Couldn't get frame size, hr: 0x%x", (guint) hr);
170     if (raw_format) {
171       gst_caps_unref (caps);
172 
173       return NULL;
174     }
175   }
176 
177   if (width > 0 && height > 0) {
178     gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
179         "height", G_TYPE_INT, height, NULL);
180   }
181 
182   hr = MFGetAttributeRatio (media_type, MF_MT_FRAME_RATE, &num, &den);
183   if (SUCCEEDED (hr) && num > 0 && den > 0)
184     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
185 
186   hr = MFGetAttributeRatio (media_type, MF_MT_PIXEL_ASPECT_RATIO, &num, &den);
187   if (SUCCEEDED (hr) && num > 0 && den > 0)
188     gst_caps_set_simple (caps,
189         "pixel-aspect-ratio", GST_TYPE_FRACTION, num, den, NULL);
190 
191   colorimetry.range = GST_VIDEO_COLOR_RANGE_UNKNOWN;
192   colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_UNKNOWN;
193   colorimetry.transfer = GST_VIDEO_TRANSFER_UNKNOWN;
194   colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
195 
196   hr = media_type->GetUINT32 (MF_MT_VIDEO_NOMINAL_RANGE, &val);
197   if (SUCCEEDED (hr)) {
198     switch (val) {
199       case MFNominalRange_0_255:
200         colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
201         break;
202       case MFNominalRange_16_235:
203         colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
204         break;
205       default:
206         break;
207     }
208   }
209 
210   hr = media_type->GetUINT32 (MF_MT_VIDEO_PRIMARIES, &val);
211   if (SUCCEEDED (hr)) {
212     switch (val) {
213       case MFVideoPrimaries_BT709:
214         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
215         break;
216       case MFVideoPrimaries_BT470_2_SysM:
217         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
218         break;
219       case MFVideoPrimaries_BT470_2_SysBG:
220         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
221         break;
222       case MFVideoPrimaries_SMPTE170M:
223         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
224         break;
225       case MFVideoPrimaries_SMPTE240M:
226         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_SMPTE240M;
227         break;
228       case MFVideoPrimaries_EBU3213:
229         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_EBU3213;
230         break;
231       case MFVideoPrimaries_BT2020:
232         colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
233         break;
234       default:
235         GST_FIXME ("unhandled color primaries %d", val);
236         break;
237     }
238   }
239 
240   hr = media_type->GetUINT32 (MF_MT_YUV_MATRIX, &val);
241   if (SUCCEEDED (hr)) {
242     switch (val) {
243       case MFVideoTransferMatrix_BT709:
244         colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
245         break;
246       case MFVideoTransferMatrix_BT601:
247         colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
248         break;
249       case MFVideoTransferMatrix_SMPTE240M:
250         colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
251         break;
252       case MFVideoTransferMatrix_BT2020_10:
253       case MFVideoTransferMatrix_BT2020_12:
254         colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
255         break;
256       default:
257         GST_FIXME ("unhandled color matrix %d", val);
258         break;
259     }
260   }
261 
262   hr = media_type->GetUINT32 (MF_MT_TRANSFER_FUNCTION, &val);
263   if (SUCCEEDED (hr)) {
264     switch (val) {
265       case MFVideoTransFunc_10:
266         colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA10;
267         break;
268       case MFVideoTransFunc_18:
269         colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA18;
270         break;
271       case MFVideoTransFunc_20:
272         colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA20;
273         break;
274       case MFVideoTransFunc_22:
275         colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA22;
276         break;
277       case MFVideoTransFunc_709:
278       case MFVideoTransFunc_709_sym:
279         colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
280         break;
281       case MFVideoTransFunc_240M:
282         colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
283         break;
284       case MFVideoTransFunc_sRGB:
285         colorimetry.transfer = GST_VIDEO_TRANSFER_SRGB;
286         break;
287       case MFVideoTransFunc_28:
288         colorimetry.transfer = GST_VIDEO_TRANSFER_GAMMA28;
289         break;
290       case MFVideoTransFunc_Log_100:
291         colorimetry.transfer = GST_VIDEO_TRANSFER_LOG100;
292         break;
293       case MFVideoTransFunc_Log_316:
294         colorimetry.transfer = GST_VIDEO_TRANSFER_LOG316;
295         break;
296       case MFVideoTransFunc_2020_const:
297       case MFVideoTransFunc_2020:
298         colorimetry.transfer = GST_VIDEO_TRANSFER_BT2020_10;
299         break;
300       case MFVideoTransFunc_2084:
301         colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE2084;
302         break;
303       case MFVideoTransFunc_HLG:
304         colorimetry.transfer = GST_VIDEO_TRANSFER_ARIB_STD_B67;
305         break;
306       default:
307         GST_FIXME ("unhandled color transfer %d", val);
308         break;
309     }
310   }
311 
312   str = gst_video_colorimetry_to_string (&colorimetry);
313   if (str) {
314     gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, str, NULL);
315     g_free (str);
316     str = NULL;
317   }
318 
319   chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN;
320 
321   hr = media_type->GetUINT32 (MF_MT_VIDEO_CHROMA_SITING, &val);
322   if (SUCCEEDED (hr)) {
323     gboolean known_value = TRUE;
324 
325     if ((val & MFVideoChromaSubsampling_MPEG2) ==
326         MFVideoChromaSubsampling_MPEG2) {
327       chroma_site = GST_VIDEO_CHROMA_SITE_MPEG2;
328     } else if ((val & MFVideoChromaSubsampling_DV_PAL) ==
329         MFVideoChromaSubsampling_DV_PAL) {
330       chroma_site = GST_VIDEO_CHROMA_SITE_DV;
331     } else if ((val & MFVideoChromaSubsampling_Cosited) ==
332         MFVideoChromaSubsampling_Cosited) {
333       chroma_site = GST_VIDEO_CHROMA_SITE_COSITED;
334     } else {
335       known_value = FALSE;
336     }
337 
338     GST_LOG ("have %s chroma site value 0x%x",
339         known_value ? "known" : "unknown", val);
340   }
341 
342   if (chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN)
343     gst_caps_set_simple (caps, "chroma-site", G_TYPE_STRING,
344         gst_video_chroma_to_string (chroma_site), NULL);
345 
346   return caps;
347 }
348 
349 GstCaps *
gst_mf_media_type_to_caps(IMFMediaType * media_type)350 gst_mf_media_type_to_caps (IMFMediaType * media_type)
351 {
352   GUID major_type;
353   HRESULT hr;
354 
355   g_return_val_if_fail (media_type != NULL, NULL);
356 
357   hr = media_type->GetMajorType (&major_type);
358   if (FAILED (hr)) {
359     GST_WARNING ("failed to get major type, hr: 0x%x", (guint) hr);
360     return NULL;
361   }
362 
363   if (IsEqualGUID (major_type, MFMediaType_Video))
364     return gst_mf_media_type_to_video_caps (media_type);
365 
366   return NULL;
367 }
368 
369 void
gst_mf_media_type_release(IMFMediaType * media_type)370 gst_mf_media_type_release (IMFMediaType * media_type)
371 {
372   if (media_type)
373     media_type->Release ();
374 }
375 
376 gboolean
gst_mf_update_video_info_with_stride(GstVideoInfo * info,gint stride)377 gst_mf_update_video_info_with_stride (GstVideoInfo * info, gint stride)
378 {
379   guint width, height, cr_h;
380 
381   g_return_val_if_fail (info != nullptr, FALSE);
382   g_return_val_if_fail (stride > 0, FALSE);
383   g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (info)
384       != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
385 
386   if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_ENCODED)
387     return TRUE;
388 
389   width = GST_VIDEO_INFO_WIDTH (info);
390   height = GST_VIDEO_INFO_HEIGHT (info);
391 
392   /* copied from video-info */
393   switch (GST_VIDEO_INFO_FORMAT (info)) {
394       /* RGB */
395     case GST_VIDEO_FORMAT_RGBx:
396     case GST_VIDEO_FORMAT_RGBA:
397     case GST_VIDEO_FORMAT_RGB16:
398     case GST_VIDEO_FORMAT_BGR15:
399     case GST_VIDEO_FORMAT_BGR:
400       info->stride[0] = stride;
401       info->offset[0] = 0;
402       info->size = info->stride[0] * height;
403       break;
404       /* packed YUV */
405     case GST_VIDEO_FORMAT_YUY2:
406     case GST_VIDEO_FORMAT_YVYU:
407     case GST_VIDEO_FORMAT_UYVY:
408     case GST_VIDEO_FORMAT_VUYA:
409       info->stride[0] = stride;
410       info->offset[0] = 0;
411       info->size = info->stride[0] * height;
412       break;
413       /* semi-planar */
414     case GST_VIDEO_FORMAT_NV12:
415     case GST_VIDEO_FORMAT_P010_10LE:
416     case GST_VIDEO_FORMAT_P016_LE:
417       if (height % 2) {
418         GST_ERROR ("Height must be even number");
419         return FALSE;
420       }
421 
422       cr_h = height / 2;
423 
424       info->stride[0] = stride;
425       info->stride[1] = info->stride[0];
426       info->offset[0] = 0;
427       info->offset[1] = info->stride[0] * height;
428       info->size = info->offset[1] + info->stride[0] * cr_h;
429       break;
430       /* planar */
431     case GST_VIDEO_FORMAT_I420:
432     case GST_VIDEO_FORMAT_YV12:
433       if (stride % 2) {
434         GST_ERROR ("Stride must be even number");
435         return FALSE;
436       }
437 
438       if (height % 2) {
439         GST_ERROR ("Height must be even number");
440         return FALSE;
441       }
442 
443       cr_h = height / 2;
444 
445       info->stride[0] = stride;
446       info->stride[1] = stride / 2;
447       info->stride[2] = info->stride[1];
448       info->offset[0] = 0;
449       info->offset[1] = info->stride[0] * height;
450       info->offset[2] = info->offset[1] + info->stride[1] * cr_h;
451       info->size = info->offset[2] + info->stride[2] * cr_h;
452       break;
453       /* complex */
454     case GST_VIDEO_FORMAT_v210:
455     case GST_VIDEO_FORMAT_v216:
456       info->stride[0] = stride;
457       info->offset[0] = 0;
458       info->size = info->stride[0] * height;
459       break;
460       /* gray */
461     case GST_VIDEO_FORMAT_GRAY16_LE:
462       info->stride[0] = stride;
463       info->offset[0] = 0;
464       info->size = info->stride[0] * height;
465       break;
466     default:
467       GST_ERROR ("Unhandled format %s",
468           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
469       return FALSE;
470   }
471 
472   return TRUE;
473 }
474 
475 gboolean
_gst_mf_result(HRESULT hr,GstDebugCategory * cat,const gchar * file,const gchar * function,gint line)476 _gst_mf_result (HRESULT hr, GstDebugCategory * cat, const gchar * file,
477     const gchar * function, gint line)
478 {
479 #ifndef GST_DISABLE_GST_DEBUG
480   gboolean ret = TRUE;
481 
482   if (FAILED (hr)) {
483     gchar *error_text = NULL;
484 
485     error_text = g_win32_error_message ((gint) hr);
486     /* g_win32_error_message() doesn't cover all HERESULT return code,
487      * so it could be empty string, or null if there was an error
488      * in g_utf16_to_utf8() */
489     gst_debug_log (cat, GST_LEVEL_WARNING, file, function, line,
490         NULL, "MediaFoundation call failed: 0x%x, %s", (guint) hr,
491         GST_STR_NULL (error_text));
492     g_free (error_text);
493 
494     ret = FALSE;
495   }
496 
497   return ret;
498 #else
499   return SUCCEEDED (hr);
500 #endif
501 }
502 
503 /* Reference:
504  * https://docs.microsoft.com/en-us/windows/win32/medfound/media-type-debugging-code */
505 #define GST_MF_IF_EQUAL_RETURN(guid,val) G_STMT_START { \
506   if (IsEqualGUID (guid, val)) \
507     return G_STRINGIFY (val); \
508 } G_STMT_END
509 
510 static const gchar *
gst_mf_guid_to_static_string(const GUID & guid)511 gst_mf_guid_to_static_string (const GUID & guid)
512 {
513   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MAJOR_TYPE);
514   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MAJOR_TYPE);
515   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_SUBTYPE);
516   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_ALL_SAMPLES_INDEPENDENT);
517   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_FIXED_SIZE_SAMPLES);
518   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_COMPRESSED);
519   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_SAMPLE_SIZE);
520   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_WRAPPED_TYPE);
521   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_NUM_CHANNELS);
522   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_SAMPLES_PER_SECOND);
523   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND);
524   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND);
525   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_BLOCK_ALIGNMENT);
526   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_BITS_PER_SAMPLE);
527   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE);
528   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK);
529   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_CHANNEL_MASK);
530   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_FOLDDOWN_MATRIX);
531   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_WMADRC_PEAKREF);
532   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_WMADRC_PEAKTARGET);
533   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_WMADRC_AVGREF);
534   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_WMADRC_AVGTARGET);
535   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX);
536   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AAC_PAYLOAD_TYPE);
537   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION);
538   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_FRAME_SIZE);
539   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_FRAME_RATE);
540   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_FRAME_RATE_RANGE_MAX);
541   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_FRAME_RATE_RANGE_MIN);
542   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_PIXEL_ASPECT_RATIO);
543   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DRM_FLAGS);
544   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_PAD_CONTROL_FLAGS);
545   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_SOURCE_CONTENT_HINT);
546   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_VIDEO_CHROMA_SITING);
547   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_INTERLACE_MODE);
548   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_TRANSFER_FUNCTION);
549   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_VIDEO_PRIMARIES);
550   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_YUV_MATRIX);
551   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_VIDEO_LIGHTING);
552   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_VIDEO_NOMINAL_RANGE);
553   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_GEOMETRIC_APERTURE);
554   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MINIMUM_DISPLAY_APERTURE);
555   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_PAN_SCAN_APERTURE);
556   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_PAN_SCAN_ENABLED);
557   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AVG_BITRATE);
558   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AVG_BIT_ERROR_RATE);
559   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MAX_KEYFRAME_SPACING);
560   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DEFAULT_STRIDE);
561   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_PALETTE);
562   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_USER_DATA);
563   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG_START_TIME_CODE);
564   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG2_PROFILE);
565   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG2_LEVEL);
566   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG2_FLAGS);
567   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG_SEQUENCE_HEADER);
568   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_AAUX_SRC_PACK_0);
569   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_AAUX_CTRL_PACK_0);
570   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_AAUX_SRC_PACK_1);
571   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_AAUX_CTRL_PACK_1);
572   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_VAUX_SRC_PACK);
573   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_DV_VAUX_CTRL_PACK);
574   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_IMAGE_LOSS_TOLERANT);
575   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION);
576   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY);
577 
578   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Audio);
579   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Video);
580   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Protected);
581   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_SAMI);
582   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Script);
583   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Image);
584   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_HTML);
585   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_Binary);
586   GST_MF_IF_EQUAL_RETURN (guid, MFMediaType_FileTransfer);
587 
588   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_AI44);
589   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_ARGB32);
590   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_AYUV);
591   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_DV25);
592   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_DV50);
593   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_DVH1);
594   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_DVSD);
595   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_DVSL);
596   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_H264);
597   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_H265);
598   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_HEVC);
599   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_HEVC_ES);
600   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_I420);
601   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_IYUV);
602   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_M4S2);
603   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MJPG);
604   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MP43);
605   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MP4S);
606   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MP4V);
607   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MPG1);
608   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MSS1);
609   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_MSS2);
610   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_NV11);
611   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_NV12);
612   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_P010);
613   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_P016);
614   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_P210);
615   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_P216);
616   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_RGB24);
617   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_RGB32);
618   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_RGB555);
619   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_RGB565);
620   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_RGB8);
621   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_UYVY);
622   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_v210);
623   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_v410);
624   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_VP80);
625   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_VP90);
626   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_WMV1);
627   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_WMV2);
628   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_WMV3);
629   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_WVC1);
630   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y210);
631   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y216);
632   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y410);
633   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y416);
634   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y41P);
635   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_Y41T);
636   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_YUY2);
637   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_YV12);
638   GST_MF_IF_EQUAL_RETURN (guid, MFVideoFormat_YVYU);
639 
640   /* WAVE_FORMAT_PCM */
641   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_PCM);
642   /* WAVE_FORMAT_IEEE_FLOAT */
643   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_Float);
644   /* WAVE_FORMAT_DTS */
645   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_DTS);
646   /* WAVE_FORMAT_DOLBY_AC3_SPDIF */
647   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_Dolby_AC3_SPDIF);
648   /* WAVE_FORMAT_DRM */
649   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_DRM);
650   /* WAVE_FORMAT_WMAUDIO2 */
651   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_WMAudioV8);
652   /* WAVE_FORMAT_WMAUDIO3 */
653   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_WMAudioV9);
654   /* WAVE_FORMAT_WMAUDIO_LOSSLESS */
655   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_WMAudio_Lossless);
656   /* WAVE_FORMAT_WMASPDIF */
657   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_WMASPDIF);
658   /* WAVE_FORMAT_WMAVOICE9 */
659   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_MSP1);
660   /* WAVE_FORMAT_MPEGLAYER3 */
661   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_MP3);
662   /* WAVE_FORMAT_MPEG */
663   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_MPEG);
664   /* WAVE_FORMAT_MPEG_HEAAC */
665   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_AAC);
666   /* WAVE_FORMAT_MPEG_ADTS_AAC */
667   GST_MF_IF_EQUAL_RETURN (guid, MFAudioFormat_ADTS);
668 
669 #if GST_MF_WINAPI_DESKTOP
670   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
671   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_AM_FORMAT_TYPE);
672   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_ARBITRARY_HEADER);
673   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_ARBITRARY_FORMAT);
674   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_ORIGINAL_4CC);
675   GST_MF_IF_EQUAL_RETURN (guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG);
676 #endif
677 
678   return NULL;
679 }
680 
681 static gchar *
gst_mf_guid_to_string(const GUID & guid)682 gst_mf_guid_to_string (const GUID & guid)
683 {
684   const gchar *str = NULL;
685   HRESULT hr;
686   WCHAR *name = NULL;
687   gchar *ret = NULL;
688 
689   str = gst_mf_guid_to_static_string (guid);
690   if (str)
691     return g_strdup (str);
692 
693   hr = StringFromCLSID (guid, &name);
694   if (gst_mf_result (hr) && name) {
695     ret = g_utf16_to_utf8 ((const gunichar2 *) name, -1, NULL, NULL, NULL);
696     CoTaskMemFree (name);
697 
698     if (ret)
699       return ret;
700   }
701 
702   ret = g_strdup_printf
703       ("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
704       (guint) guid.Data1, (guint) guid.Data2, (guint) guid.Data3,
705       guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
706       guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
707 
708   return ret;
709 }
710 
711 static gchar *
gst_mf_attribute_value_to_string(const GUID & guid,const PROPVARIANT & var)712 gst_mf_attribute_value_to_string (const GUID & guid, const PROPVARIANT & var)
713 {
714   if (IsEqualGUID (guid, MF_MT_FRAME_RATE) ||
715       IsEqualGUID (guid, MF_MT_FRAME_RATE_RANGE_MAX) ||
716       IsEqualGUID (guid, MF_MT_FRAME_RATE_RANGE_MIN) ||
717       IsEqualGUID (guid, MF_MT_FRAME_SIZE) ||
718       IsEqualGUID (guid, MF_MT_PIXEL_ASPECT_RATIO)) {
719     UINT32 high = 0, low = 0;
720 
721     Unpack2UINT32AsUINT64 (var.uhVal.QuadPart, &high, &low);
722     return g_strdup_printf ("%dx%d", high, low);
723   }
724 
725   if (IsEqualGUID (guid, MF_MT_GEOMETRIC_APERTURE) ||
726       IsEqualGUID (guid, MF_MT_MINIMUM_DISPLAY_APERTURE) ||
727       IsEqualGUID (guid, MF_MT_PAN_SCAN_APERTURE)) {
728     /* FIXME: Not our usecase for now */
729     return g_strdup ("Not parsed");
730   }
731 
732   switch (var.vt) {
733     case VT_UI4:
734       return g_strdup_printf ("%d", var.ulVal);
735     case VT_UI8:
736       return g_strdup_printf ("%" G_GUINT64_FORMAT, var.uhVal);
737     case VT_R8:
738       return g_strdup_printf ("%f", var.dblVal);
739     case VT_CLSID:
740       return gst_mf_guid_to_string (*var.puuid);
741     case VT_LPWSTR:
742       return g_utf16_to_utf8 ((const gunichar2 *) var.pwszVal,
743           -1, NULL, NULL, NULL);
744     case VT_UNKNOWN:
745       return g_strdup ("IUnknown");
746     default:
747       return g_strdup_printf ("Unhandled type (vt = %d)", var.vt);
748   }
749 
750   return NULL;
751 }
752 
753 static void
gst_mf_dump_attribute_value_by_index(IMFAttributes * attr,const gchar * msg,guint index,GstDebugLevel level,GstDebugCategory * cat,const gchar * file,const gchar * function,gint line)754 gst_mf_dump_attribute_value_by_index (IMFAttributes * attr, const gchar * msg,
755     guint index, GstDebugLevel level, GstDebugCategory * cat,
756     const gchar * file, const gchar * function, gint line)
757 {
758   gchar *guid_name = NULL;
759   gchar *value = NULL;
760   GUID guid = GUID_NULL;
761   HRESULT hr;
762 
763   PROPVARIANT var;
764   PropVariantInit (&var);
765 
766   hr = attr->GetItemByIndex (index, &guid, &var);
767   if (!gst_mf_result (hr))
768     goto done;
769 
770   guid_name = gst_mf_guid_to_string (guid);
771   if (!guid_name)
772     goto done;
773 
774   value = gst_mf_attribute_value_to_string (guid, var);
775   if (!value)
776     goto done;
777 
778   gst_debug_log (cat, level, file, function, line,
779       NULL, "%s attribute %d, %s: %s", msg ? msg : "", index, guid_name, value);
780 
781 done:
782   PropVariantClear (&var);
783   g_free (guid_name);
784   g_free (value);
785 }
786 
787 void
_gst_mf_dump_attributes(IMFAttributes * attr,const gchar * msg,GstDebugLevel level,GstDebugCategory * cat,const gchar * file,const gchar * function,gint line)788 _gst_mf_dump_attributes (IMFAttributes * attr, const gchar * msg,
789     GstDebugLevel level, GstDebugCategory * cat, const gchar * file,
790     const gchar * function, gint line)
791 {
792 #ifndef GST_DISABLE_GST_DEBUG
793   HRESULT hr;
794   UINT32 count = 0, i;
795 
796   if (!attr)
797     return;
798 
799   hr = attr->GetCount (&count);
800   if (!gst_mf_result (hr) || count == 0)
801     return;
802 
803   for (i = 0; i < count; i++) {
804     gst_mf_dump_attribute_value_by_index (attr,
805         msg, i, level, cat, file, function, line);
806   }
807 #endif
808 }
809