plugin_audio_dsp_resampler.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. // MS Audio Resampler DSP: http://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
  20. #include "plugin_audio_dsp_utils.h"
  21. #include "tinymedia/tmedia_resampler.h"
  22. #include "tsk_memory.h"
  23. #include "tsk_debug.h"
  24. #include <initguid.h>
  25. #include <Wmcodecdsp.h>
  26. #include <Mftransform.h>
  27. #include <Mfapi.h>
  28. #include <Mferror.h>
  29. #if !defined(PLUGIN_AUDIO_DSP_RESAMPLER_MAX_QUALITY)
  30. # define PLUGIN_AUDIO_DSP_RESAMPLER_MAX_QUALITY 60 /* [1 - 60]: http://msdn.microsoft.com/en-us/library/windows/desktop/ff819449(v=vs.85).aspx */
  31. #endif
  32. static const UINT32 g_nBitsPerSample = 16;
  33. static HRESULT ProcessOutput(struct plugin_audio_dsp_resampler_s *resampler, IMFSample **ppSample);
  34. typedef struct plugin_audio_dsp_resampler_s {
  35. TMEDIA_DECLARE_RESAMPLER;
  36. bool bOpened;
  37. tsk_size_t in_size_samples;
  38. tsk_size_t in_size_bytes;
  39. tsk_size_t out_size_samples;
  40. tsk_size_t out_size_bytes;
  41. uint32_t in_channels;
  42. uint32_t out_channels;
  43. LONGLONG rtStart;
  44. UINT64 rtDuration;
  45. IMFTransform* pMFT;
  46. IMFSample *pSampleIn;
  47. IMFSample *pSampleOut;
  48. }
  49. plugin_audio_dsp_resampler_t;
  50. // Doubango engine uses quality from [1 - 10].
  51. static int plugin_audio_dsp_resampler_open(tmedia_resampler_t* self, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality)
  52. {
  53. plugin_audio_dsp_resampler_t *resampler = (plugin_audio_dsp_resampler_t *)self;
  54. IMFMediaType* pTypeIn = NULL;
  55. IMFMediaType* pTypeOut = NULL;
  56. IWMResamplerProps* pProps = NULL;
  57. HRESULT hr = S_OK;
  58. if(in_channels != 1 && in_channels != 2) {
  59. TSK_DEBUG_ERROR("%d not valid as input channel", in_channels);
  60. CHECK_HR(hr = E_INVALIDARG);
  61. }
  62. if(out_channels != 1 && out_channels != 2) {
  63. TSK_DEBUG_ERROR("%d not valid as output channel", out_channels);
  64. CHECK_HR(hr = E_INVALIDARG);
  65. }
  66. if(resampler->bOpened) {
  67. TSK_DEBUG_ERROR("Resampler already opened");
  68. CHECK_HR(hr = E_FAIL);
  69. }
  70. resampler->in_size_samples = ((in_freq * frame_duration) / 1000) << (in_channels == 2 ? 1 : 0);
  71. resampler->out_size_samples = ((out_freq * frame_duration) / 1000) << (out_channels == 2 ? 1 : 0);
  72. resampler->in_channels = in_channels;
  73. resampler->out_channels = out_channels;
  74. resampler->in_size_bytes = (resampler->in_size_samples * (g_nBitsPerSample >> 3));
  75. resampler->out_size_bytes = (resampler->out_size_samples * (g_nBitsPerSample >> 3));
  76. resampler->rtStart = 0;
  77. resampler->rtDuration = PLUGIN_AUDIO_DSP_MILLIS_TO_100NS(frame_duration); // milliseconds -> 100ns
  78. CHECK_HR(hr = CoCreateInstance(CLSID_CResamplerMediaObject, NULL,
  79. CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&resampler->pMFT)));
  80. CHECK_HR(hr = AudioDSPUtils::CreatePCMAudioType(in_freq, g_nBitsPerSample, in_channels, &pTypeIn));
  81. CHECK_HR(hr = AudioDSPUtils::CreatePCMAudioType(out_freq, g_nBitsPerSample, out_channels, &pTypeOut));
  82. CHECK_HR(hr = resampler->pMFT->SetInputType(0, pTypeIn, 0));
  83. CHECK_HR(hr = resampler->pMFT->SetOutputType(0, pTypeOut, 0));
  84. CHECK_HR(hr = resampler->pMFT->QueryInterface(IID_PPV_ARGS(&pProps)));
  85. CHECK_HR(hr = pProps->SetHalfFilterLength((quality * PLUGIN_AUDIO_DSP_RESAMPLER_MAX_QUALITY) / 10)); // [1 - 10] -> [1 - 60]
  86. CHECK_HR(hr = resampler->pMFT->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL));
  87. CHECK_HR(hr = resampler->pMFT->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL));
  88. CHECK_HR(hr = resampler->pMFT->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL));
  89. bail:
  90. resampler->bOpened = SUCCEEDED(hr);
  91. if(!resampler->bOpened) {
  92. SafeRelease(&resampler->pMFT);
  93. }
  94. SafeRelease(&pTypeIn);
  95. SafeRelease(&pTypeOut);
  96. SafeRelease(&pProps);
  97. return resampler->bOpened ? 0 : -1;
  98. }
  99. static tsk_size_t plugin_audio_dsp_resampler_process(tmedia_resampler_t* self, const uint16_t* in_data, tsk_size_t in_size, uint16_t* out_data, tsk_size_t out_size)
  100. {
  101. plugin_audio_dsp_resampler_t *resampler = (plugin_audio_dsp_resampler_t *)self;
  102. HRESULT hr = S_OK;
  103. tsk_size_t retSize = 0;
  104. if(!resampler || !out_data) {
  105. CHECK_HR(hr = E_POINTER);
  106. }
  107. if(!resampler->bOpened) {
  108. TSK_DEBUG_ERROR("Resampler not opened");
  109. CHECK_HR(hr = E_FAIL);
  110. }
  111. if(in_size != resampler->in_size_samples) {
  112. TSK_DEBUG_ERROR("Input data has wrong size");
  113. CHECK_HR(hr = E_FAIL);
  114. }
  115. if(out_size < resampler->out_size_samples) {
  116. TSK_DEBUG_ERROR("Output data is too short");
  117. CHECK_HR(hr = E_FAIL);
  118. }
  119. IMFMediaBuffer* pBufferIn = NULL;
  120. IMFMediaBuffer* pBufferOut = NULL;
  121. IMFSample *pSampleOut = NULL;
  122. BYTE* pBufferPtr = NULL;
  123. if(!resampler->pSampleIn) {
  124. CHECK_HR(hr = AudioDSPUtils::CreateMediaSample(resampler->in_size_bytes, &resampler->pSampleIn));
  125. hr = resampler->pSampleIn->GetBufferByIndex(0, &pBufferIn);
  126. if(FAILED(hr)) {
  127. SafeRelease(&resampler->pSampleIn);
  128. CHECK_HR(hr);
  129. }
  130. }
  131. else {
  132. DWORD dwMaxLength = 0;
  133. CHECK_HR(hr = resampler->pSampleIn->GetBufferByIndex(0, &pBufferIn));
  134. CHECK_HR(hr = pBufferIn->GetMaxLength(&dwMaxLength));
  135. if(dwMaxLength < resampler->in_size_bytes) {
  136. CHECK_HR(hr = resampler->pSampleIn->RemoveAllBuffers());
  137. SafeRelease(&pBufferIn);
  138. CHECK_HR(hr = MFCreateMemoryBuffer(resampler->in_size_bytes, &pBufferIn));
  139. CHECK_HR(hr = resampler->pSampleIn->AddBuffer(pBufferIn));
  140. }
  141. }
  142. CHECK_HR(hr = pBufferIn->Lock(&pBufferPtr, NULL, NULL));
  143. memcpy(pBufferPtr, in_data, resampler->in_size_bytes);
  144. CHECK_HR(hr = pBufferIn->Unlock());
  145. CHECK_HR(hr = pBufferIn->SetCurrentLength(resampler->in_size_bytes));
  146. CHECK_HR(hr = resampler->pSampleIn->SetSampleDuration(resampler->rtDuration));
  147. CHECK_HR(hr = resampler->pSampleIn->SetSampleTime(resampler->rtStart));
  148. // Process input
  149. hr = resampler->pMFT->ProcessInput(0, resampler->pSampleIn, 0);
  150. if(hr == MF_E_NOTACCEPTING) {
  151. hr = S_OK;
  152. }
  153. CHECK_HR(hr);
  154. resampler->rtStart += resampler->rtDuration;
  155. // Process output
  156. CHECK_HR(hr = ProcessOutput(resampler, &pSampleOut));
  157. if(pSampleOut) {
  158. CHECK_HR(hr = pSampleOut->GetBufferByIndex(0, &pBufferOut));
  159. BYTE* pBufferOutPtr = NULL;
  160. DWORD dwDataLength = 0;
  161. CHECK_HR(hr = pBufferOut->GetCurrentLength(&dwDataLength));
  162. //if(dwDataLength == resampler->out_size_bytes)
  163. {
  164. CHECK_HR(hr = pBufferOut->Lock(&pBufferOutPtr, NULL, NULL));
  165. {
  166. memcpy(out_data, pBufferOutPtr, TSK_MIN(dwDataLength, resampler->out_size_bytes));
  167. if(dwDataLength < resampler->out_size_bytes) {
  168. TSK_DEBUG_INFO("[MS Resampler DSP] Output too short filling with silence");
  169. memset(&((uint8_t*)out_data)[dwDataLength], 0, (resampler->out_size_bytes - dwDataLength));
  170. }
  171. retSize = (tsk_size_t)resampler->out_size_bytes;
  172. }
  173. CHECK_HR(hr = pBufferOut->Unlock());
  174. }
  175. }
  176. bail:
  177. SafeRelease(&pBufferIn);
  178. SafeRelease(&pBufferOut);
  179. SafeRelease(&pSampleOut);
  180. return retSize;
  181. }
  182. static int plugin_audio_dsp_resampler_close(tmedia_resampler_t* self)
  183. {
  184. plugin_audio_dsp_resampler_t *resampler = (plugin_audio_dsp_resampler_t *)self;
  185. HRESULT hr = S_OK;
  186. if(resampler->pMFT) {
  187. hr = resampler->pMFT->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, NULL);
  188. }
  189. SafeRelease(&resampler->pMFT);
  190. SafeRelease(&resampler->pSampleIn);
  191. SafeRelease(&resampler->pSampleOut);
  192. resampler->bOpened = false;
  193. return 0;
  194. }
  195. static HRESULT ProcessOutput(plugin_audio_dsp_resampler_t *resampler, IMFSample **ppSample)
  196. {
  197. *ppSample = NULL;
  198. IMFMediaBuffer* pBufferOut = NULL;
  199. DWORD dwStatus;
  200. HRESULT hr = S_OK;
  201. MFT_OUTPUT_DATA_BUFFER mftOutputData = { 0 };
  202. if(!resampler || !ppSample) {
  203. CHECK_HR(hr = E_POINTER);
  204. }
  205. if(!resampler->pSampleOut) {
  206. CHECK_HR(hr = AudioDSPUtils::CreateMediaSample(resampler->out_size_bytes, &resampler->pSampleOut));
  207. hr = resampler->pSampleOut->GetBufferByIndex(0, &pBufferOut);
  208. if(FAILED(hr)) {
  209. SafeRelease(&resampler->pSampleOut);
  210. CHECK_HR(hr);
  211. }
  212. }
  213. else {
  214. DWORD dwMaxLength = 0;
  215. CHECK_HR(hr = resampler->pSampleOut->GetBufferByIndex(0, &pBufferOut));
  216. CHECK_HR(hr = pBufferOut->GetMaxLength(&dwMaxLength));
  217. if(dwMaxLength < resampler->out_size_bytes) {
  218. CHECK_HR(hr = resampler->pSampleOut->RemoveAllBuffers());
  219. SafeRelease(&pBufferOut);
  220. CHECK_HR(hr = MFCreateMemoryBuffer(resampler->out_size_bytes, &pBufferOut));
  221. CHECK_HR(hr = resampler->pSampleOut->AddBuffer(pBufferOut));
  222. }
  223. }
  224. CHECK_HR(hr = pBufferOut->SetCurrentLength(0));
  225. //Set the output sample
  226. mftOutputData.pSample = resampler->pSampleOut;
  227. //Set the output id
  228. mftOutputData.dwStreamID = 0;
  229. //Generate the output sample
  230. hr = resampler->pMFT->ProcessOutput(0, 1, &mftOutputData, &dwStatus);
  231. if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
  232. hr = S_OK;
  233. goto bail;
  234. }
  235. // TODO: Handle MF_E_TRANSFORM_STREAM_CHANGE
  236. if (FAILED(hr)) {
  237. goto bail;
  238. }
  239. *ppSample = resampler->pSampleOut;
  240. (*ppSample)->AddRef();
  241. bail:
  242. SafeRelease(&pBufferOut);
  243. return hr;
  244. }
  245. //
  246. // Speex resamplerr Plugin definition
  247. //
  248. /* constructor */
  249. static tsk_object_t* plugin_audio_dsp_resampler_ctor(tsk_object_t * self, va_list * app)
  250. {
  251. plugin_audio_dsp_resampler_t *resampler = (plugin_audio_dsp_resampler_t *)self;
  252. if(resampler) {
  253. AudioDSPUtils::Startup();
  254. /* init base */
  255. tmedia_resampler_init(TMEDIA_RESAMPLER(resampler));
  256. /* init self */
  257. }
  258. return self;
  259. }
  260. /* destructor */
  261. static tsk_object_t* plugin_audio_dsp_resampler_dtor(tsk_object_t * self)
  262. {
  263. plugin_audio_dsp_resampler_t *resampler = (plugin_audio_dsp_resampler_t *)self;
  264. if(resampler) {
  265. /* deinit base */
  266. tmedia_resampler_deinit(TMEDIA_RESAMPLER(resampler));
  267. /* deinit self */
  268. // tmedia_resampler_deinit() already closed the resampler and freed the resources...but do it again
  269. SafeRelease(&resampler->pMFT);
  270. SafeRelease(&resampler->pSampleIn);
  271. SafeRelease(&resampler->pSampleOut);
  272. TSK_DEBUG_INFO("*** MS Audio Resampler DSP (plugin) destroyed ***");
  273. }
  274. return self;
  275. }
  276. /* object definition */
  277. static const tsk_object_def_t plugin_audio_dsp_resampler_def_s = {
  278. sizeof(plugin_audio_dsp_resampler_t),
  279. plugin_audio_dsp_resampler_ctor,
  280. plugin_audio_dsp_resampler_dtor,
  281. tsk_null,
  282. };
  283. /* plugin definition*/
  284. static const tmedia_resampler_plugin_def_t plugin_audio_dsp_resampler_plugin_def_s = {
  285. &plugin_audio_dsp_resampler_def_s,
  286. "MS Audio Resampler DSP", /* http://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx */
  287. plugin_audio_dsp_resampler_open,
  288. plugin_audio_dsp_resampler_process,
  289. plugin_audio_dsp_resampler_close,
  290. };
  291. const tmedia_resampler_plugin_def_t *plugin_audio_dsp_resampler_plugin_def_t = &plugin_audio_dsp_resampler_plugin_def_s;