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