• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #define COBJMACROS
20 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
21 #undef _WIN32_WINNT
22 #define _WIN32_WINNT 0x0602
23 #endif
24 
25 #include "mf_utils.h"
26 #include "libavutil/pixdesc.h"
27 
ff_MFGetAttributeSize(IMFAttributes * pattr,REFGUID guid,UINT32 * pw,UINT32 * ph)28 HRESULT ff_MFGetAttributeSize(IMFAttributes *pattr, REFGUID guid,
29                               UINT32 *pw, UINT32 *ph)
30 {
31     UINT64 t;
32     HRESULT hr = IMFAttributes_GetUINT64(pattr, guid, &t);
33     if (!FAILED(hr)) {
34         *pw = t >> 32;
35         *ph = (UINT32)t;
36     }
37     return hr;
38 }
39 
ff_MFSetAttributeSize(IMFAttributes * pattr,REFGUID guid,UINT32 uw,UINT32 uh)40 HRESULT ff_MFSetAttributeSize(IMFAttributes *pattr, REFGUID guid,
41                               UINT32 uw, UINT32 uh)
42 {
43     UINT64 t = (((UINT64)uw) << 32) | uh;
44     return IMFAttributes_SetUINT64(pattr, guid, t);
45 }
46 
47 #define ff_MFSetAttributeRatio ff_MFSetAttributeSize
48 #define ff_MFGetAttributeRatio ff_MFGetAttributeSize
49 
ff_hr_str_buf(char * buf,size_t size,HRESULT hr)50 char *ff_hr_str_buf(char *buf, size_t size, HRESULT hr)
51 {
52 #define HR(x) case x: return (char *) # x;
53     switch (hr) {
54     HR(S_OK)
55     HR(E_UNEXPECTED)
56     HR(MF_E_INVALIDMEDIATYPE)
57     HR(MF_E_INVALIDSTREAMNUMBER)
58     HR(MF_E_INVALIDTYPE)
59     HR(MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING)
60     HR(MF_E_TRANSFORM_TYPE_NOT_SET)
61     HR(MF_E_UNSUPPORTED_D3D_TYPE)
62     HR(MF_E_TRANSFORM_NEED_MORE_INPUT)
63     HR(MF_E_TRANSFORM_STREAM_CHANGE)
64     HR(MF_E_NOTACCEPTING)
65     HR(MF_E_NO_SAMPLE_TIMESTAMP)
66     HR(MF_E_NO_SAMPLE_DURATION)
67 #undef HR
68     }
69     snprintf(buf, size, "%x", (unsigned)hr);
70     return buf;
71 }
72 
73 // If fill_data!=NULL, initialize the buffer and set the length. (This is a
74 // subtle but important difference: some decoders want CurrentLength==0 on
75 // provided output buffers.)
ff_create_memory_sample(MFFunctions * f,void * fill_data,size_t size,size_t align)76 IMFSample *ff_create_memory_sample(MFFunctions *f,void *fill_data, size_t size,
77                                    size_t align)
78 {
79     HRESULT hr;
80     IMFSample *sample;
81     IMFMediaBuffer *buffer;
82 
83     hr = f->MFCreateSample(&sample);
84     if (FAILED(hr))
85         return NULL;
86 
87     align = FFMAX(align, 16); // 16 is "recommended", even if not required
88 
89     hr = f->MFCreateAlignedMemoryBuffer(size, align - 1, &buffer);
90     if (FAILED(hr))
91         return NULL;
92 
93     if (fill_data) {
94         BYTE *tmp;
95 
96         hr = IMFMediaBuffer_Lock(buffer, &tmp, NULL, NULL);
97         if (FAILED(hr)) {
98             IMFMediaBuffer_Release(buffer);
99             IMFSample_Release(sample);
100             return NULL;
101         }
102         memcpy(tmp, fill_data, size);
103 
104         IMFMediaBuffer_SetCurrentLength(buffer, size);
105         IMFMediaBuffer_Unlock(buffer);
106     }
107 
108     IMFSample_AddBuffer(sample, buffer);
109     IMFMediaBuffer_Release(buffer);
110 
111     return sample;
112 }
113 
ff_media_type_to_sample_fmt(IMFAttributes * type)114 enum AVSampleFormat ff_media_type_to_sample_fmt(IMFAttributes *type)
115 {
116     HRESULT hr;
117     UINT32 bits;
118     GUID subtype;
119 
120     hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits);
121     if (FAILED(hr))
122         return AV_SAMPLE_FMT_NONE;
123 
124     hr = IMFAttributes_GetGUID(type, &MF_MT_SUBTYPE, &subtype);
125     if (FAILED(hr))
126         return AV_SAMPLE_FMT_NONE;
127 
128     if (IsEqualGUID(&subtype, &MFAudioFormat_PCM)) {
129         switch (bits) {
130         case 8:  return AV_SAMPLE_FMT_U8;
131         case 16: return AV_SAMPLE_FMT_S16;
132         case 32: return AV_SAMPLE_FMT_S32;
133         }
134     } else if (IsEqualGUID(&subtype, &MFAudioFormat_Float)) {
135         switch (bits) {
136         case 32: return AV_SAMPLE_FMT_FLT;
137         case 64: return AV_SAMPLE_FMT_DBL;
138         }
139     }
140 
141     return AV_SAMPLE_FMT_NONE;
142 }
143 
144 struct mf_pix_fmt_entry {
145     const GUID *guid;
146     enum AVPixelFormat pix_fmt;
147 };
148 
149 static const struct mf_pix_fmt_entry mf_pix_fmts[] = {
150     {&MFVideoFormat_IYUV, AV_PIX_FMT_YUV420P},
151     {&MFVideoFormat_I420, AV_PIX_FMT_YUV420P},
152     {&MFVideoFormat_NV12, AV_PIX_FMT_NV12},
153     {&MFVideoFormat_P010, AV_PIX_FMT_P010},
154     {&MFVideoFormat_P016, AV_PIX_FMT_P010}, // not equal, but compatible
155     {&MFVideoFormat_YUY2, AV_PIX_FMT_YUYV422},
156 };
157 
ff_media_type_to_pix_fmt(IMFAttributes * type)158 enum AVPixelFormat ff_media_type_to_pix_fmt(IMFAttributes *type)
159 {
160     HRESULT hr;
161     GUID subtype;
162     int i;
163 
164     hr = IMFAttributes_GetGUID(type, &MF_MT_SUBTYPE, &subtype);
165     if (FAILED(hr))
166         return AV_PIX_FMT_NONE;
167 
168     for (i = 0; i < FF_ARRAY_ELEMS(mf_pix_fmts); i++) {
169         if (IsEqualGUID(&subtype, mf_pix_fmts[i].guid))
170             return mf_pix_fmts[i].pix_fmt;
171     }
172 
173     return AV_PIX_FMT_NONE;
174 }
175 
ff_pix_fmt_to_guid(enum AVPixelFormat pix_fmt)176 const GUID *ff_pix_fmt_to_guid(enum AVPixelFormat pix_fmt)
177 {
178     int i;
179 
180     for (i = 0; i < FF_ARRAY_ELEMS(mf_pix_fmts); i++) {
181         if (mf_pix_fmts[i].pix_fmt == pix_fmt)
182             return mf_pix_fmts[i].guid;
183     }
184 
185     return NULL;
186 }
187 
188 // If this GUID is of the form XXXXXXXX-0000-0010-8000-00AA00389B71, then
189 // extract the XXXXXXXX prefix as FourCC (oh the pain).
ff_fourcc_from_guid(const GUID * guid,uint32_t * out_fourcc)190 int ff_fourcc_from_guid(const GUID *guid, uint32_t *out_fourcc)
191 {
192     if (guid->Data2 == 0 && guid->Data3 == 0x0010 &&
193         guid->Data4[0] == 0x80 &&
194         guid->Data4[1] == 0x00 &&
195         guid->Data4[2] == 0x00 &&
196         guid->Data4[3] == 0xAA &&
197         guid->Data4[4] == 0x00 &&
198         guid->Data4[5] == 0x38 &&
199         guid->Data4[6] == 0x9B &&
200         guid->Data4[7] == 0x71) {
201         *out_fourcc = guid->Data1;
202         return 0;
203     }
204 
205     *out_fourcc = 0;
206     return AVERROR_UNKNOWN;
207 }
208 
209 struct GUID_Entry {
210     const GUID *guid;
211     const char *name;
212 };
213 
214 #define GUID_ENTRY(var) {&(var), # var}
215 
216 static struct GUID_Entry guid_names[] = {
217     GUID_ENTRY(MFT_FRIENDLY_NAME_Attribute),
218     GUID_ENTRY(MFT_TRANSFORM_CLSID_Attribute),
219     GUID_ENTRY(MFT_ENUM_HARDWARE_URL_Attribute),
220     GUID_ENTRY(MFT_CONNECTED_STREAM_ATTRIBUTE),
221     GUID_ENTRY(MFT_CONNECTED_TO_HW_STREAM),
222     GUID_ENTRY(MF_SA_D3D_AWARE),
223     GUID_ENTRY(ff_MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT),
224     GUID_ENTRY(ff_MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE),
225     GUID_ENTRY(ff_MF_SA_D3D11_BINDFLAGS),
226     GUID_ENTRY(ff_MF_SA_D3D11_USAGE),
227     GUID_ENTRY(ff_MF_SA_D3D11_AWARE),
228     GUID_ENTRY(ff_MF_SA_D3D11_SHARED),
229     GUID_ENTRY(ff_MF_SA_D3D11_SHARED_WITHOUT_MUTEX),
230     GUID_ENTRY(MF_MT_SUBTYPE),
231     GUID_ENTRY(MF_MT_MAJOR_TYPE),
232     GUID_ENTRY(MF_MT_AUDIO_SAMPLES_PER_SECOND),
233     GUID_ENTRY(MF_MT_AUDIO_NUM_CHANNELS),
234     GUID_ENTRY(MF_MT_AUDIO_CHANNEL_MASK),
235     GUID_ENTRY(MF_MT_FRAME_SIZE),
236     GUID_ENTRY(MF_MT_INTERLACE_MODE),
237     GUID_ENTRY(MF_MT_USER_DATA),
238     GUID_ENTRY(MF_MT_PIXEL_ASPECT_RATIO),
239     GUID_ENTRY(MFMediaType_Audio),
240     GUID_ENTRY(MFMediaType_Video),
241     GUID_ENTRY(MFAudioFormat_PCM),
242     GUID_ENTRY(MFAudioFormat_Float),
243     GUID_ENTRY(MFVideoFormat_H264),
244     GUID_ENTRY(MFVideoFormat_H264_ES),
245     GUID_ENTRY(ff_MFVideoFormat_HEVC),
246     GUID_ENTRY(ff_MFVideoFormat_HEVC_ES),
247     GUID_ENTRY(MFVideoFormat_MPEG2),
248     GUID_ENTRY(MFVideoFormat_MP43),
249     GUID_ENTRY(MFVideoFormat_MP4V),
250     GUID_ENTRY(MFVideoFormat_WMV1),
251     GUID_ENTRY(MFVideoFormat_WMV2),
252     GUID_ENTRY(MFVideoFormat_WMV3),
253     GUID_ENTRY(MFVideoFormat_WVC1),
254     GUID_ENTRY(MFAudioFormat_Dolby_AC3),
255     GUID_ENTRY(MFAudioFormat_Dolby_DDPlus),
256     GUID_ENTRY(MFAudioFormat_AAC),
257     GUID_ENTRY(MFAudioFormat_MP3),
258     GUID_ENTRY(MFAudioFormat_MSP1),
259     GUID_ENTRY(MFAudioFormat_WMAudioV8),
260     GUID_ENTRY(MFAudioFormat_WMAudioV9),
261     GUID_ENTRY(MFAudioFormat_WMAudio_Lossless),
262     GUID_ENTRY(MF_MT_ALL_SAMPLES_INDEPENDENT),
263     GUID_ENTRY(MF_MT_COMPRESSED),
264     GUID_ENTRY(MF_MT_FIXED_SIZE_SAMPLES),
265     GUID_ENTRY(MF_MT_SAMPLE_SIZE),
266     GUID_ENTRY(MF_MT_WRAPPED_TYPE),
267     GUID_ENTRY(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION),
268     GUID_ENTRY(MF_MT_AAC_PAYLOAD_TYPE),
269     GUID_ENTRY(MF_MT_AUDIO_AVG_BYTES_PER_SECOND),
270     GUID_ENTRY(MF_MT_AUDIO_BITS_PER_SAMPLE),
271     GUID_ENTRY(MF_MT_AUDIO_BLOCK_ALIGNMENT),
272     GUID_ENTRY(MF_MT_AUDIO_CHANNEL_MASK),
273     GUID_ENTRY(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND),
274     GUID_ENTRY(MF_MT_AUDIO_FOLDDOWN_MATRIX),
275     GUID_ENTRY(MF_MT_AUDIO_NUM_CHANNELS),
276     GUID_ENTRY(MF_MT_AUDIO_PREFER_WAVEFORMATEX),
277     GUID_ENTRY(MF_MT_AUDIO_SAMPLES_PER_BLOCK),
278     GUID_ENTRY(MF_MT_AUDIO_SAMPLES_PER_SECOND),
279     GUID_ENTRY(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE),
280     GUID_ENTRY(MF_MT_AUDIO_WMADRC_AVGREF),
281     GUID_ENTRY(MF_MT_AUDIO_WMADRC_AVGTARGET),
282     GUID_ENTRY(MF_MT_AUDIO_WMADRC_PEAKREF),
283     GUID_ENTRY(MF_MT_AUDIO_WMADRC_PEAKTARGET),
284     GUID_ENTRY(MF_MT_AVG_BIT_ERROR_RATE),
285     GUID_ENTRY(MF_MT_AVG_BITRATE),
286     GUID_ENTRY(MF_MT_DEFAULT_STRIDE),
287     GUID_ENTRY(MF_MT_DRM_FLAGS),
288     GUID_ENTRY(MF_MT_FRAME_RATE),
289     GUID_ENTRY(MF_MT_FRAME_RATE_RANGE_MAX),
290     GUID_ENTRY(MF_MT_FRAME_RATE_RANGE_MIN),
291     GUID_ENTRY(MF_MT_FRAME_SIZE),
292     GUID_ENTRY(MF_MT_GEOMETRIC_APERTURE),
293     GUID_ENTRY(MF_MT_INTERLACE_MODE),
294     GUID_ENTRY(MF_MT_MAX_KEYFRAME_SPACING),
295     GUID_ENTRY(MF_MT_MINIMUM_DISPLAY_APERTURE),
296     GUID_ENTRY(MF_MT_MPEG_SEQUENCE_HEADER),
297     GUID_ENTRY(MF_MT_MPEG_START_TIME_CODE),
298     GUID_ENTRY(MF_MT_MPEG2_FLAGS),
299     GUID_ENTRY(MF_MT_MPEG2_LEVEL),
300     GUID_ENTRY(MF_MT_MPEG2_PROFILE),
301     GUID_ENTRY(MF_MT_PAD_CONTROL_FLAGS),
302     GUID_ENTRY(MF_MT_PALETTE),
303     GUID_ENTRY(MF_MT_PAN_SCAN_APERTURE),
304     GUID_ENTRY(MF_MT_PAN_SCAN_ENABLED),
305     GUID_ENTRY(MF_MT_PIXEL_ASPECT_RATIO),
306     GUID_ENTRY(MF_MT_SOURCE_CONTENT_HINT),
307     GUID_ENTRY(MF_MT_TRANSFER_FUNCTION),
308     GUID_ENTRY(MF_MT_VIDEO_CHROMA_SITING),
309     GUID_ENTRY(MF_MT_VIDEO_LIGHTING),
310     GUID_ENTRY(MF_MT_VIDEO_NOMINAL_RANGE),
311     GUID_ENTRY(MF_MT_VIDEO_PRIMARIES),
312     GUID_ENTRY(MF_MT_VIDEO_ROTATION),
313     GUID_ENTRY(MF_MT_YUV_MATRIX),
314     GUID_ENTRY(ff_CODECAPI_AVDecVideoThumbnailGenerationMode),
315     GUID_ENTRY(ff_CODECAPI_AVDecVideoDropPicWithMissingRef),
316     GUID_ENTRY(ff_CODECAPI_AVDecVideoSoftwareDeinterlaceMode),
317     GUID_ENTRY(ff_CODECAPI_AVDecVideoFastDecodeMode),
318     GUID_ENTRY(ff_CODECAPI_AVLowLatencyMode),
319     GUID_ENTRY(ff_CODECAPI_AVDecVideoH264ErrorConcealment),
320     GUID_ENTRY(ff_CODECAPI_AVDecVideoMPEG2ErrorConcealment),
321     GUID_ENTRY(ff_CODECAPI_AVDecVideoCodecType),
322     GUID_ENTRY(ff_CODECAPI_AVDecVideoDXVAMode),
323     GUID_ENTRY(ff_CODECAPI_AVDecVideoDXVABusEncryption),
324     GUID_ENTRY(ff_CODECAPI_AVDecVideoSWPowerLevel),
325     GUID_ENTRY(ff_CODECAPI_AVDecVideoMaxCodedWidth),
326     GUID_ENTRY(ff_CODECAPI_AVDecVideoMaxCodedHeight),
327     GUID_ENTRY(ff_CODECAPI_AVDecNumWorkerThreads),
328     GUID_ENTRY(ff_CODECAPI_AVDecSoftwareDynamicFormatChange),
329     GUID_ENTRY(ff_CODECAPI_AVDecDisableVideoPostProcessing),
330 };
331 
ff_guid_str_buf(char * buf,size_t buf_size,const GUID * guid)332 char *ff_guid_str_buf(char *buf, size_t buf_size, const GUID *guid)
333 {
334     uint32_t fourcc;
335     int n;
336     for (n = 0; n < FF_ARRAY_ELEMS(guid_names); n++) {
337         if (IsEqualGUID(guid, guid_names[n].guid)) {
338             snprintf(buf, buf_size, "%s", guid_names[n].name);
339             return buf;
340         }
341     }
342 
343     if (ff_fourcc_from_guid(guid, &fourcc) >= 0) {
344         snprintf(buf, buf_size, "<FourCC %s>", av_fourcc2str(fourcc));
345         return buf;
346     }
347 
348     snprintf(buf, buf_size,
349              "{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}",
350              (unsigned) guid->Data1, guid->Data2, guid->Data3,
351              guid->Data4[0], guid->Data4[1],
352              guid->Data4[2], guid->Data4[3],
353              guid->Data4[4], guid->Data4[5],
354              guid->Data4[6], guid->Data4[7]);
355     return buf;
356 }
357 
ff_attributes_dump(void * log,IMFAttributes * attrs)358 void ff_attributes_dump(void *log, IMFAttributes *attrs)
359 {
360     HRESULT hr;
361     UINT32 count;
362     int n;
363 
364     hr = IMFAttributes_GetCount(attrs, &count);
365     if (FAILED(hr))
366         return;
367 
368     for (n = 0; n < count; n++) {
369         GUID key;
370         MF_ATTRIBUTE_TYPE type;
371         char extra[80] = {0};
372         const char *name = NULL;
373 
374         hr = IMFAttributes_GetItemByIndex(attrs, n, &key, NULL);
375         if (FAILED(hr))
376             goto err;
377 
378         name = ff_guid_str(&key);
379 
380         if (IsEqualGUID(&key, &MF_MT_AUDIO_CHANNEL_MASK)) {
381             UINT32 v;
382             hr = IMFAttributes_GetUINT32(attrs, &key, &v);
383             if (FAILED(hr))
384                 goto err;
385             snprintf(extra, sizeof(extra), " (0x%x)", (unsigned)v);
386         } else if (IsEqualGUID(&key, &MF_MT_FRAME_SIZE)) {
387             UINT32 w, h;
388 
389             hr = ff_MFGetAttributeSize(attrs, &MF_MT_FRAME_SIZE, &w, &h);
390             if (FAILED(hr))
391                 goto err;
392             snprintf(extra, sizeof(extra), " (%dx%d)", (int)w, (int)h);
393         } else if (IsEqualGUID(&key, &MF_MT_PIXEL_ASPECT_RATIO) ||
394                    IsEqualGUID(&key, &MF_MT_FRAME_RATE)) {
395             UINT32 num, den;
396 
397             hr = ff_MFGetAttributeRatio(attrs, &key, &num, &den);
398             if (FAILED(hr))
399                 goto err;
400             snprintf(extra, sizeof(extra), " (%d:%d)", (int)num, (int)den);
401         }
402 
403         hr = IMFAttributes_GetItemType(attrs, &key, &type);
404         if (FAILED(hr))
405             goto err;
406 
407         switch (type) {
408         case MF_ATTRIBUTE_UINT32: {
409             UINT32 v;
410             hr = IMFAttributes_GetUINT32(attrs, &key, &v);
411             if (FAILED(hr))
412                 goto err;
413             av_log(log, AV_LOG_VERBOSE, "   %s=%d%s\n", name, (int)v, extra);
414             break;
415         case MF_ATTRIBUTE_UINT64: {
416             UINT64 v;
417             hr = IMFAttributes_GetUINT64(attrs, &key, &v);
418             if (FAILED(hr))
419                 goto err;
420             av_log(log, AV_LOG_VERBOSE, "   %s=%lld%s\n", name, (long long)v, extra);
421             break;
422         }
423         case MF_ATTRIBUTE_DOUBLE: {
424             DOUBLE v;
425             hr = IMFAttributes_GetDouble(attrs, &key, &v);
426             if (FAILED(hr))
427                 goto err;
428             av_log(log, AV_LOG_VERBOSE, "   %s=%f%s\n", name, (double)v, extra);
429             break;
430         }
431         case MF_ATTRIBUTE_STRING: {
432             wchar_t s[512]; // being lazy here
433             hr = IMFAttributes_GetString(attrs, &key, s, sizeof(s), NULL);
434             if (FAILED(hr))
435                 goto err;
436             av_log(log, AV_LOG_VERBOSE, "   %s='%ls'%s\n", name, s, extra);
437             break;
438         }
439         case MF_ATTRIBUTE_GUID: {
440             GUID v;
441             hr = IMFAttributes_GetGUID(attrs, &key, &v);
442             if (FAILED(hr))
443                 goto err;
444             av_log(log, AV_LOG_VERBOSE, "   %s=%s%s\n", name, ff_guid_str(&v), extra);
445             break;
446         }
447         case MF_ATTRIBUTE_BLOB: {
448             UINT32 sz;
449             UINT8 buffer[100];
450             hr = IMFAttributes_GetBlobSize(attrs, &key, &sz);
451             if (FAILED(hr))
452                 goto err;
453             if (sz <= sizeof(buffer)) {
454                 // hex-dump it
455                 char str[512] = {0};
456                 size_t pos = 0;
457                 hr = IMFAttributes_GetBlob(attrs, &key, buffer, sizeof(buffer), &sz);
458                 if (FAILED(hr))
459                     goto err;
460                 for (pos = 0; pos < sz; pos++) {
461                     const char *hex = "0123456789ABCDEF";
462                     if (pos * 3 + 3 > sizeof(str))
463                         break;
464                     str[pos * 3 + 0] = hex[buffer[pos] >> 4];
465                     str[pos * 3 + 1] = hex[buffer[pos] & 15];
466                     str[pos * 3 + 2] = ' ';
467                 }
468                 str[pos * 3 + 0] = 0;
469                 av_log(log, AV_LOG_VERBOSE, "   %s=<blob size %d: %s>%s\n", name, (int)sz, str, extra);
470             } else {
471                 av_log(log, AV_LOG_VERBOSE, "   %s=<blob size %d>%s\n", name, (int)sz, extra);
472             }
473             break;
474         }
475         case MF_ATTRIBUTE_IUNKNOWN: {
476             av_log(log, AV_LOG_VERBOSE, "   %s=<IUnknown>%s\n", name, extra);
477             break;
478         }
479         default:
480             av_log(log, AV_LOG_VERBOSE, "   %s=<unknown type>%s\n", name, extra);
481             break;
482         }
483         }
484 
485         if (IsEqualGUID(&key, &MF_MT_SUBTYPE)) {
486             const char *fmt;
487             fmt = av_get_sample_fmt_name(ff_media_type_to_sample_fmt(attrs));
488             if (fmt)
489                 av_log(log, AV_LOG_VERBOSE, "   FF-sample-format=%s\n", fmt);
490 
491             fmt = av_get_pix_fmt_name(ff_media_type_to_pix_fmt(attrs));
492             if (fmt)
493                 av_log(log, AV_LOG_VERBOSE, "   FF-pixel-format=%s\n", fmt);
494         }
495 
496         continue;
497     err:
498         av_log(log, AV_LOG_VERBOSE, "   %s=<failed to get value>\n", name ? name : "?");
499     }
500 }
501 
ff_media_type_dump(void * log,IMFMediaType * type)502 void ff_media_type_dump(void *log, IMFMediaType *type)
503 {
504     ff_attributes_dump(log, (IMFAttributes *)type);
505 }
506 
ff_codec_to_mf_subtype(enum AVCodecID codec)507 const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec)
508 {
509     switch (codec) {
510     case AV_CODEC_ID_H264:              return &MFVideoFormat_H264;
511     case AV_CODEC_ID_HEVC:              return &ff_MFVideoFormat_HEVC;
512     case AV_CODEC_ID_AC3:               return &MFAudioFormat_Dolby_AC3;
513     case AV_CODEC_ID_AAC:               return &MFAudioFormat_AAC;
514     case AV_CODEC_ID_MP3:               return &MFAudioFormat_MP3;
515     default:                            return NULL;
516     }
517 }
518 
init_com_mf(void * log,MFFunctions * f)519 static int init_com_mf(void *log, MFFunctions *f)
520 {
521     HRESULT hr;
522 
523     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
524     if (hr == RPC_E_CHANGED_MODE) {
525         av_log(log, AV_LOG_ERROR, "COM must not be in STA mode\n");
526         return AVERROR(EINVAL);
527     } else if (FAILED(hr)) {
528         av_log(log, AV_LOG_ERROR, "could not initialize COM\n");
529         return AVERROR(ENOSYS);
530     }
531 
532     hr = f->MFStartup(MF_VERSION, MFSTARTUP_FULL);
533     if (FAILED(hr)) {
534         av_log(log, AV_LOG_ERROR, "could not initialize MediaFoundation\n");
535         CoUninitialize();
536         return AVERROR(ENOSYS);
537     }
538 
539     return 0;
540 }
541 
uninit_com_mf(MFFunctions * f)542 static void uninit_com_mf(MFFunctions *f)
543 {
544     f->MFShutdown();
545     CoUninitialize();
546 }
547 
548 // Find and create a IMFTransform with the given input/output types. When done,
549 // you should use ff_free_mf() to destroy it, which will also uninit COM.
ff_instantiate_mf(void * log,MFFunctions * f,GUID category,MFT_REGISTER_TYPE_INFO * in_type,MFT_REGISTER_TYPE_INFO * out_type,int use_hw,IMFTransform ** res)550 int ff_instantiate_mf(void *log,
551                       MFFunctions *f,
552                       GUID category,
553                       MFT_REGISTER_TYPE_INFO *in_type,
554                       MFT_REGISTER_TYPE_INFO *out_type,
555                       int use_hw,
556                       IMFTransform **res)
557 {
558     HRESULT hr;
559     int n;
560     int ret;
561     IMFActivate **activate;
562     UINT32 num_activate;
563     IMFActivate *winner = 0;
564     UINT32 flags;
565 
566     ret = init_com_mf(log, f);
567     if (ret < 0)
568         return ret;
569 
570     flags = MFT_ENUM_FLAG_SORTANDFILTER;
571 
572     if (use_hw) {
573         flags |= MFT_ENUM_FLAG_HARDWARE;
574     } else {
575         flags |= MFT_ENUM_FLAG_SYNCMFT;
576     }
577 
578     hr = f->MFTEnumEx(category, flags, in_type, out_type, &activate,
579                       &num_activate);
580     if (FAILED(hr))
581         goto error_uninit_mf;
582 
583     if (log) {
584         if (!num_activate)
585             av_log(log, AV_LOG_ERROR, "could not find any MFT for the given media type\n");
586 
587         for (n = 0; n < num_activate; n++) {
588             av_log(log, AV_LOG_VERBOSE, "MF %d attributes:\n", n);
589             ff_attributes_dump(log, (IMFAttributes *)activate[n]);
590         }
591     }
592 
593     *res = NULL;
594     for (n = 0; n < num_activate; n++) {
595         if (log)
596             av_log(log, AV_LOG_VERBOSE, "activate MFT %d\n", n);
597         hr = IMFActivate_ActivateObject(activate[n], &IID_IMFTransform,
598                                         (void **)res);
599         if (*res) {
600             winner = activate[n];
601             IMFActivate_AddRef(winner);
602             break;
603         }
604     }
605 
606     for (n = 0; n < num_activate; n++)
607        IMFActivate_Release(activate[n]);
608     CoTaskMemFree(activate);
609 
610     if (!*res) {
611         if (log)
612             av_log(log, AV_LOG_ERROR, "could not create MFT\n");
613         goto error_uninit_mf;
614     }
615 
616     if (log) {
617         wchar_t s[512]; // being lazy here
618         IMFAttributes *attrs;
619         hr = IMFTransform_GetAttributes(*res, &attrs);
620         if (!FAILED(hr) && attrs) {
621 
622             av_log(log, AV_LOG_VERBOSE, "MFT attributes\n");
623             ff_attributes_dump(log, attrs);
624             IMFAttributes_Release(attrs);
625         }
626 
627         hr = IMFActivate_GetString(winner, &MFT_FRIENDLY_NAME_Attribute, s,
628                                    sizeof(s), NULL);
629         if (!FAILED(hr))
630             av_log(log, AV_LOG_INFO, "MFT name: '%ls'\n", s);
631 
632     }
633 
634     IMFActivate_Release(winner);
635 
636     return 0;
637 
638 error_uninit_mf:
639     uninit_com_mf(f);
640     return AVERROR(ENOSYS);
641 }
642 
ff_free_mf(MFFunctions * f,IMFTransform ** mft)643 void ff_free_mf(MFFunctions *f, IMFTransform **mft)
644 {
645     if (*mft)
646         IMFTransform_Release(*mft);
647     *mft = NULL;
648     uninit_com_mf(f);
649 }
650