xref: /third_party/ffmpeg/libavcodec/mf_utils.c (revision cabdff1a)
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
28HRESULT 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
40HRESULT 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
50char *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.)
76IMFSample *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
114enum 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
144struct mf_pix_fmt_entry {
145    const GUID *guid;
146    enum AVPixelFormat pix_fmt;
147};
148
149static 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
158enum 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
176const 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).
190int 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
209struct GUID_Entry {
210    const GUID *guid;
211    const char *name;
212};
213
214#define GUID_ENTRY(var) {&(var), # var}
215
216static 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
332char *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
358void 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
502void ff_media_type_dump(void *log, IMFMediaType *type)
503{
504    ff_attributes_dump(log, (IMFAttributes *)type);
505}
506
507const 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
519static 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
542static 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.
550int 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
638error_uninit_mf:
639    uninit_com_mf(f);
640    return AVERROR(ENOSYS);
641}
642
643void 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