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