mf_utils.cxx 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944
  1. /* Copyright (C) 2013 Mamadou DIOP
  2. * Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
  3. *
  4. * This file is part of Open Source Doubango Framework.
  5. *
  6. * DOUBANGO is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * DOUBANGO is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with DOUBANGO.
  18. */
  19. #include "mf_utils.h"
  20. #include "mf_codec.h"
  21. #include "tinymedia/tmedia_common.h"
  22. #include "tsk_debug.h"
  23. #include <KS.h>/* KS.H must be included before codecapi.H */
  24. #include <Codecapi.h>
  25. #include <initguid.h>
  26. #include <wmcodecdsp.h>
  27. #include <d3d9.h>
  28. #include <assert.h>
  29. #ifdef _MSC_VER
  30. #pragma comment(lib, "strmiids.lib")
  31. #pragma comment(lib, "wmcodecdspuuid.lib")
  32. #pragma comment(lib, "d3d9")
  33. #endif
  34. #if !defined(PLUGIN_MF_DISABLE_CODECS)
  35. // Must be "0" to use "Microsoft"/"Intel Quick Sync" MFT codecs. Testing: When set to "1", libx264 and FFmpeg will be used.
  36. // Metropolis code (G2J.COM TelePresence client) has "PLUGIN_MF_DISABLE_CODECS=1" because of interop issues against Tandberg and Intel QuickSync H.264 implementations.
  37. # define PLUGIN_MF_DISABLE_CODECS 1
  38. #endif
  39. #if !defined(PLUGIN_MF_DISABLE_MS_H264_ENCODER)
  40. // MS H.264 encoder produces artifacts when bundled with the producer. Disable until we found why this happens.
  41. // What is strange is that NVIDIA CUDA H.264 decoder doesn't produce artifacts when decoding MS frames while FFmpeg and MS decoder do.
  42. // To encode with MS and decode with CUDA:
  43. // - Force "bMFEncoderIsRegistered" value to "FALSE" in plugin_win_mf_producer_video.cxx
  44. // Metropolis code (G2J.COM TelePresence) has "PLUGIN_MF_DISABLE_MS_H264_ENCODER=1" beacause Microsoft H.264 not fully tested against Tandberg, Polycom, Hartallo...
  45. # define PLUGIN_MF_DISABLE_MS_H264_ENCODER 1
  46. #endif
  47. #if !defined(PLUGIN_MF_DISABLE_ASYNC_DECODERS)
  48. // Not fully tested
  49. # define PLUGIN_MF_DISABLE_ASYNC_DECODERS 1
  50. #endif
  51. BOOL MFUtils::g_bStarted = FALSE;
  52. DWORD MFUtils::g_dwMajorVersion = -1;
  53. DWORD MFUtils::g_dwMinorVersion = -1;
  54. BOOL MFUtils::g_bLowLatencyH264Checked = FALSE;
  55. BOOL MFUtils::g_bLowLatencyH264Supported = FALSE;
  56. BOOL MFUtils::g_bLowLatencyH264SupportsMaxSliceSize = FALSE;
  57. BOOL MFUtils::g_bD3D9Checked = FALSE;
  58. BOOL MFUtils::g_bD3D9Supported = FALSE;
  59. const TOPOID MFUtils::g_ullTopoIdSinkMain = 111;
  60. const TOPOID MFUtils::g_ullTopoIdSinkPreview = 222;
  61. const TOPOID MFUtils::g_ullTopoIdSource = 333;
  62. const TOPOID MFUtils::g_ullTopoIdVideoProcessor = 444;
  63. // Preferred VideoSubTypes
  64. static const VideoSubTypeGuidPair PreferredVideoSubTypeGuidPairs[] = {
  65. { tmedia_chroma_yuv420p, MFVideoFormat_I420 },
  66. { tmedia_chroma_nv12, MFVideoFormat_NV12 },
  67. { tmedia_chroma_uyvy422, MFVideoFormat_UYVY },
  68. { tmedia_chroma_yuyv422, MFVideoFormat_YUY2 },
  69. /* TODO: Add more YUV formats */
  70. { tmedia_chroma_rgb565le, MFVideoFormat_RGB565 },
  71. { tmedia_chroma_bgr24, MFVideoFormat_RGB24 },
  72. { tmedia_chroma_rgb32, MFVideoFormat_RGB32 },
  73. };
  74. static const tsk_size_t PreferredVideoSubTypeGuidPairsCount = sizeof(PreferredVideoSubTypeGuidPairs)/sizeof(PreferredVideoSubTypeGuidPairs[0]);
  75. // Video Processor
  76. DEFINE_GUID(CLSID_VideoProcessorMFT,
  77. 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);
  78. // {4BE8D3C0-0515-4A37-AD55-E4BAE19AF471}
  79. DEFINE_GUID(CLSID_MF_INTEL_H264EncFilter, // Intel Quick Sync Encoder
  80. 0x4be8d3c0, 0x0515, 0x4a37, 0xad, 0x55, 0xe4, 0xba, 0xe1, 0x9a, 0xf4, 0x71);
  81. // {0855C9AC-BC6F-4371-8954-671CCD4EC16F}
  82. DEFINE_GUID(CLSID_MF_INTEL_H264DecFilter, // Intel Quick Sync Decoder
  83. 0x0855c9ac, 0xbc6f, 0x4371, 0x89, 0x54, 0x67, 0x1c, 0xcd, 0x4e, 0xc1, 0x6f);
  84. #if WINVER < 0x0602/* From "sdkddkver.h" and defines the SDK version not the host */
  85. // 6ca50344-051a-4ded-9779-a43305165e35
  86. DEFINE_GUID(CLSID_CMSH264EncoderMFT, // MS H.264 encoder
  87. 0x6ca50344, 0x051a, 0x4ded, 0x97, 0x79, 0xa4, 0x33, 0x05, 0x16, 0x5e, 0x35);
  88. #endif /* WINVER */
  89. #define IsWin7_OrLater(dwMajorVersion, dwMinorVersion) ( (dwMajorVersion > 6) || ( (dwMajorVersion == 6) && (dwMinorVersion >= 1) ) )
  90. #define IsWin8_OrLater(dwMajorVersion, dwMinorVersion) ( (dwMajorVersion > 6) || ( (dwMajorVersion == 6) && (dwMinorVersion >= 2) ) )
  91. HRESULT MFUtils::Startup()
  92. {
  93. if(!g_bStarted) {
  94. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  95. if(SUCCEEDED(hr) || hr == 0x80010106) { // 0x80010106 when called from managed code (e.g. Boghe) - More info: http://support.microsoft.com/kb/824480
  96. hr = MFStartup(MF_VERSION);
  97. }
  98. g_bStarted = SUCCEEDED(hr);
  99. OSVERSIONINFO osvi;
  100. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  101. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  102. GetVersionEx(&osvi);
  103. g_dwMajorVersion = osvi.dwMajorVersion;
  104. g_dwMinorVersion = osvi.dwMinorVersion;
  105. return hr;
  106. }
  107. return S_OK;
  108. }
  109. HRESULT MFUtils::Shutdown()
  110. {
  111. if(g_bStarted) {
  112. g_bStarted = false;
  113. return S_OK;
  114. }
  115. return S_OK;
  116. }
  117. BOOL MFUtils::IsD3D9Supported()
  118. {
  119. if (MFUtils::g_bD3D9Checked) {
  120. return MFUtils::g_bD3D9Supported;
  121. }
  122. MFUtils::g_bD3D9Checked = TRUE;
  123. HRESULT hr = S_OK;
  124. IDirect3D9* pD3D = NULL;
  125. D3DDISPLAYMODE mode = { 0 };
  126. D3DPRESENT_PARAMETERS pp = {0};
  127. IDirect3DDevice9* pDevice = NULL;
  128. CHECK_HR(hr = MFUtils::Startup());
  129. if (!(pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
  130. CHECK_HR(hr = E_OUTOFMEMORY);
  131. }
  132. hr = pD3D->GetAdapterDisplayMode(
  133. D3DADAPTER_DEFAULT,
  134. &mode
  135. );
  136. if (FAILED(hr)) {
  137. goto bail;
  138. }
  139. hr = pD3D->CheckDeviceType(
  140. D3DADAPTER_DEFAULT,
  141. D3DDEVTYPE_HAL,
  142. mode.Format,
  143. D3DFMT_X8R8G8B8,
  144. TRUE // windowed
  145. );
  146. if (FAILED(hr)) {
  147. goto bail;
  148. }
  149. pp.BackBufferFormat = D3DFMT_X8R8G8B8;
  150. pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  151. pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  152. pp.Windowed = TRUE;
  153. pp.hDeviceWindow = GetDesktopWindow();
  154. hr = pD3D->CreateDevice(
  155. D3DADAPTER_DEFAULT,
  156. D3DDEVTYPE_HAL,
  157. pp.hDeviceWindow,
  158. D3DCREATE_HARDWARE_VERTEXPROCESSING,
  159. &pp,
  160. &pDevice
  161. );
  162. if (FAILED(hr)) {
  163. goto bail;
  164. }
  165. // Everythings is OK
  166. MFUtils::g_bD3D9Supported = TRUE;
  167. TSK_DEBUG_INFO("D3D9 supported");
  168. bail:
  169. if (!MFUtils::g_bD3D9Supported) {
  170. TSK_DEBUG_WARN("D3D9 not supported");
  171. }
  172. SafeRelease(&pDevice);
  173. SafeRelease(&pD3D);
  174. return MFUtils::g_bD3D9Supported;
  175. }
  176. BOOL MFUtils::IsLowLatencyH264Supported()
  177. {
  178. if(MFUtils::g_bLowLatencyH264Checked) {
  179. return MFUtils::g_bLowLatencyH264Supported;
  180. }
  181. #if PLUGIN_MF_DISABLE_CODECS
  182. MFUtils::g_bLowLatencyH264Checked = TRUE;
  183. MFUtils::g_bLowLatencyH264Supported = FALSE;
  184. #else
  185. Startup();
  186. HRESULT hr = S_OK;
  187. IMFTransform *pEncoderMFT = NULL;
  188. IMFTransform *pDecoderMFT = NULL;
  189. MFCodecVideoH264* pEncoderCodec = NULL;
  190. MFCodecVideoH264* pDecoderCodec = NULL;
  191. static const BOOL IsEncoderYes = TRUE;
  192. // Encoder
  193. hr = MFUtils::GetBestCodec(IsEncoderYes, MFMediaType_Video, MFVideoFormat_NV12, MFVideoFormat_H264, &pEncoderMFT);
  194. if(FAILED(hr)) {
  195. TSK_DEBUG_INFO("No low latency H.264 encoder");
  196. goto bail;
  197. }
  198. // Decoder
  199. hr = MFUtils::GetBestCodec(!IsEncoderYes, MFMediaType_Video, MFVideoFormat_H264, MFVideoFormat_NV12, &pDecoderMFT);
  200. if(FAILED(hr)) {
  201. TSK_DEBUG_INFO("No low latency H.264 decoder");
  202. goto bail;
  203. }
  204. // Make sure both encoder and decoder are working well. Check encoding/decoding 1080p@30 would work.
  205. TSK_DEBUG_INFO("Probing H.264 MFT encoder...");
  206. pEncoderCodec = MFCodecVideoH264::CreateCodecH264Main(MFCodecType_Encoder, pEncoderMFT);
  207. if(!pEncoderCodec) {
  208. CHECK_HR(hr = E_FAIL);
  209. }
  210. CHECK_HR(hr = pEncoderCodec->Initialize(
  211. 30, // FPS
  212. 1920, // WIDTH
  213. 1080, // HEIGHT
  214. tmedia_get_video_bandwidth_kbps_2(1920, 1080, 30) * 1024) // BITRATE
  215. );
  216. CHECK_HR(pEncoderCodec->IsSetSliceMaxSizeInBytesSupported(MFUtils::g_bLowLatencyH264SupportsMaxSliceSize));
  217. TSK_DEBUG_INFO("Probing H.264 MFT decoder...");
  218. pDecoderCodec = MFCodecVideoH264::CreateCodecH264Main(MFCodecType_Decoder, pDecoderMFT);
  219. if(!pDecoderCodec) {
  220. CHECK_HR(hr = E_FAIL);
  221. }
  222. CHECK_HR(hr = pDecoderCodec->Initialize(
  223. 30, // FPS
  224. 1920, // WIDTH
  225. 1080 // HEIGHT
  226. ));
  227. bail:
  228. MFUtils::g_bLowLatencyH264Checked = TRUE;
  229. MFUtils::g_bLowLatencyH264Supported = SUCCEEDED(hr) ? TRUE : FALSE;
  230. SafeRelease(&pEncoderMFT);
  231. SafeRelease(&pEncoderCodec);
  232. SafeRelease(&pDecoderMFT);
  233. SafeRelease(&pDecoderCodec);
  234. #endif /* PLUGIN_MF_DISABLE_CODECS */
  235. return MFUtils::g_bLowLatencyH264Supported;
  236. }
  237. BOOL MFUtils::IsLowLatencyH264SupportsMaxSliceSize()
  238. {
  239. return MFUtils::IsLowLatencyH264Supported() && MFUtils::g_bLowLatencyH264SupportsMaxSliceSize;
  240. }
  241. HRESULT MFUtils::IsAsyncMFT(
  242. IMFTransform *pMFT, // The MFT to check
  243. BOOL* pbIsAsync // Whether the MFT is Async
  244. )
  245. {
  246. if(!pbIsAsync || !pMFT) {
  247. return E_POINTER;
  248. }
  249. IMFAttributes *pAttributes = NULL;
  250. UINT32 nIsAsync = 0;
  251. HRESULT hr = S_OK;
  252. hr = pMFT->GetAttributes(&pAttributes);
  253. if(SUCCEEDED(hr)) {
  254. hr = pAttributes->GetUINT32(MF_TRANSFORM_ASYNC, &nIsAsync);
  255. }
  256. // Never fails: just say not Async
  257. CHECK_HR(hr = S_OK);
  258. *pbIsAsync = !!nIsAsync;
  259. bail:
  260. return hr;
  261. }
  262. HRESULT MFUtils::UnlockAsyncMFT(
  263. IMFTransform *pMFT // The MFT to unlock
  264. )
  265. {
  266. IMFAttributes *pAttributes = NULL;
  267. UINT32 nValue = 0;
  268. HRESULT hr = S_OK;
  269. hr = pMFT->GetAttributes(&pAttributes);
  270. if(FAILED(hr)) {
  271. hr = S_OK;
  272. goto bail;
  273. }
  274. hr = pAttributes->GetUINT32(MF_TRANSFORM_ASYNC, &nValue);
  275. if(FAILED(hr)) {
  276. hr = S_OK;
  277. goto bail;
  278. }
  279. if(nValue == TRUE) {
  280. CHECK_HR(hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE));
  281. }
  282. bail:
  283. SafeRelease(&pAttributes);
  284. return hr;
  285. }
  286. //-------------------------------------------------------------------
  287. // CreatePCMAudioType
  288. //
  289. // Creates a media type that describes an uncompressed PCM audio
  290. // format.
  291. //-------------------------------------------------------------------
  292. HRESULT MFUtils::CreatePCMAudioType(
  293. UINT32 sampleRate, // Samples per second
  294. UINT32 bitsPerSample, // Bits per sample
  295. UINT32 cChannels, // Number of channels
  296. IMFMediaType **ppType // Receives a pointer to the media type.
  297. )
  298. {
  299. HRESULT hr = S_OK;
  300. IMFMediaType *pType = NULL;
  301. // Calculate derived values.
  302. UINT32 blockAlign = cChannels * (bitsPerSample / 8);
  303. UINT32 bytesPerSecond = blockAlign * sampleRate;
  304. // Create the empty media type.
  305. hr = MFCreateMediaType(&pType);
  306. // Set attributes on the type.
  307. if (SUCCEEDED(hr)) {
  308. hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
  309. }
  310. if (SUCCEEDED(hr)) {
  311. hr = pType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
  312. }
  313. if (SUCCEEDED(hr)) {
  314. hr = pType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, cChannels);
  315. }
  316. if (SUCCEEDED(hr)) {
  317. hr = pType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate);
  318. }
  319. if (SUCCEEDED(hr)) {
  320. hr = pType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign);
  321. }
  322. if (SUCCEEDED(hr)) {
  323. hr = pType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond);
  324. }
  325. if (SUCCEEDED(hr)) {
  326. hr = pType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
  327. }
  328. if (SUCCEEDED(hr)) {
  329. hr = pType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
  330. }
  331. if (SUCCEEDED(hr)) {
  332. // Return the type to the caller.
  333. *ppType = pType;
  334. (*ppType)->AddRef();
  335. }
  336. SafeRelease(&pType);
  337. return hr;
  338. }
  339. //-------------------------------------------------------------------
  340. // CreateVideoType
  341. //
  342. // Creates a media type that describes a video subtype
  343. // format.
  344. //-------------------------------------------------------------------
  345. HRESULT MFUtils::CreateVideoType(
  346. const GUID* subType, // video subType
  347. IMFMediaType **ppType, // Receives a pointer to the media type.
  348. UINT32 unWidth, // Video width (0 to ignore)
  349. UINT32 unHeight // Video height (0 to ignore)
  350. )
  351. {
  352. HRESULT hr = S_OK;
  353. IMFMediaType *pType = NULL;
  354. CHECK_HR(hr = MFCreateMediaType(&pType));
  355. CHECK_HR(hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
  356. CHECK_HR(hr = pType->SetGUID(MF_MT_SUBTYPE, *subType));
  357. CHECK_HR(hr = pType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)); // UnCompressed
  358. CHECK_HR(hr = pType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE)); // UnCompressed
  359. CHECK_HR(hr = pType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
  360. if(unWidth > 0 && unHeight > 0) {
  361. CHECK_HR(hr = MFSetAttributeSize(pType, MF_MT_FRAME_SIZE, unWidth, unHeight));
  362. }
  363. *ppType = pType;
  364. (*ppType)->AddRef();
  365. bail:
  366. SafeRelease(&pType);
  367. return hr;
  368. }
  369. //-------------------------------------------------------------------
  370. // Name: ValidateVideoFormat
  371. // Description: Validates a media type for this sink.
  372. //-------------------------------------------------------------------
  373. HRESULT MFUtils::ValidateVideoFormat(IMFMediaType *pmt)
  374. {
  375. GUID major_type = GUID_NULL;
  376. GUID subtype = GUID_NULL;
  377. MFVideoInterlaceMode interlace = MFVideoInterlace_Unknown;
  378. UINT32 val = 0;
  379. BOOL bFoundMatchingSubtype = FALSE;
  380. HRESULT hr = S_OK;
  381. // Major type must be video.
  382. CHECK_HR(hr = pmt->GetGUID(MF_MT_MAJOR_TYPE, &major_type));
  383. if (major_type != MFMediaType_Video) {
  384. CHECK_HR(hr = MF_E_INVALIDMEDIATYPE);
  385. }
  386. // Subtype must be one of the subtypes in our global list.
  387. // Get the subtype GUID.
  388. CHECK_HR(hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype));
  389. #if 0
  390. // Look for the subtype in our list of accepted types.
  391. for (DWORD i = 0; i < g_NumVideoSubtypes; i++) {
  392. if (subtype == *g_VideoSubtypes[i]) {
  393. bFoundMatchingSubtype = TRUE;
  394. break;
  395. }
  396. }
  397. if (!bFoundMatchingSubtype) {
  398. CHECK_HR(hr = MF_E_INVALIDMEDIATYPE);
  399. }
  400. #endif
  401. // Video must be progressive frames.
  402. CHECK_HR(hr = pmt->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&interlace));
  403. if (interlace != MFVideoInterlace_Progressive) {
  404. CHECK_HR(hr = MF_E_INVALIDMEDIATYPE);
  405. }
  406. bail:
  407. return hr;
  408. }
  409. HRESULT MFUtils::ConvertVideoTypeToUncompressedType(
  410. IMFMediaType *pType, // Pointer to an encoded video type.
  411. const GUID& subtype, // Uncompressed subtype (eg, RGB-32, AYUV)
  412. IMFMediaType **ppType // Receives a matching uncompressed video type.
  413. )
  414. {
  415. IMFMediaType *pTypeUncomp = NULL;
  416. HRESULT hr = S_OK;
  417. GUID majortype = { 0 };
  418. MFRatio par = { 0 };
  419. hr = pType->GetMajorType(&majortype);
  420. if (majortype != MFMediaType_Video) {
  421. return MF_E_INVALIDMEDIATYPE;
  422. }
  423. // Create a new media type and copy over all of the items.
  424. // This ensures that extended color information is retained.
  425. if (SUCCEEDED(hr)) {
  426. hr = MFCreateMediaType(&pTypeUncomp);
  427. }
  428. if (SUCCEEDED(hr)) {
  429. hr = pType->CopyAllItems(pTypeUncomp);
  430. }
  431. // Set the subtype.
  432. if (SUCCEEDED(hr)) {
  433. hr = pTypeUncomp->SetGUID(MF_MT_SUBTYPE, subtype);
  434. }
  435. // Uncompressed means all samples are independent.
  436. if (SUCCEEDED(hr)) {
  437. hr = pTypeUncomp->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
  438. }
  439. // Fix up PAR if not set on the original type.
  440. if (SUCCEEDED(hr)) {
  441. hr = MFGetAttributeRatio(
  442. pTypeUncomp,
  443. MF_MT_PIXEL_ASPECT_RATIO,
  444. (UINT32*)&par.Numerator,
  445. (UINT32*)&par.Denominator
  446. );
  447. // Default to square pixels.
  448. if (FAILED(hr)) {
  449. hr = MFSetAttributeRatio(
  450. pTypeUncomp,
  451. MF_MT_PIXEL_ASPECT_RATIO,
  452. 1, 1
  453. );
  454. }
  455. }
  456. if (SUCCEEDED(hr)) {
  457. *ppType = pTypeUncomp;
  458. (*ppType)->AddRef();
  459. }
  460. SafeRelease(&pTypeUncomp);
  461. return hr;
  462. }
  463. HRESULT MFUtils::CreateMediaSample(
  464. DWORD cbData, // Maximum buffer size
  465. IMFSample **ppSample // Receives the sample
  466. )
  467. {
  468. assert(ppSample);
  469. HRESULT hr = S_OK;
  470. IMFSample *pSample = NULL;
  471. IMFMediaBuffer *pBuffer = NULL;
  472. CHECK_HR(hr = MFCreateSample(&pSample));
  473. CHECK_HR(hr = MFCreateMemoryBuffer(cbData, &pBuffer));
  474. CHECK_HR(hr = pSample->AddBuffer(pBuffer));
  475. *ppSample = pSample;
  476. (*ppSample)->AddRef();
  477. bail:
  478. SafeRelease(&pSample);
  479. SafeRelease(&pBuffer);
  480. return hr;
  481. }
  482. // Gets the best encoder and decoder. Up to the caller to release the returned pointer
  483. HRESULT MFUtils::GetBestCodec(
  484. BOOL bEncoder, // Whether we request an encoder or not (TRUE=encoder, FALSE=decoder)
  485. const GUID& mediaType, // The MediaType
  486. const GUID& inputFormat, // The input MediaFormat (e.g. MFVideoFormat_NV12)
  487. const GUID& outputFormat, // The output MediaFormat (e.g. MFVideoFormat_H264)
  488. IMFTransform **ppMFT // Receives the decoder/encoder transform
  489. )
  490. {
  491. assert(ppMFT);
  492. assert(mediaType == MFMediaType_Video || mediaType == MFMediaType_Audio); // only audio and video codecs are support for now
  493. *ppMFT = NULL;
  494. HRESULT hr = S_OK;
  495. if(outputFormat == MFVideoFormat_H264 || inputFormat == MFVideoFormat_H264) {
  496. if(bEncoder) {
  497. // Force using Intel Quick Sync Encoder
  498. hr = CoCreateInstance(CLSID_MF_INTEL_H264EncFilter, NULL,
  499. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(ppMFT));
  500. if(SUCCEEDED(hr) && *ppMFT) {
  501. TSK_DEBUG_INFO("Using Intel Quick Sync encoder :)");
  502. return hr;
  503. }
  504. TSK_DEBUG_INFO("Not using Intel Quick Sync encoder :(");
  505. }
  506. else {
  507. #if !PLUGIN_MF_DISABLE_ASYNC_DECODERS // Intel Quick Sync decoder is asynchronous
  508. // Force using Intel Quick Sync Decoder
  509. hr = CoCreateInstance(CLSID_MF_INTEL_H264DecFilter, NULL,
  510. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(ppMFT));
  511. #endif
  512. if(SUCCEEDED(hr) && *ppMFT) {
  513. TSK_DEBUG_INFO("Using Intel Quick Sync decoder :)");
  514. return hr;
  515. }
  516. TSK_DEBUG_INFO("Not using Intel Quick Sync decoder :(");
  517. }
  518. }
  519. UINT32 count = 0;
  520. BOOL bAsync = FALSE;
  521. GUID guidActivateCLSID = GUID_NULL;
  522. IMFActivate **ppActivate = NULL;
  523. MFT_REGISTER_TYPE_INFO infoInput = { mediaType, inputFormat };
  524. MFT_REGISTER_TYPE_INFO infoOutput = { mediaType, outputFormat };
  525. UINT32 unFlags = MFT_ENUM_FLAG_HARDWARE |
  526. MFT_ENUM_FLAG_SYNCMFT |
  527. MFT_ENUM_FLAG_ASYNCMFT |
  528. MFT_ENUM_FLAG_LOCALMFT |
  529. MFT_ENUM_FLAG_TRANSCODE_ONLY | // Otherwise Intel Quick Sync will not be listed
  530. MFT_ENUM_FLAG_SORTANDFILTER;
  531. hr = MFTEnumEx(
  532. (mediaType == MFMediaType_Video) ? (bEncoder ? MFT_CATEGORY_VIDEO_ENCODER : MFT_CATEGORY_VIDEO_DECODER) : (bEncoder ? MFT_CATEGORY_AUDIO_ENCODER : MFT_CATEGORY_AUDIO_DECODER),
  533. unFlags,
  534. (inputFormat == GUID_NULL) ? NULL : &infoInput, // Input type
  535. (outputFormat == GUID_NULL) ? NULL : &infoOutput, // Output type
  536. &ppActivate,
  537. &count
  538. );
  539. for(UINT32 i = 0; i < count; ++i) {
  540. SafeRelease(ppMFT);
  541. hr = ppActivate[i]->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guidActivateCLSID);
  542. if(FAILED(hr)) {
  543. continue;
  544. }
  545. if(bEncoder) {
  546. // Encoder
  547. if(guidActivateCLSID == CLSID_CMSH264EncoderMFT) { // MS H.264 encoder ?
  548. if(PLUGIN_MF_DISABLE_MS_H264_ENCODER) {
  549. // Microsoft H.264 encoder is disabled
  550. TSK_DEBUG_INFO("MS H.264 encoder is disabled...skipping");
  551. continue;
  552. }
  553. if(!IsWin8_OrLater(g_dwMajorVersion, g_dwMinorVersion)) {
  554. // Microsoft H.264 encoder doesn't support low latency on Win7.
  555. TSK_DEBUG_INFO("MS H.264 encoder doesn't support low delay on (%ld, %ld)...skipping", g_dwMajorVersion, g_dwMinorVersion);
  556. continue;
  557. }
  558. }
  559. }
  560. else {
  561. // Decoder
  562. if(guidActivateCLSID == CLSID_CMSH264DecoderMFT) { // MS H.264 decoder ?
  563. if(!IsWin8_OrLater(g_dwMajorVersion, g_dwMinorVersion)) {
  564. // Microsoft H.264 decoder doesn't support low latency on Win7.
  565. TSK_DEBUG_INFO("MS H.264 decoder doesn't support low delay on (%ld, %ld)...skipping", g_dwMajorVersion, g_dwMinorVersion);
  566. continue;
  567. }
  568. }
  569. }
  570. hr = ppActivate[i]->ActivateObject(IID_PPV_ARGS(ppMFT));
  571. if(SUCCEEDED(hr) && *ppMFT) { // For now we just get the first one. FIXME: Give HW encoders/decoders higher priority.
  572. if(bEncoder) {
  573. // Encoder
  574. }
  575. else {
  576. // Decoder
  577. #if PLUGIN_MF_DISABLE_ASYNC_DECODERS
  578. hr = IsAsyncMFT(*ppMFT, &bAsync);
  579. if(bAsync) {
  580. TSK_DEBUG_INFO("Skipping async decoder because not supported yet");
  581. continue; // Async decoders not supported yet
  582. }
  583. #endif
  584. }
  585. break;
  586. }
  587. }
  588. for (UINT32 i = 0; i < count; i++) {
  589. ppActivate[i]->Release();
  590. }
  591. CoTaskMemFree(ppActivate);
  592. return *ppMFT ? S_OK : MF_E_NOT_FOUND;
  593. }
  594. HRESULT MFUtils::IsVideoProcessorSupported(BOOL *pbSupported)
  595. {
  596. HRESULT hr = S_OK;
  597. IMFTransform *pTransform = NULL;
  598. if(!pbSupported) {
  599. CHECK_HR(hr = E_POINTER);
  600. }
  601. hr = CoCreateInstance(CLSID_VideoProcessorMFT, NULL,
  602. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTransform));
  603. *pbSupported = SUCCEEDED(hr);
  604. if(FAILED(hr)) {
  605. hr = S_OK; // not an error
  606. }
  607. bail:
  608. SafeRelease(&pTransform);
  609. return hr;
  610. }
  611. HRESULT MFUtils::GetBestVideoProcessor(
  612. const GUID& inputFormat, // The input MediaFormat (e.g. MFVideoFormat_I420)
  613. const GUID& outputFormat, // The output MediaFormat (e.g. MFVideoFormat_NV12)
  614. IMFTransform **ppProcessor // Receives the video processor
  615. )
  616. {
  617. assert(ppProcessor);
  618. *ppProcessor = NULL;
  619. HRESULT hr = S_OK;
  620. UINT32 count = 0;
  621. IMFActivate **ppActivate = NULL;
  622. MFT_REGISTER_TYPE_INFO infoInput = { MFMediaType_Video, inputFormat };
  623. MFT_REGISTER_TYPE_INFO infoOutput = { MFMediaType_Video, outputFormat };
  624. UINT32 unFlags = MFT_ENUM_FLAG_HARDWARE |
  625. MFT_ENUM_FLAG_SYNCMFT |
  626. MFT_ENUM_FLAG_LOCALMFT |
  627. MFT_ENUM_FLAG_SORTANDFILTER;
  628. hr = MFTEnumEx(
  629. MFT_CATEGORY_VIDEO_PROCESSOR,
  630. unFlags,
  631. &infoInput, // Input type
  632. &infoOutput, // Output type
  633. &ppActivate,
  634. &count
  635. );
  636. for(UINT32 i = 0; i < count; ++i) {
  637. hr = ppActivate[i]->ActivateObject(IID_PPV_ARGS(ppProcessor));
  638. if(SUCCEEDED(hr) && *ppProcessor) {
  639. break;
  640. }
  641. SafeRelease(ppProcessor);
  642. }
  643. for (UINT32 i = 0; i < count; i++) {
  644. ppActivate[i]->Release();
  645. }
  646. CoTaskMemFree(ppActivate);
  647. return *ppProcessor ? S_OK : MF_E_NOT_FOUND;
  648. }
  649. // Add an transform node to a topology.
  650. HRESULT MFUtils::AddTransformNode(
  651. IMFTopology *pTopology, // Topology.
  652. IMFTransform *pMFT, // MFT.
  653. DWORD dwId, // Identifier of the stream sink.
  654. IMFTopologyNode **ppNode // Receives the node pointer.
  655. )
  656. {
  657. *ppNode = NULL;
  658. IMFTopologyNode *pNode = NULL;
  659. HRESULT hr = S_OK;
  660. // Create the node.
  661. CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pNode));
  662. // Set the object pointer.
  663. CHECK_HR(hr = pNode->SetObject(pMFT));
  664. CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId));
  665. CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE));
  666. // Add the node to the topology.
  667. CHECK_HR(hr = pTopology->AddNode(pNode));
  668. // Return the pointer to the caller.
  669. *ppNode = pNode;
  670. (*ppNode)->AddRef();
  671. bail:
  672. SafeRelease(&pNode);
  673. return hr;
  674. }
  675. // Sets the IMFStreamSink pointer on an output node.
  676. HRESULT MFUtils::BindOutputNode(
  677. IMFTopologyNode *pNode // The Node
  678. )
  679. {
  680. assert(pNode);
  681. HRESULT hr = S_OK;
  682. IUnknown *pNodeObject = NULL;
  683. IMFActivate *pActivate = NULL;
  684. IMFStreamSink *pStream = NULL;
  685. IMFMediaSink *pSink = NULL;
  686. // Get the node's object pointer.
  687. CHECK_HR(hr = pNode->GetObject(&pNodeObject));
  688. // The object pointer should be one of the following:
  689. // 1. An activation object for the media sink.
  690. // 2. The stream sink.
  691. // If it's #2, then we're already done.
  692. // First, check if it's an activation object.
  693. CHECK_HR(hr = pNodeObject->QueryInterface(IID_PPV_ARGS(&pActivate)));
  694. if (SUCCEEDED(hr)) {
  695. DWORD dwStreamID = 0;
  696. // The object pointer is an activation object.
  697. // Try to create the media sink.
  698. hr = pActivate->ActivateObject(IID_PPV_ARGS(&pSink));
  699. // Look up the stream ID. (Default to zero.)
  700. if (SUCCEEDED(hr)) {
  701. dwStreamID = MFGetAttributeUINT32(pNode, MF_TOPONODE_STREAMID, 0);
  702. }
  703. // Now try to get or create the stream sink.
  704. // Check if the media sink already has a stream sink with the requested ID.
  705. if (SUCCEEDED(hr)) {
  706. hr = pSink->GetStreamSinkById(dwStreamID, &pStream);
  707. if (FAILED(hr)) {
  708. // Try to add a new stream sink.
  709. hr = pSink->AddStreamSink(dwStreamID, NULL, &pStream);
  710. }
  711. }
  712. // Replace the node's object pointer with the stream sink.
  713. if (SUCCEEDED(hr)) {
  714. hr = pNode->SetObject(pStream);
  715. }
  716. }
  717. else {
  718. // Not an activation object. Is it a stream sink?
  719. hr = pNodeObject->QueryInterface(IID_PPV_ARGS(&pStream));
  720. }
  721. bail:
  722. SafeRelease(&pNodeObject);
  723. SafeRelease(&pActivate);
  724. SafeRelease(&pStream);
  725. SafeRelease(&pSink);
  726. return hr;
  727. }
  728. // Add an output node to a topology.
  729. HRESULT MFUtils::AddOutputNode(
  730. IMFTopology *pTopology, // Topology.
  731. IMFActivate *pActivate, // Media sink activation object.
  732. DWORD dwId, // Identifier of the stream sink.
  733. IMFTopologyNode **ppNode) // Receives the node pointer
  734. {
  735. IMFTopologyNode *pNode = NULL;
  736. HRESULT hr = S_OK;
  737. CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode));
  738. CHECK_HR(hr = pNode->SetObject(pActivate));
  739. CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId));
  740. CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE));
  741. CHECK_HR(hr = pTopology->AddNode(pNode));
  742. // Return the pointer to the caller.
  743. *ppNode = pNode;
  744. (*ppNode)->AddRef();
  745. bail:
  746. SafeRelease(&pNode);
  747. return hr;
  748. }
  749. // Add a source node to a topology
  750. HRESULT MFUtils::AddSourceNode(
  751. IMFTopology *pTopology, // Topology.
  752. IMFMediaSource *pSource, // Media source.
  753. IMFPresentationDescriptor *pPD, // Presentation descriptor.
  754. IMFStreamDescriptor *pSD, // Stream descriptor.
  755. IMFTopologyNode **ppNode // Receives the node pointer.
  756. )
  757. {
  758. IMFTopologyNode *pNode = NULL;
  759. HRESULT hr = S_OK;
  760. CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode));
  761. CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource));
  762. CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD));
  763. CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD));
  764. CHECK_HR(hr = pTopology->AddNode(pNode));
  765. // Return the pointer to the caller.
  766. *ppNode = pNode;
  767. (*ppNode)->AddRef();
  768. bail:
  769. SafeRelease(&pNode);
  770. return hr;
  771. }
  772. // Create the topology
  773. //
  774. // [source] -> (Transform) -> [SinkMain]
  775. // \-> (SinkPreview)
  776. //
  777. HRESULT MFUtils::CreateTopology(
  778. IMFMediaSource *pSource, // Media source
  779. IMFTransform *pTransform, // Transform filter (e.g. encoder or decoder) to insert between the source and Sink. NULL is valid.
  780. IMFActivate *pSinkActivateMain, // Main sink (e.g. sample grabber or EVR).
  781. IMFActivate *pSinkActivatePreview, // Preview sink. Optional. Could be NULL.
  782. IMFMediaType *pIputTypeMain, // Main sink input MediaType
  783. IMFTopology **ppTopo // Receives the newly created topology
  784. )
  785. {
  786. IMFTopology *pTopology = NULL;
  787. IMFPresentationDescriptor *pPD = NULL;
  788. IMFStreamDescriptor *pSD = NULL;
  789. IMFMediaTypeHandler *pHandler = NULL;
  790. IMFTopologyNode *pNodeSource = NULL;
  791. IMFTopologyNode *pNodeSinkMain = NULL;
  792. IMFTopologyNode *pNodeSinkPreview = NULL;
  793. IMFTopologyNode *pNodeTransform = NULL;
  794. IMFTopologyNode *pNodeTee = NULL;
  795. IMFMediaType *pMediaType = NULL;
  796. IMFTransform *pVideoProcessor = NULL;
  797. IMFTopologyNode *pNodeVideoProcessor = NULL;
  798. IMFTransform *pConvFrameRate = NULL;
  799. IMFTransform *pConvSize = NULL;
  800. IMFTransform *pConvColor = NULL;
  801. IMFTopologyNode *pNodeConvFrameRate = NULL;
  802. IMFTopologyNode *pNodeConvSize = NULL;
  803. IMFTopologyNode *pNodeConvColor = NULL;
  804. IMFMediaType *pTransformInputType = NULL;
  805. IMFMediaType *pSinkMainInputType = NULL;
  806. const IMFTopologyNode *pcNodeBeforeSinkMain = NULL;
  807. HRESULT hr = S_OK;
  808. DWORD cStreams = 0;
  809. BOOL bSourceFound = FALSE;
  810. BOOL bSupportedSize = FALSE;
  811. BOOL bSupportedFps = FALSE;
  812. BOOL bSupportedFormat = FALSE;
  813. BOOL bVideoProcessorSupported = FALSE;
  814. GUID inputMajorType, inputSubType;
  815. CHECK_HR(hr = IsVideoProcessorSupported(&bVideoProcessorSupported));
  816. CHECK_HR(hr = pIputTypeMain->GetMajorType(&inputMajorType));
  817. CHECK_HR(hr = MFCreateTopology(&pTopology));
  818. CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
  819. CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
  820. for (DWORD i = 0; i < cStreams; i++) {
  821. BOOL fSelected = FALSE;
  822. GUID majorType;
  823. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD));
  824. CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
  825. CHECK_HR(hr = pHandler->GetMajorType(&majorType));
  826. if (majorType == inputMajorType && fSelected) {
  827. CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pNodeSource));
  828. CHECK_HR(hr = pNodeSource->SetTopoNodeID(MFUtils::g_ullTopoIdSource));
  829. CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivateMain, 0, &pNodeSinkMain));
  830. CHECK_HR(hr = pNodeSinkMain->SetTopoNodeID(MFUtils::g_ullTopoIdSinkMain));
  831. CHECK_HR(hr = MFUtils::BindOutputNode(pNodeSinkMain)); // To avoid MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED
  832. //
  833. // Create preview
  834. //
  835. if(pSinkActivatePreview) {
  836. CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivatePreview, 0, &pNodeSinkPreview));
  837. CHECK_HR(hr = pNodeSinkPreview->SetTopoNodeID(MFUtils::g_ullTopoIdSinkPreview));
  838. CHECK_HR(hr = MFUtils::BindOutputNode(pNodeSinkPreview));
  839. CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &pNodeTee));
  840. CHECK_HR(hr = pTopology->AddNode(pNodeTee));
  841. }
  842. //
  843. // Create converters
  844. //
  845. if(majorType == MFMediaType_Video) {
  846. // Even when size matches the topology could add a resizer which doesn't keep ratio when resizing while video processor does.
  847. if(!bVideoProcessorSupported) {
  848. hr = IsSupported(
  849. pPD,
  850. i,
  851. pIputTypeMain,
  852. &bSupportedSize,
  853. &bSupportedFps,
  854. &bSupportedFormat);
  855. }
  856. CHECK_HR(hr = pIputTypeMain->GetGUID(MF_MT_SUBTYPE, &inputSubType));
  857. if(!bSupportedSize || !bSupportedFps || !bSupportedFormat) {
  858. // Use video processor single MFT or 3 different MFTs
  859. if(!pVideoProcessor) {
  860. hr = CoCreateInstance(CLSID_VideoProcessorMFT, NULL,
  861. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pVideoProcessor));
  862. }
  863. if(!pVideoProcessor) {
  864. // Video Resizer DSP(http://msdn.microsoft.com/en-us/library/windows/desktop/ff819491(v=vs.85).aspx) supports I420 only
  865. if(!bSupportedSize && !pConvSize && inputSubType == MFVideoFormat_I420) {
  866. hr = CoCreateInstance(CLSID_CResizerDMO, NULL,
  867. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pConvSize));
  868. }
  869. // Frame Rate Converter DSP(http://msdn.microsoft.com/en-us/library/windows/desktop/ff819100(v=vs.85).aspx) supports neither NV12 nor I420
  870. /*if(!bSupportedFps && !pConvFrameRate)
  871. {
  872. hr = CoCreateInstance(CLSID_CFrameRateConvertDmo, NULL,
  873. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pConvFrameRate));
  874. }*/
  875. // Color Converter DSP (http://msdn.microsoft.com/en-us/library/windows/desktop/ff819079(v=vs.85).aspx) supports both NV12 and I420
  876. if(!bSupportedFormat && !pConvColor) {
  877. hr = CoCreateInstance(CLSID_CColorConvertDMO, NULL,
  878. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pConvColor));
  879. }
  880. }
  881. }
  882. else {
  883. // MediaType supported
  884. CHECK_HR(hr = pHandler->SetCurrentMediaType(pIputTypeMain));
  885. }
  886. if(pVideoProcessor && !pNodeVideoProcessor) {
  887. CHECK_HR(hr = AddTransformNode(pTopology, pVideoProcessor, 0, &pNodeVideoProcessor));
  888. CHECK_HR(hr = pNodeVideoProcessor->SetTopoNodeID(MFUtils::g_ullTopoIdVideoProcessor));
  889. }
  890. if(pConvColor && !pNodeConvColor) {
  891. CHECK_HR(hr = AddTransformNode(pTopology, pConvColor, 0, &pNodeConvColor));
  892. }
  893. if(pConvFrameRate && !pNodeConvFrameRate) {
  894. CHECK_HR(hr = AddTransformNode(pTopology, pConvFrameRate, 0, &pNodeConvFrameRate));
  895. }
  896. if(pConvSize && !pNodeConvSize) {
  897. CHECK_HR(hr = AddTransformNode(pTopology, pConvSize, 0, &pNodeConvSize));
  898. }
  899. } // if(majorType == MFMediaType_Video)
  900. //
  901. // Set media type
  902. //
  903. if(pTransform) {
  904. CHECK_HR(hr = AddTransformNode(pTopology, pTransform, 0, &pNodeTransform));
  905. hr = pTransform->GetInputCurrentType(0, &pTransformInputType);
  906. if(FAILED(hr)) {
  907. pTransformInputType = pIputTypeMain;
  908. pTransformInputType->AddRef();
  909. hr = S_OK;
  910. }
  911. if(pVideoProcessor) {
  912. CHECK_HR(hr = pVideoProcessor->SetOutputType(0, pTransformInputType, 0));
  913. }
  914. else {
  915. if(pConvColor) {
  916. /*CHECK_HR*/(hr = pConvColor->SetOutputType(0, pTransformInputType, 0));
  917. }
  918. if(pConvFrameRate) {
  919. /*CHECK_HR*/(hr = pConvFrameRate->SetOutputType(0, pTransformInputType, 0));
  920. }
  921. if(pConvSize) {
  922. // Transform requires NV12
  923. //Video Resizer DSP(http://msdn.microsoft.com/en-us/library/windows/desktop/ff819491(v=vs.85).aspx) doesn't support NV12
  924. //*CHECK_HR*/(hr = pConvSize->SetOutputType(0, pTransformInputType, 0));
  925. }
  926. }
  927. }
  928. else {
  929. hr = pNodeSinkMain->GetInputPrefType(0, &pSinkMainInputType);
  930. if(FAILED(hr)) {
  931. pSinkMainInputType = pIputTypeMain;
  932. pSinkMainInputType->AddRef();
  933. hr = S_OK;
  934. }
  935. if(SUCCEEDED(hr)) {
  936. if(pVideoProcessor) {
  937. CHECK_HR(hr = pVideoProcessor->SetOutputType(0, pSinkMainInputType, 0));
  938. }
  939. else {
  940. //!\ MUST NOT SET OUTPUT TYPE
  941. if(pConvColor) {
  942. //*CHECK_HR*/(hr = pConvColor->SetOutputType(0, pSinkMainInputType, 0));
  943. }
  944. if(pConvFrameRate) {
  945. //*CHECK_HR*/(hr = pConvFrameRate->SetOutputType(0, pSinkMainInputType, 0));
  946. }
  947. if(pConvSize) {
  948. //*CHECK_HR*/(hr = pConvSize->SetOutputType(0, pSinkMainInputType, 0));
  949. }
  950. }
  951. }
  952. }
  953. //
  954. // Connect
  955. //
  956. if(pNodeTee) {
  957. // Connect(Source -> Tee)
  958. CHECK_HR(hr = pNodeSource->ConnectOutput(0, pNodeTee, 0));
  959. // Connect(Tee -> SinkPreview)
  960. CHECK_HR(hr = pNodeTee->ConnectOutput(1, pNodeSinkPreview, 0));
  961. // Connect(Tee ->(Processors)
  962. if(pVideoProcessor) {
  963. CHECK_HR(hr = pNodeTee->ConnectOutput(0, pNodeVideoProcessor, 0));
  964. pcNodeBeforeSinkMain = pNodeVideoProcessor;
  965. }
  966. else if(pNodeConvFrameRate || pNodeConvSize || pNodeConvColor) {
  967. CHECK_HR(hr = ConnectConverters(
  968. pNodeTee,
  969. 0,
  970. pNodeConvFrameRate,
  971. pNodeConvColor,
  972. pNodeConvSize
  973. ));
  974. pcNodeBeforeSinkMain = pNodeConvSize ? pNodeConvSize : (pNodeConvColor ? pNodeConvColor : pNodeConvFrameRate);
  975. }
  976. else {
  977. pcNodeBeforeSinkMain = pNodeTee;
  978. }
  979. }
  980. else {
  981. // Connect(Source -> (Processors))
  982. if(pVideoProcessor) {
  983. CHECK_HR(hr = pNodeSource->ConnectOutput(0, pNodeVideoProcessor, 0));
  984. pcNodeBeforeSinkMain = pNodeVideoProcessor;
  985. }
  986. else if(pNodeConvFrameRate || pNodeConvFrameRate || pNodeConvColor) {
  987. CHECK_HR(hr = ConnectConverters(
  988. pNodeSource,
  989. 0,
  990. pNodeConvFrameRate,
  991. pNodeConvSize,
  992. pNodeConvColor
  993. ));
  994. pcNodeBeforeSinkMain = pNodeConvSize ? pNodeConvSize : (pNodeConvColor ? pNodeConvColor : pNodeConvFrameRate);
  995. }
  996. else {
  997. pcNodeBeforeSinkMain = pNodeSource;
  998. }
  999. }
  1000. if(pNodeTransform) {
  1001. // Connect(X->Transform)
  1002. CHECK_HR(hr = ((IMFTopologyNode *)pcNodeBeforeSinkMain)->ConnectOutput(0, pNodeTransform, 0));
  1003. pcNodeBeforeSinkMain = pNodeTransform;
  1004. }
  1005. // Connect(X -> SinkMain)
  1006. CHECK_HR(hr = ((IMFTopologyNode *)pcNodeBeforeSinkMain)->ConnectOutput(0, pNodeSinkMain, 0));
  1007. bSourceFound = TRUE;
  1008. break;
  1009. }
  1010. else {
  1011. CHECK_HR(hr = pPD->DeselectStream(i));
  1012. }
  1013. SafeRelease(&pSD);
  1014. SafeRelease(&pHandler);
  1015. }
  1016. *ppTopo = pTopology;
  1017. (*ppTopo)->AddRef();
  1018. bail:
  1019. SafeRelease(&pTopology);
  1020. SafeRelease(&pNodeSource);
  1021. SafeRelease(&pNodeSinkMain);
  1022. SafeRelease(&pNodeSinkPreview);
  1023. SafeRelease(&pNodeTransform);
  1024. SafeRelease(&pNodeTee);
  1025. SafeRelease(&pPD);
  1026. SafeRelease(&pSD);
  1027. SafeRelease(&pHandler);
  1028. SafeRelease(&pMediaType);
  1029. SafeRelease(&pTransformInputType);
  1030. SafeRelease(&pSinkMainInputType);
  1031. SafeRelease(&pVideoProcessor);
  1032. SafeRelease(&pNodeVideoProcessor);
  1033. SafeRelease(&pConvFrameRate);
  1034. SafeRelease(&pConvSize);
  1035. SafeRelease(&pConvColor);
  1036. SafeRelease(&pNodeConvFrameRate);
  1037. SafeRelease(&pNodeConvSize);
  1038. SafeRelease(&pNodeConvColor);
  1039. if(!bSourceFound) {
  1040. TSK_DEBUG_ERROR("No source node found");
  1041. return E_NOT_SET;
  1042. }
  1043. return hr;
  1044. }
  1045. // Creates a fully loaded topology from the input partial topology.
  1046. HRESULT MFUtils::ResolveTopology(
  1047. IMFTopology *pInputTopo, // A pointer to the IMFTopology interface of the partial topology to be resolved.
  1048. IMFTopology **ppOutputTopo, // Receives a pointer to the IMFTopology interface of the completed topology. The caller must release the interface.
  1049. IMFTopology *pCurrentTopo /*= NULL*/ // A pointer to the IMFTopology interface of the previous full topology. The topology loader can re-use objects from this topology in the new topology. This parameter can be NULL.
  1050. )
  1051. {
  1052. assert(ppOutputTopo && pInputTopo);
  1053. HRESULT hr = S_OK;
  1054. IMFTopoLoader* pTopoLoader = NULL;
  1055. *ppOutputTopo = NULL;
  1056. CHECK_HR(hr = MFCreateTopoLoader(&pTopoLoader));
  1057. CHECK_HR(hr = pTopoLoader->Load(pInputTopo, ppOutputTopo, pCurrentTopo));
  1058. bail:
  1059. SafeRelease(&pTopoLoader);
  1060. return hr;
  1061. }
  1062. HRESULT MFUtils::FindNodeObject(
  1063. IMFTopology *pInputTopo, // The Topology containing the node to find
  1064. TOPOID qwTopoNodeID, //The identifier for the node
  1065. void** ppObject // Receives the Object
  1066. )
  1067. {
  1068. assert(pInputTopo && ppObject);
  1069. *ppObject = NULL;
  1070. IMFTopologyNode *pNode = NULL;
  1071. HRESULT hr = S_OK;
  1072. CHECK_HR(hr = pInputTopo->GetNodeByID(qwTopoNodeID, &pNode));
  1073. CHECK_HR(hr = pNode->GetObject((IUnknown**)ppObject));
  1074. bail:
  1075. SafeRelease(&pNode);
  1076. return hr;
  1077. }
  1078. // Create an activation object for a renderer, based on the stream media type.
  1079. HRESULT MFUtils::CreateMediaSinkActivate(
  1080. IMFStreamDescriptor *pSourceSD, // Pointer to the stream descriptor.
  1081. HWND hVideoWindow, // Handle to the video clipping window.
  1082. IMFActivate **ppActivate
  1083. )
  1084. {
  1085. HRESULT hr = S_OK;
  1086. IMFMediaTypeHandler *pHandler = NULL;
  1087. IMFActivate *pActivate = NULL;
  1088. // Get the media type handler for the stream.
  1089. CHECK_HR(hr = pSourceSD->GetMediaTypeHandler(&pHandler));
  1090. // Get the major media type.
  1091. GUID guidMajorType;
  1092. CHECK_HR(hr = pHandler->GetMajorType(&guidMajorType));
  1093. // Create an IMFActivate object for the renderer, based on the media type.
  1094. if (MFMediaType_Audio == guidMajorType) {
  1095. // Create the audio renderer.
  1096. CHECK_HR(hr = MFCreateAudioRendererActivate(&pActivate));
  1097. }
  1098. else if (MFMediaType_Video == guidMajorType) {
  1099. // Create the video renderer.
  1100. CHECK_HR(hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate));
  1101. }
  1102. else {
  1103. // Unknown stream type.
  1104. hr = E_FAIL;
  1105. // Optionally, you could deselect this stream instead of failing.
  1106. }
  1107. if (FAILED(hr)) {
  1108. goto bail;
  1109. }
  1110. // Return IMFActivate pointer to caller.
  1111. *ppActivate = pActivate;
  1112. (*ppActivate)->AddRef();
  1113. bail:
  1114. SafeRelease(&pHandler);
  1115. SafeRelease(&pActivate);
  1116. return hr;
  1117. }
  1118. // Set source output media type
  1119. HRESULT MFUtils::SetMediaType(
  1120. IMFMediaSource *pSource, // Media source.
  1121. IMFMediaType* pMediaType // Media Type.
  1122. )
  1123. {
  1124. assert(pSource && pMediaType);
  1125. IMFPresentationDescriptor *pPD = NULL;
  1126. IMFStreamDescriptor *pSD = NULL;
  1127. IMFMediaTypeHandler *pHandler = NULL;
  1128. HRESULT hr = S_OK;
  1129. DWORD cStreams = 0;
  1130. GUID inputMajorType;
  1131. CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
  1132. CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
  1133. CHECK_HR(hr = pMediaType->GetMajorType(&inputMajorType));
  1134. for (DWORD i = 0; i < cStreams; i++) {
  1135. BOOL fSelected = FALSE;
  1136. GUID majorType;
  1137. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD));
  1138. CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
  1139. CHECK_HR(hr = pHandler->GetMajorType(&majorType));
  1140. if (majorType == inputMajorType && fSelected) {
  1141. CHECK_HR(hr = pHandler->SetCurrentMediaType(pMediaType));
  1142. }
  1143. else {
  1144. CHECK_HR(hr = pPD->DeselectStream(i));
  1145. }
  1146. SafeRelease(&pSD);
  1147. SafeRelease(&pHandler);
  1148. }
  1149. bail:
  1150. SafeRelease(&pPD);
  1151. SafeRelease(&pSD);
  1152. SafeRelease(&pHandler);
  1153. return hr;
  1154. }
  1155. HRESULT MFUtils::SetVideoWindow(
  1156. IMFTopology *pTopology, // Topology.
  1157. IMFMediaSource *pSource, // Media source.
  1158. HWND hVideoWnd // Window for video playback.
  1159. )
  1160. {
  1161. HRESULT hr = S_OK;
  1162. IMFStreamDescriptor *pSD = NULL;
  1163. IMFPresentationDescriptor *pPD = NULL;
  1164. IMFActivate *pSinkActivate = NULL;
  1165. IMFTopologyNode *pSourceNode = NULL;
  1166. IMFTopologyNode *pOutputNode = NULL;
  1167. DWORD cStreams = 0, iStream;
  1168. CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
  1169. CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
  1170. for(iStream = 0; iStream < cStreams; ++iStream) {
  1171. BOOL fSelected = FALSE;
  1172. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD));
  1173. if (fSelected) {
  1174. // Create the media sink activation object.
  1175. CHECK_HR(hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate));
  1176. // Add a source node for this stream.
  1177. CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode));
  1178. // Create the output node for the renderer.
  1179. CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode));
  1180. // Connect the source node to the output node.
  1181. CHECK_HR(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
  1182. }
  1183. // else: If not selected, don't add the branch.
  1184. }
  1185. bail:
  1186. SafeRelease(&pPD);
  1187. SafeRelease(&pSD);
  1188. SafeRelease(&pSinkActivate);
  1189. SafeRelease(&pSourceNode);
  1190. SafeRelease(&pOutputNode);
  1191. return hr;
  1192. }
  1193. // Run the session
  1194. HRESULT MFUtils::RunSession(
  1195. IMFMediaSession *pSession, // Session to run
  1196. IMFTopology *pTopology // The toppology
  1197. )
  1198. {
  1199. assert(pSession && pTopology);
  1200. IMFMediaEvent *pEvent = NULL;
  1201. PROPVARIANT var;
  1202. PropVariantInit(&var);
  1203. MediaEventType met;
  1204. HRESULT hrStatus = S_OK;
  1205. HRESULT hr = S_OK;
  1206. CHECK_HR(hr = pSession->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, pTopology)); // MFSESSION_SETTOPOLOGY_IMMEDIATE required to update (reload) topology when media type change
  1207. CHECK_HR(hr = pSession->Start(&GUID_NULL, &var));
  1208. // Check first event
  1209. hr = pSession->GetEvent(MF_EVENT_FLAG_NO_WAIT, &pEvent);
  1210. if(hr == MF_E_NO_EVENTS_AVAILABLE || hr == MF_E_MULTIPLE_SUBSCRIBERS) { // MF_E_MULTIPLE_SUBSCRIBERS means already listening
  1211. hr = S_OK;
  1212. goto bail;
  1213. }
  1214. if(pEvent) {
  1215. CHECK_HR(hr = pEvent->GetStatus(&hrStatus));
  1216. }
  1217. else {
  1218. hrStatus = hr;
  1219. }
  1220. if (FAILED(hrStatus)) {
  1221. CHECK_HR(hr = pEvent->GetType(&met));
  1222. TSK_DEBUG_ERROR("Session error: 0x%x (event id: %d)\n", hrStatus, met);
  1223. hr = hrStatus;
  1224. goto bail;
  1225. }
  1226. bail:
  1227. SafeRelease(&pEvent);
  1228. return hr;
  1229. }
  1230. // Stop session
  1231. HRESULT MFUtils::ShutdownSession(
  1232. IMFMediaSession *pSession, // The Session
  1233. IMFMediaSource *pSource // Source to shutdown (optional)
  1234. )
  1235. {
  1236. // MUST be source then session
  1237. if(pSource) {
  1238. pSource->Stop();
  1239. pSource->Shutdown();
  1240. }
  1241. if(pSession) {
  1242. pSession->Shutdown();
  1243. }
  1244. return S_OK;
  1245. }
  1246. // Pause session
  1247. HRESULT MFUtils::PauseSession(
  1248. IMFMediaSession *pSession, // The session
  1249. IMFMediaSource *pSource // Source to pause (optional)
  1250. )
  1251. {
  1252. if(!pSession) {
  1253. return E_INVALIDARG;
  1254. }
  1255. if(pSource) {
  1256. pSource->Pause();
  1257. }
  1258. return pSession->Pause();
  1259. }
  1260. // Returns -1 if none is supported
  1261. INT MFUtils::GetSupportedSubTypeIndex(
  1262. IMFMediaSource *pSource, // The source
  1263. const GUID& mediaType, // The MediaType
  1264. const VideoSubTypeGuidPair* subTypes, UINT subTypesCount // List of preferred subtypes (in ascending order)
  1265. )
  1266. {
  1267. assert(pSource);
  1268. IMFPresentationDescriptor *pPD = NULL;
  1269. IMFStreamDescriptor *pSD = NULL;
  1270. IMFMediaTypeHandler *pHandler = NULL;
  1271. IMFMediaType *pMediaType = NULL;
  1272. INT nIndex = -1;
  1273. HRESULT hr = S_OK;
  1274. DWORD cStreams = 0, cMediaTypesCount;
  1275. GUID majorType, subType;
  1276. BOOL fSelected;
  1277. CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
  1278. CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
  1279. for (UINT subTypesIndex = 0; subTypesIndex < subTypesCount && nIndex == -1; ++subTypesIndex) {
  1280. for (DWORD cStreamIndex = 0; cStreamIndex < cStreams && nIndex == -1; ++cStreamIndex) {
  1281. fSelected = FALSE;
  1282. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(cStreamIndex, &fSelected, &pSD));
  1283. if(fSelected) {
  1284. CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
  1285. CHECK_HR(hr = pHandler->GetMajorType(&majorType));
  1286. if(majorType == mediaType) {
  1287. CHECK_HR(hr = pHandler->GetMediaTypeCount(&cMediaTypesCount));
  1288. for(DWORD cMediaTypesIndex = 0; cMediaTypesIndex < cMediaTypesCount && nIndex == -1; ++cMediaTypesIndex) {
  1289. CHECK_HR(hr = pHandler->GetMediaTypeByIndex(cMediaTypesIndex, &pMediaType));
  1290. CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &subType));
  1291. if (subTypes[subTypesIndex].fourcc == subType) {
  1292. nIndex = subTypesIndex;
  1293. break;
  1294. }
  1295. SafeRelease(&pMediaType);
  1296. }
  1297. }
  1298. }
  1299. SafeRelease(&pSD);
  1300. SafeRelease(&pHandler);
  1301. }
  1302. }
  1303. bail:
  1304. SafeRelease(&pMediaType);
  1305. SafeRelease(&pPD);
  1306. SafeRelease(&pSD);
  1307. SafeRelease(&pHandler);
  1308. return nIndex;
  1309. }
  1310. HRESULT MFUtils::IsSupported(
  1311. IMFPresentationDescriptor *pPD,
  1312. DWORD cStreamIndex,
  1313. UINT32 nWidth,
  1314. UINT32 nHeight,
  1315. UINT32 nFps,
  1316. const GUID& guidFormat,
  1317. BOOL* pbSupportedSize,
  1318. BOOL* pbSupportedFps,
  1319. BOOL* pbSupportedFormat
  1320. )
  1321. {
  1322. HRESULT hr = S_OK;
  1323. BOOL fSelected = FALSE;
  1324. IMFStreamDescriptor *pSD = NULL;
  1325. IMFMediaTypeHandler *pHandler = NULL;
  1326. IMFMediaType *pMediaType = NULL;
  1327. UINT32 _nWidth = 0, _nHeight = 0, numeratorFps = 0, denominatorFps = 0;
  1328. GUID subType;
  1329. DWORD cMediaTypesCount;
  1330. if(!pPD || !pbSupportedSize || !pbSupportedFps || !pbSupportedFormat) {
  1331. CHECK_HR(hr = E_POINTER);
  1332. }
  1333. *pbSupportedSize = FALSE;
  1334. *pbSupportedFps = FALSE;
  1335. *pbSupportedFormat = FALSE;
  1336. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(cStreamIndex, &fSelected, &pSD));
  1337. if(fSelected) {
  1338. CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
  1339. CHECK_HR(hr = pHandler->GetMediaTypeCount(&cMediaTypesCount));
  1340. for(DWORD cMediaTypesIndex = 0; cMediaTypesIndex < cMediaTypesCount; ++cMediaTypesIndex) {
  1341. CHECK_HR(hr = pHandler->GetMediaTypeByIndex(cMediaTypesIndex, &pMediaType));
  1342. CHECK_HR(hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &_nWidth, &_nHeight));
  1343. CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &subType));
  1344. if(FAILED(hr = MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, &numeratorFps, &denominatorFps))) {
  1345. numeratorFps = 30;
  1346. denominatorFps = 1;
  1347. }
  1348. // all must match for the same stream
  1349. if(_nWidth == nWidth && _nHeight == nHeight && subType == guidFormat && (numeratorFps/denominatorFps) == nFps) {
  1350. *pbSupportedSize = TRUE;
  1351. *pbSupportedFormat = TRUE;
  1352. *pbSupportedFps = TRUE;
  1353. break;
  1354. }
  1355. SafeRelease(&pMediaType);
  1356. }
  1357. SafeRelease(&pHandler);
  1358. }
  1359. bail:
  1360. SafeRelease(&pSD);
  1361. SafeRelease(&pHandler);
  1362. SafeRelease(&pMediaType);
  1363. return hr;
  1364. }
  1365. HRESULT MFUtils::IsSupported(
  1366. IMFPresentationDescriptor *pPD,
  1367. DWORD cStreamIndex,
  1368. IMFMediaType* pMediaType,
  1369. BOOL* pbSupportedSize,
  1370. BOOL* pbSupportedFps,
  1371. BOOL* pbSupportedFormat
  1372. )
  1373. {
  1374. HRESULT hr = S_OK;
  1375. UINT32 nWidth = 0, nHeight = 0, nFps = 0, numeratorFps = 30, denominatorFps = 1;
  1376. GUID subType;
  1377. if(!pPD || !pMediaType || !pbSupportedSize || !pbSupportedFps || !pbSupportedFormat) {
  1378. CHECK_HR(hr = E_POINTER);
  1379. }
  1380. CHECK_HR(hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &nWidth, &nHeight));
  1381. CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &subType));
  1382. if(FAILED(hr = MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, &numeratorFps, &denominatorFps))) {
  1383. numeratorFps = 30;
  1384. denominatorFps = 1;
  1385. }
  1386. CHECK_HR(hr = IsSupported(
  1387. pPD,
  1388. cStreamIndex,
  1389. nWidth,
  1390. nHeight,
  1391. (numeratorFps / denominatorFps),
  1392. subType,
  1393. pbSupportedSize,
  1394. pbSupportedFps,
  1395. pbSupportedFormat
  1396. ));
  1397. bail:
  1398. return hr;
  1399. }
  1400. HRESULT MFUtils::IsSupportedByInput(
  1401. IMFPresentationDescriptor *pPD,
  1402. DWORD cStreamIndex,
  1403. IMFTopologyNode *pNode,
  1404. BOOL* pbSupportedSize,
  1405. BOOL* pbSupportedFps,
  1406. BOOL* pbSupportedFormat
  1407. )
  1408. {
  1409. HRESULT hr = S_OK;
  1410. IMFMediaType *pMediaType = NULL;
  1411. IUnknown* pObject = NULL;
  1412. IMFActivate *pActivate = NULL;
  1413. IMFMediaSink *pMediaSink = NULL;
  1414. IMFTransform *pTransform = NULL;
  1415. IMFStreamSink *pStreamSink = NULL;
  1416. IMFMediaTypeHandler *pHandler = NULL;
  1417. if(!pPD || !pNode || !pbSupportedSize || !pbSupportedFps || !pbSupportedFormat) {
  1418. CHECK_HR(hr = E_POINTER);
  1419. }
  1420. CHECK_HR(hr = pNode->GetObject(&pObject));
  1421. hr = pObject->QueryInterface(IID_PPV_ARGS(&pActivate));
  1422. if(SUCCEEDED(hr)) {
  1423. SafeRelease(&pObject);
  1424. hr = pActivate->ActivateObject(IID_IMFMediaSink, (void**)&pObject);
  1425. if(FAILED(hr)) {
  1426. hr = pActivate->ActivateObject(IID_IMFTransform, (void**)&pObject);
  1427. }
  1428. }
  1429. if(!pObject) {
  1430. CHECK_HR(hr = E_NOINTERFACE);
  1431. }
  1432. hr = pObject->QueryInterface(IID_PPV_ARGS(&pMediaSink));
  1433. if(FAILED(hr)) {
  1434. hr = pObject->QueryInterface(IID_PPV_ARGS(&pTransform));
  1435. }
  1436. if(pMediaSink) {
  1437. CHECK_HR(hr = pMediaSink->GetStreamSinkByIndex(0, &pStreamSink));
  1438. CHECK_HR(hr = pStreamSink->GetMediaTypeHandler(&pHandler));
  1439. CHECK_HR(hr = pHandler->GetCurrentMediaType(&pMediaType));
  1440. }
  1441. else if(pTransform) {
  1442. CHECK_HR(hr = pTransform->GetInputCurrentType(0, &pMediaType));
  1443. }
  1444. else {
  1445. CHECK_HR(hr = pNode->GetInputPrefType(0, &pMediaType));
  1446. }
  1447. CHECK_HR(hr = IsSupported(
  1448. pPD,
  1449. cStreamIndex,
  1450. pMediaType,
  1451. pbSupportedSize,
  1452. pbSupportedFps,
  1453. pbSupportedFormat
  1454. ));
  1455. bail:
  1456. SafeRelease(&pObject);
  1457. SafeRelease(&pActivate);
  1458. SafeRelease(&pMediaType);
  1459. SafeRelease(&pStreamSink);
  1460. SafeRelease(&pHandler);
  1461. return hr;
  1462. }
  1463. HRESULT MFUtils::ConnectConverters(
  1464. IMFTopologyNode *pNode,
  1465. DWORD dwOutputIndex,
  1466. IMFTopologyNode *pNodeConvFrameRate,
  1467. IMFTopologyNode *pNodeConvColor,
  1468. IMFTopologyNode *pNodeConvSize
  1469. )
  1470. {
  1471. HRESULT hr = S_OK;
  1472. if(!pNode) {
  1473. CHECK_HR(hr = E_POINTER);
  1474. }
  1475. if(pNodeConvFrameRate) {
  1476. CHECK_HR(hr = pNode->ConnectOutput(dwOutputIndex, pNodeConvFrameRate, 0));
  1477. if(pNodeConvSize) {
  1478. CHECK_HR(hr = pNodeConvFrameRate->ConnectOutput(0, pNodeConvSize, 0));
  1479. if(pNodeConvColor) {
  1480. CHECK_HR(hr = pNodeConvSize->ConnectOutput(0, pNodeConvColor, 0));
  1481. }
  1482. }
  1483. else {
  1484. if(pNodeConvColor) {
  1485. CHECK_HR(hr = pNodeConvFrameRate->ConnectOutput(0, pNodeConvColor, 0));
  1486. }
  1487. }
  1488. }
  1489. else {
  1490. if(pNodeConvSize) {
  1491. CHECK_HR(hr = pNode->ConnectOutput(dwOutputIndex, pNodeConvSize, 0));
  1492. if(pNodeConvColor) {
  1493. CHECK_HR(hr = pNodeConvSize->ConnectOutput(0, pNodeConvColor, 0));
  1494. }
  1495. }
  1496. else {
  1497. if(pNodeConvColor) {
  1498. CHECK_HR(hr = pNode->ConnectOutput(dwOutputIndex, pNodeConvColor, 0));
  1499. }
  1500. }
  1501. }
  1502. bail:
  1503. return hr;
  1504. }
  1505. // This function should be called only if VideoProcessor is not supported
  1506. HRESULT MFUtils::GetBestFormat(
  1507. IMFMediaSource *pSource,
  1508. const GUID *pSubType,
  1509. UINT32 nWidth,
  1510. UINT32 nHeight,
  1511. UINT32 nFps,
  1512. UINT32 *pnWidth,
  1513. UINT32 *pnHeight,
  1514. UINT32 *pnFps,
  1515. const VideoSubTypeGuidPair **ppSubTypeGuidPair
  1516. )
  1517. {
  1518. #define _FindPairByGuid(_guid, _index) { \
  1519. int _i; _index = -1; \
  1520. for (_i = 0; _i < PreferredVideoSubTypeGuidPairsCount; ++_i) { \
  1521. if (PreferredVideoSubTypeGuidPairs[_i].fourcc == _guid) { \
  1522. _index = _i; break; \
  1523. } \
  1524. } \
  1525. }
  1526. #if 0
  1527. *pnWidth = 640;
  1528. *pnHeight = 480;
  1529. *pnFps = 30;
  1530. return S_OK;
  1531. #else
  1532. HRESULT hr = S_OK;
  1533. IMFPresentationDescriptor *pPD = NULL;
  1534. IMFStreamDescriptor *pSD = NULL;
  1535. IMFMediaTypeHandler *pHandler = NULL;
  1536. IMFMediaType *pMediaType = NULL;
  1537. DWORD cStreams = 0, cMediaTypesCount;
  1538. GUID majorType, subType, _BestSubType;
  1539. BOOL bFound = FALSE, fSelected;
  1540. UINT32 _nWidth, _nHeight, numeratorFps, denominatorFps, _nFps, _nScore, _nBestScore;
  1541. int PreferredVideoSubTypeGuidPairIndex;
  1542. static const UINT32 kSubTypeMismatchPad = _UI32_MAX >> 4;
  1543. static const UINT32 kFpsMismatchPad = _UI32_MAX >> 2;
  1544. if (!ppSubTypeGuidPair || !pSubType) {
  1545. CHECK_HR(hr = E_INVALIDARG);
  1546. }
  1547. _FindPairByGuid(*pSubType, PreferredVideoSubTypeGuidPairIndex);
  1548. if (PreferredVideoSubTypeGuidPairIndex == -1) {
  1549. CHECK_HR(hr = E_INVALIDARG);
  1550. }
  1551. *ppSubTypeGuidPair = &PreferredVideoSubTypeGuidPairs[PreferredVideoSubTypeGuidPairIndex];
  1552. _nBestScore = _UI32_MAX;
  1553. CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
  1554. CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
  1555. for (DWORD i = 0; i < cStreams; i++) {
  1556. fSelected = FALSE;
  1557. CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD));
  1558. if (fSelected) {
  1559. CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
  1560. CHECK_HR(hr = pHandler->GetMajorType(&majorType));
  1561. if(majorType == MFMediaType_Video) {
  1562. CHECK_HR(hr = pHandler->GetMediaTypeCount(&cMediaTypesCount));
  1563. for(DWORD cMediaTypesIndex = 0; cMediaTypesIndex < cMediaTypesCount; ++cMediaTypesIndex) {
  1564. CHECK_HR(hr = pHandler->GetMediaTypeByIndex(cMediaTypesIndex, &pMediaType));
  1565. CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &subType));
  1566. // if(subType == *pSubType)
  1567. {
  1568. CHECK_HR(hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &_nWidth, &_nHeight));
  1569. CHECK_HR(hr = MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, &numeratorFps, &denominatorFps));
  1570. _nFps = (numeratorFps / denominatorFps);
  1571. if (subType == *pSubType) {
  1572. _nScore = 0;
  1573. }
  1574. else {
  1575. _FindPairByGuid(subType, PreferredVideoSubTypeGuidPairIndex);
  1576. if (PreferredVideoSubTypeGuidPairIndex == -1) {
  1577. _nScore = kSubTypeMismatchPad; // Not a must but important: If(!VideoProcess) then CLSID_CColorConvertDMO
  1578. }
  1579. else {
  1580. _nScore = kSubTypeMismatchPad >> (PreferredVideoSubTypeGuidPairsCount - PreferredVideoSubTypeGuidPairIndex);
  1581. }
  1582. }
  1583. _nScore += abs((int)(_nWidth - nWidth)); // Not a must: If(!VideoProcess) then CLSID_CResizerDMO
  1584. _nScore += abs((int)(_nHeight - nHeight)); // Not a must: If(!VideoProcess) then CLSID_CResizerDMO
  1585. _nScore += (_nFps == nFps) ? 0 : kFpsMismatchPad; // Fps is a must because without video processor no alternative exist (CLSID_CFrameRateConvertDmo doesn't support I420)
  1586. if (_nScore <= _nBestScore || !bFound) {
  1587. *pnWidth = _nWidth;
  1588. *pnHeight = _nHeight;
  1589. *pnFps = _nFps;
  1590. bFound = TRUE;
  1591. _BestSubType = subType;
  1592. _nBestScore = _nScore;
  1593. }
  1594. }
  1595. SafeRelease(&pMediaType);
  1596. }
  1597. }
  1598. }
  1599. SafeRelease(&pHandler);
  1600. SafeRelease(&pSD);
  1601. }
  1602. bail:
  1603. SafeRelease(&pPD);
  1604. SafeRelease(&pSD);
  1605. SafeRelease(&pHandler);
  1606. SafeRelease(&pMediaType);
  1607. _FindPairByGuid(_BestSubType, PreferredVideoSubTypeGuidPairIndex);
  1608. if (PreferredVideoSubTypeGuidPairIndex != -1) {
  1609. *ppSubTypeGuidPair = &PreferredVideoSubTypeGuidPairs[PreferredVideoSubTypeGuidPairIndex];
  1610. }
  1611. else { /*if (_nBestScore > kSubTypeMismatchPad)*/
  1612. *pnWidth = 640;
  1613. *pnHeight = 480;
  1614. *pnFps = 30;
  1615. TSK_DEBUG_WARN("Failed to math subtype...using VGA@30fps");
  1616. }
  1617. return SUCCEEDED(hr) ? (bFound ? S_OK : E_NOT_SET): hr;
  1618. #endif
  1619. }
  1620. HWND MFUtils::GetConsoleHwnd(void)
  1621. {
  1622. #define MY_BUFSIZE 1024 // Buffer size for console window titles.
  1623. HWND hwndFound; // This is what is returned to the caller.
  1624. TCHAR pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated
  1625. // WindowTitle.
  1626. TCHAR pszOldWindowTitle[MY_BUFSIZE]; // Contains original
  1627. // WindowTitle.
  1628. // Fetch current window title.
  1629. GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
  1630. // Format a "unique" NewWindowTitle.
  1631. wsprintf(pszNewWindowTitle,TEXT("%d/%d"),
  1632. GetTickCount(),
  1633. GetCurrentProcessId());
  1634. // Change current window title.
  1635. SetConsoleTitle(pszNewWindowTitle);
  1636. // Ensure window title has been updated.
  1637. Sleep(40);
  1638. // Look for NewWindowTitle.
  1639. hwndFound=FindWindow(NULL, pszNewWindowTitle);
  1640. // Restore original window title.
  1641. SetConsoleTitle(pszOldWindowTitle);
  1642. return(hwndFound);
  1643. }