You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
22KB

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