plugin_win_mf_converter_video.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /* Copyright (C) 2013-2015 Mamadou DIOP
  2. * Copyright (C) 2013-2015 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. /*
  20. Video Processor MFT (http://msdn.microsoft.com/en-us/library/windows/desktop/hh162913(v=vs.85).aspx)
  21. * The video processor supports GPU-accelerated video processing.
  22. * The video processor MFT is a Microsoft Media Foundation transform (MFT) that performs :
  23. - colorspace conversion
  24. - video resizing
  25. - deinterlacing
  26. - frame rate conversion
  27. - rotation
  28. - cropping
  29. - spatial left and right view unpacking
  30. - and mirroring
  31. */
  32. #include "plugin_win_mf_config.h"
  33. #include "internals/mf_utils.h"
  34. #include "tinymedia/tmedia_converter_video.h"
  35. #include "tsk_memory.h"
  36. #include "tsk_debug.h"
  37. #include <assert.h>
  38. #include <initguid.h>
  39. #include <dmo.h>
  40. #include <wmcodecdsp.h>
  41. #ifdef _MSC_VER
  42. #pragma comment(lib, "strmiids.lib")
  43. #pragma comment(lib, "wmcodecdspuuid.lib")
  44. #endif
  45. EXTERN_C const GUID CLSID_VideoProcessorMFT; // defined in mf_utils.cxx
  46. #if !defined(_WIN32_WINNT_WIN8)
  47. #define _WIN32_WINNT_WIN8 0x0602
  48. #endif /* _WIN32_WINNT_WIN8 */
  49. #if (WINVER < _WIN32_WINNT_WIN8)
  50. DEFINE_GUID(MF_SA_D3D11_AWARE,
  51. 0x206b4fc8, 0xfcf9, 0x4c51, 0xaf, 0xe3, 0x97, 0x64, 0x36, 0x9e, 0x33, 0xa0);
  52. #endif /* MF_SA_D3D11_AWARE */
  53. #if !defined(HAVE_IMFVideoProcessorControl)
  54. # if defined(__IMFVideoProcessorControl_INTERFACE_DEFINED__)
  55. # define HAVE_IMFVideoProcessorControl 1
  56. # else
  57. # define HAVE_IMFVideoProcessorControl 0
  58. # endif
  59. #endif /* HAVE_IMFVideoProcessorControl */
  60. #if !defined(E_BOUNDS)
  61. # define E_BOUNDS _HRESULT_TYPEDEF_(0x8000000BL)
  62. #endif /* E_BOUNDS */
  63. #if !defined(PLUGIN_MF_VC_FPS)
  64. #define PLUGIN_MF_VC_FPS 120 // Samples requires timestamp
  65. #endif /* PLUGIN_MF_VC_FPS */
  66. typedef struct plugin_win_mf_converter_video_ms_s {
  67. TMEDIA_DECLARE_CONVERTER_VIDEO;
  68. GUID fmtSrc;
  69. tsk_size_t widthSrc;
  70. tsk_size_t heightSrc;
  71. GUID fmtDst;
  72. tsk_size_t widthDst;
  73. tsk_size_t heightDst;
  74. UINT32 rotation;
  75. UINT32 xOutputSize;
  76. UINT32 xInputSize;
  77. BOOL flip;
  78. IMFSample* pSampleOut;
  79. IMFSample* pSampleIn;
  80. LONGLONG rtStart;
  81. UINT64 rtDuration;
  82. IMFTransform* pMFT; // "CLSID_VideoProcessorMFT" or "CLSID_CColorConvertDMO"
  83. #if HAVE_IMFVideoProcessorControl
  84. IMFVideoProcessorControl* pVPC;
  85. #endif
  86. BOOL isVideoProcessor;
  87. }
  88. plugin_win_mf_converter_video_ms_t;
  89. static inline const GUID& _plugin_win_mf_converter_video_ms_get_pixfmt(tmedia_chroma_t chroma);
  90. static inline tsk_size_t _plugin_win_mf_converter_video_ms_get_size(tmedia_chroma_t chroma, tsk_size_t w, tsk_size_t h);
  91. static inline HRESULT _plugin_win_mf_converter_video_ms_copy_rgb32_down_top(
  92. BYTE* pDst,
  93. const BYTE* pSrc,
  94. INT dwWidthInPixels,
  95. INT dwHeightInPixels
  96. );
  97. static HRESULT _plugin_win_mf_converter_video_ms_process_input(plugin_win_mf_converter_video_ms_t* pSelf, IMFSample* pSample);
  98. static HRESULT _plugin_win_mf_converter_video_ms_process_output(plugin_win_mf_converter_video_ms_t* pSelf, IMFSample **ppSample);
  99. static HRESULT _plugin_win_mf_converter_video_ms_process(plugin_win_mf_converter_video_ms_t* pSelf, const void* pcInputPtr, UINT32 nInputSize, IMFSample **ppSampleOut);
  100. static int plugin_win_mf_converter_video_ms_init(tmedia_converter_video_t* self, tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma)
  101. {
  102. plugin_win_mf_converter_video_ms_t* pSelf = (plugin_win_mf_converter_video_ms_t*)self;
  103. TSK_DEBUG_INFO("Initializing new MF Video Converter src=(%dx%d@%d) dst=(%dx%d@%d)", srcWidth, srcHeight, srcChroma, dstWidth, dstHeight, dstChroma);
  104. if((pSelf->fmtSrc = _plugin_win_mf_converter_video_ms_get_pixfmt(srcChroma)) == GUID_NULL) {
  105. TSK_DEBUG_ERROR("Invalid source chroma");
  106. return -2;
  107. }
  108. if((pSelf->fmtDst = _plugin_win_mf_converter_video_ms_get_pixfmt(dstChroma)) == GUID_NULL) {
  109. TSK_DEBUG_ERROR("Invalid destination chroma");
  110. return -3;
  111. }
  112. pSelf->rtStart = 0;
  113. pSelf->widthSrc = srcWidth;
  114. pSelf->heightSrc = srcHeight;
  115. pSelf->widthDst = dstWidth;
  116. pSelf->heightDst = dstHeight;
  117. pSelf->rotation = 0;
  118. pSelf->xOutputSize = (UINT32)_plugin_win_mf_converter_video_ms_get_size(dstChroma, dstWidth, dstHeight);
  119. pSelf->xInputSize = (UINT32)_plugin_win_mf_converter_video_ms_get_size(srcChroma, srcWidth, srcHeight);
  120. SafeRelease(&pSelf->pSampleOut);
  121. SafeRelease(&pSelf->pSampleIn);
  122. SafeRelease(&pSelf->pMFT);
  123. #if HAVE_IMFVideoProcessorControl
  124. SafeRelease(&pSelf->pVPC);
  125. #endif
  126. HRESULT hr = S_OK;
  127. IMFMediaType* pTypeSrc = NULL;
  128. IMFMediaType* pTypeDst = NULL;
  129. // Get video processor or Color convertor
  130. hr = CoCreateInstance(CLSID_VideoProcessorMFT, NULL,
  131. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSelf->pMFT));
  132. pSelf->isVideoProcessor = SUCCEEDED(hr);
  133. if(FAILED(hr)) {
  134. TSK_DEBUG_INFO("CoCreateInstance(CLSID_VideoProcessorMFT) failed");
  135. if(pSelf->widthSrc == pSelf->widthDst && pSelf->heightSrc == pSelf->heightDst) {
  136. TSK_DEBUG_INFO("No video scaling is required...perform CoCreateInstance(CLSID_CColorConvertDMO)");
  137. CHECK_HR(hr = CoCreateInstance(CLSID_CColorConvertDMO, NULL,
  138. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSelf->pMFT)));
  139. }
  140. else {
  141. CHECK_HR(hr);
  142. }
  143. }
  144. if(pSelf->isVideoProcessor) {
  145. IMFAttributes* pAttributes = NULL;
  146. UINT32 GPU = 0;
  147. hr = pSelf->pMFT->GetAttributes(&pAttributes);
  148. if (SUCCEEDED(hr)) {
  149. hr = pAttributes->GetUINT32(MF_SA_D3D11_AWARE, &GPU);
  150. }
  151. SafeRelease(&pAttributes);
  152. TSK_DEBUG_INFO("MF_SA_D3D11_AWARE = %d", GPU);
  153. #if HAVE_IMFVideoProcessorControl
  154. CHECK_HR(hr = pSelf->pMFT->QueryInterface(IID_PPV_ARGS(&pSelf->pVPC)));
  155. #endif
  156. }
  157. CHECK_HR(hr = MFUtils::CreateVideoType(&pSelf->fmtSrc, &pTypeSrc, (UINT32)pSelf->widthSrc, (UINT32)pSelf->heightSrc));
  158. CHECK_HR(hr = MFUtils::CreateVideoType(&pSelf->fmtDst, &pTypeDst, (UINT32)pSelf->widthDst, (UINT32)pSelf->heightDst));
  159. CHECK_HR(hr = pSelf->pMFT->SetInputType(0, pTypeSrc, 0));
  160. CHECK_HR(hr = pSelf->pMFT->SetOutputType(0, pTypeDst, 0));
  161. bail:
  162. SafeRelease(&pTypeSrc);
  163. SafeRelease(&pTypeDst);
  164. if(FAILED(hr)) {
  165. SafeRelease(&pSelf->pMFT);
  166. #if HAVE_IMFVideoProcessorControl
  167. SafeRelease(&pSelf->pVPC);
  168. #endif
  169. return -4;
  170. }
  171. return 0;
  172. }
  173. static tsk_size_t plugin_win_mf_converter_video_ms_process(tmedia_converter_video_t* _self, const void* buffer, tsk_size_t buffer_size, void** output, tsk_size_t* output_max_size)
  174. {
  175. plugin_win_mf_converter_video_ms_t* pSelf = (plugin_win_mf_converter_video_ms_t*)_self;
  176. HRESULT hr = S_OK;
  177. IMFSample *pSampleOut = NULL;
  178. IMFMediaBuffer* pBufferOut = NULL;
  179. if(!pSelf || !buffer || !output || !output_max_size) {
  180. CHECK_HR(hr = E_POINTER);
  181. }
  182. if(!pSelf->pMFT) {
  183. TSK_DEBUG_ERROR("Not initialized");
  184. CHECK_HR(hr = E_FAIL);
  185. }
  186. #if HAVE_IMFVideoProcessorControl
  187. if(!pSelf->pVPC && pSelf->isVideoProcessor) {
  188. TSK_DEBUG_ERROR("Not initialized");
  189. CHECK_HR(hr = E_FAIL);
  190. }
  191. #endif
  192. if(*output_max_size < pSelf->xOutputSize) {
  193. if(!(*output = tsk_realloc(*output, pSelf->xOutputSize))) {
  194. *output_max_size = 0;
  195. TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", pSelf->xOutputSize);
  196. CHECK_HR(hr = E_OUTOFMEMORY);
  197. }
  198. *output_max_size = pSelf->xOutputSize;
  199. }
  200. #if HAVE_IMFVideoProcessorControl
  201. if(pSelf->pVPC && !!_self->flip != !!pSelf->flip) {
  202. pSelf->flip = !!_self->flip;
  203. CHECK_HR(hr = pSelf->pVPC->SetMirror(pSelf->flip ? MIRROR_NONE : MIRROR_VERTICAL));
  204. }
  205. if(pSelf->pVPC && _self->rotation != pSelf->rotation) {
  206. _self->rotation = pSelf->rotation;
  207. CHECK_HR(hr = pSelf->pVPC->SetRotation(pSelf->rotation == 0 ? ROTATION_NONE : ROTATION_NORMAL));
  208. }
  209. #endif
  210. CHECK_HR(hr = _plugin_win_mf_converter_video_ms_process(
  211. pSelf, buffer, pSelf->xInputSize, &pSampleOut));
  212. if(pSampleOut) {
  213. CHECK_HR(hr = pSampleOut->GetBufferByIndex(0, &pBufferOut));
  214. BYTE* pBufferPtr = NULL;
  215. DWORD dwDataLength = 0;
  216. CHECK_HR(hr = pBufferOut->GetCurrentLength(&dwDataLength));
  217. if(dwDataLength > 0) {
  218. if(dwDataLength != pSelf->xOutputSize) {
  219. TSK_DEBUG_ERROR("Output size mismatch");
  220. CHECK_HR(hr = E_BOUNDS);
  221. }
  222. CHECK_HR(hr = pBufferOut->Lock(&pBufferPtr, NULL, NULL));
  223. // MFCopyImage() is optimized: MMX, SSE, or SSE2
  224. switch(_self->dstChroma) {
  225. // Don't waste your time guessing which parameter to use: The consumer will always request RGB32. If not used for consumer then, just memcpy()
  226. case tmedia_chroma_rgb32: {
  227. if(pSelf->isVideoProcessor) {
  228. hr = _plugin_win_mf_converter_video_ms_copy_rgb32_down_top(
  229. (BYTE*)*output,
  230. (const BYTE*)pBufferPtr,
  231. (INT)pSelf->widthDst,
  232. (INT)pSelf->heightDst
  233. );
  234. }
  235. else {
  236. hr = MFCopyImage(
  237. (BYTE*)*output,
  238. (LONG)(pSelf->widthDst << 2),
  239. (BYTE*)pBufferPtr,
  240. (LONG)(pSelf->widthDst << 2),
  241. (DWORD)(pSelf->widthDst << 2),
  242. (DWORD)pSelf->heightDst
  243. );
  244. }
  245. if(FAILED(hr)) {
  246. // unlock() before leaving
  247. pBufferOut->Unlock();
  248. CHECK_HR(hr);
  249. }
  250. break;
  251. }
  252. default: {
  253. memcpy(*output, pBufferPtr, dwDataLength);
  254. }
  255. }
  256. CHECK_HR(hr = pBufferOut->Unlock());
  257. }
  258. }
  259. pSelf->rtStart += pSelf->rtDuration;
  260. bail:
  261. SafeRelease(&pSampleOut);
  262. SafeRelease(&pBufferOut);
  263. return SUCCEEDED(hr) ? pSelf->xOutputSize : 0;
  264. }
  265. static tsk_object_t* plugin_win_mf_converter_video_ms_ctor(tsk_object_t * self, va_list * app)
  266. {
  267. plugin_win_mf_converter_video_ms_t *pSelf = (plugin_win_mf_converter_video_ms_t *)self;
  268. if(pSelf) {
  269. HRESULT hr = MFFrameRateToAverageTimePerFrame(PLUGIN_MF_VC_FPS, 1, &pSelf->rtDuration);
  270. if(FAILED(hr)) {
  271. pSelf->rtDuration = 83333; // 120 FPS
  272. }
  273. }
  274. return self;
  275. }
  276. static tsk_object_t* plugin_win_mf_converter_video_ms_dtor(tsk_object_t * self)
  277. {
  278. plugin_win_mf_converter_video_ms_t *pSelf = (plugin_win_mf_converter_video_ms_t *)self;
  279. if(pSelf) {
  280. SafeRelease(&pSelf->pSampleOut);
  281. SafeRelease(&pSelf->pSampleIn);
  282. SafeRelease(&pSelf->pMFT);
  283. #if HAVE_IMFVideoProcessorControl
  284. SafeRelease(&pSelf->pVPC);
  285. #endif
  286. }
  287. return self;
  288. }
  289. static const tsk_object_def_t plugin_win_mf_converter_video_ms_def_s = {
  290. sizeof(plugin_win_mf_converter_video_ms_t),
  291. plugin_win_mf_converter_video_ms_ctor,
  292. plugin_win_mf_converter_video_ms_dtor,
  293. tsk_null,
  294. };
  295. const tsk_object_def_t *plugin_win_mf_converter_video_ms_def_t = &plugin_win_mf_converter_video_ms_def_s;
  296. static const tmedia_converter_video_plugin_def_t plugin_win_mf_converter_video_ms_plugin_def_s = {
  297. &plugin_win_mf_converter_video_ms_def_s,
  298. plugin_win_mf_converter_video_ms_init,
  299. plugin_win_mf_converter_video_ms_process
  300. };
  301. const tmedia_converter_video_plugin_def_t *plugin_win_mf_converter_video_ms_plugin_def_t = &plugin_win_mf_converter_video_ms_plugin_def_s;
  302. static inline tsk_size_t _plugin_win_mf_converter_video_ms_get_size(tmedia_chroma_t chroma, tsk_size_t w, tsk_size_t h)
  303. {
  304. switch(chroma) {
  305. case tmedia_chroma_rgb24:
  306. case tmedia_chroma_bgr24:
  307. return (w * h * 3);
  308. case tmedia_chroma_rgb565le:
  309. return ((w * h) << 1);
  310. case tmedia_chroma_rgb32:
  311. return ((w * h) << 2);
  312. case tmedia_chroma_nv21:
  313. return ((w * h * 3) >> 1);
  314. case tmedia_chroma_nv12:
  315. return ((w * h * 3) >> 1);
  316. case tmedia_chroma_yuv422p:
  317. return ((w * h) << 1);
  318. case tmedia_chroma_uyvy422:
  319. case tmedia_chroma_yuyv422:
  320. return ((w * h) << 1);
  321. case tmedia_chroma_yuv420p:
  322. return ((w * h * 3) >> 1);
  323. default:
  324. TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
  325. return 0;
  326. }
  327. }
  328. static inline const GUID& _plugin_win_mf_converter_video_ms_get_pixfmt(tmedia_chroma_t chroma)
  329. {
  330. switch(chroma) {
  331. case tmedia_chroma_rgb24:
  332. case tmedia_chroma_bgr24:
  333. return MFVideoFormat_RGB24;
  334. case tmedia_chroma_rgb565le:
  335. return MFVideoFormat_RGB565;
  336. case tmedia_chroma_rgb32:
  337. return MFVideoFormat_RGB32;
  338. case tmedia_chroma_nv12:
  339. return MFVideoFormat_NV12;
  340. case tmedia_chroma_yuv420p:
  341. return MFVideoFormat_I420;
  342. case tmedia_chroma_yuyv422:
  343. return MFVideoFormat_YUY2;
  344. case tmedia_chroma_uyvy422:
  345. return MFVideoFormat_UYVY;
  346. default:
  347. TSK_DEBUG_ERROR("Invalid chroma %d", (int)chroma);
  348. return GUID_NULL;
  349. }
  350. }
  351. // For RGB32:
  352. // Direct3D -> Top-Down
  353. // Video Processor -> Down-Top
  354. static inline HRESULT _plugin_win_mf_converter_video_ms_copy_rgb32_down_top(
  355. BYTE* pDst,
  356. const BYTE* pSrc,
  357. INT dwWidthInPixels,
  358. INT dwHeightInPixels
  359. )
  360. {
  361. RGBQUAD *pSrcPixel = &((RGBQUAD*)pSrc)[(dwWidthInPixels * dwHeightInPixels) - dwWidthInPixels];
  362. RGBQUAD *pDestPixel = &((RGBQUAD*)pDst)[0];
  363. register INT x;
  364. register INT y;
  365. for (y = dwHeightInPixels; y > 0 ; --y) {
  366. for (x = 0; x < dwWidthInPixels; ++x) {
  367. pDestPixel[x] = pSrcPixel[x];
  368. }
  369. pDestPixel += dwWidthInPixels;
  370. pSrcPixel -= dwWidthInPixels;
  371. }
  372. return S_OK;
  373. }
  374. static HRESULT _plugin_win_mf_converter_video_ms_process_input(plugin_win_mf_converter_video_ms_t* pSelf, IMFSample* pSample)
  375. {
  376. return pSelf->pMFT->ProcessInput(0, pSample, 0);
  377. }
  378. static HRESULT _plugin_win_mf_converter_video_ms_process_output(plugin_win_mf_converter_video_ms_t* pSelf, IMFSample **ppSample)
  379. {
  380. *ppSample = NULL;
  381. IMFMediaBuffer* pBufferOut = NULL;
  382. DWORD dwStatus;
  383. HRESULT hr = S_OK;
  384. MFT_OUTPUT_STREAM_INFO mftStreamInfo = { 0 };
  385. MFT_OUTPUT_DATA_BUFFER mftOutputData = { 0 };
  386. CHECK_HR(hr = pSelf->pMFT->GetOutputStreamInfo(0, &mftStreamInfo));
  387. if(!pSelf->pSampleOut) {
  388. CHECK_HR(hr = MFUtils::CreateMediaSample(mftStreamInfo.cbSize, &pSelf->pSampleOut));
  389. hr = pSelf->pSampleOut->GetBufferByIndex(0, &pBufferOut);
  390. if(FAILED(hr)) {
  391. SafeRelease(&pSelf->pSampleOut);
  392. CHECK_HR(hr);
  393. }
  394. }
  395. else {
  396. DWORD dwMaxLength = 0;
  397. CHECK_HR(hr = pSelf->pSampleOut->GetBufferByIndex(0, &pBufferOut));
  398. CHECK_HR(hr = pBufferOut->GetMaxLength(&dwMaxLength));
  399. if(dwMaxLength < mftStreamInfo.cbSize) {
  400. CHECK_HR(hr = pSelf->pSampleOut->RemoveAllBuffers());
  401. SafeRelease(&pBufferOut);
  402. CHECK_HR(hr = MFCreateMemoryBuffer(mftStreamInfo.cbSize, &pBufferOut));
  403. CHECK_HR(hr = pSelf->pSampleOut->AddBuffer(pBufferOut));
  404. }
  405. }
  406. CHECK_HR(hr = pBufferOut->SetCurrentLength(0));
  407. //Set the output sample
  408. mftOutputData.pSample = pSelf->pSampleOut;
  409. //Set the output id
  410. mftOutputData.dwStreamID = 0;
  411. //Generate the output sample
  412. CHECK_HR(hr = pSelf->pMFT->ProcessOutput(0, 1, &mftOutputData, &dwStatus));
  413. /*if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
  414. {
  415. hr = S_OK;
  416. goto bail;
  417. }*/
  418. // TODO: Handle MF_E_TRANSFORM_STREAM_CHANGE
  419. *ppSample = pSelf->pSampleOut;
  420. (*ppSample)->AddRef();
  421. bail:
  422. SafeRelease(&pBufferOut);
  423. return hr;
  424. }
  425. static HRESULT _plugin_win_mf_converter_video_ms_process(plugin_win_mf_converter_video_ms_t* pSelf, const void* pcInputPtr, UINT32 nInputSize, IMFSample **ppSampleOut)
  426. {
  427. if(!pcInputPtr || !nInputSize || !ppSampleOut) {
  428. TSK_DEBUG_ERROR("Invalid parameter");
  429. return E_INVALIDARG;
  430. }
  431. *ppSampleOut = NULL;
  432. HRESULT hr = S_OK;
  433. IMFMediaBuffer* pBufferIn = NULL;
  434. BYTE* pBufferPtr = NULL;
  435. if(!pSelf->pSampleIn) {
  436. CHECK_HR(hr = MFUtils::CreateMediaSample(nInputSize, &pSelf->pSampleIn));
  437. hr = pSelf->pSampleIn->GetBufferByIndex(0, &pBufferIn);
  438. if(FAILED(hr)) {
  439. SafeRelease(&pSelf->pSampleIn);
  440. CHECK_HR(hr);
  441. }
  442. }
  443. else {
  444. DWORD dwMaxLength = 0;
  445. CHECK_HR(hr = pSelf->pSampleIn->GetBufferByIndex(0, &pBufferIn));
  446. CHECK_HR(hr = pBufferIn->GetMaxLength(&dwMaxLength));
  447. if(dwMaxLength < nInputSize) {
  448. CHECK_HR(hr = pSelf->pSampleIn->RemoveAllBuffers());
  449. SafeRelease(&pBufferIn);
  450. CHECK_HR(hr = MFCreateMemoryBuffer(nInputSize, &pBufferIn));
  451. CHECK_HR(hr = pSelf->pSampleIn->AddBuffer(pBufferIn));
  452. }
  453. }
  454. CHECK_HR(hr = pBufferIn->Lock(&pBufferPtr, NULL, NULL));
  455. memcpy(pBufferPtr, pcInputPtr, nInputSize);
  456. CHECK_HR(hr = pBufferIn->Unlock());
  457. CHECK_HR(hr = pBufferIn->SetCurrentLength(nInputSize));
  458. CHECK_HR(hr = pSelf->pSampleIn->SetSampleDuration(pSelf->rtDuration));
  459. CHECK_HR(hr = pSelf->pSampleIn->SetSampleTime(pSelf->rtStart));
  460. hr = _plugin_win_mf_converter_video_ms_process_input(pSelf, pSelf->pSampleIn);
  461. while(hr == MF_E_NOTACCEPTING) {
  462. TSK_DEBUG_INFO("MF_E_NOTACCEPTING");
  463. IMFSample* pSample = NULL;
  464. hr = _plugin_win_mf_converter_video_ms_process_output(pSelf, &pSample);
  465. if(SUCCEEDED(hr) && pSample) {
  466. SafeRelease(ppSampleOut);
  467. *ppSampleOut = pSample, pSample = NULL;
  468. hr = pSelf->pSampleIn->SetUINT32(MFSampleExtension_Discontinuity, TRUE);
  469. hr = _plugin_win_mf_converter_video_ms_process_input(pSelf, pSelf->pSampleIn);
  470. }
  471. }
  472. if(!*ppSampleOut) {
  473. CHECK_HR(hr = _plugin_win_mf_converter_video_ms_process_output(pSelf, ppSampleOut));
  474. }
  475. bail:
  476. SafeRelease(&pBufferIn);
  477. return hr;
  478. }