ACMEncoder.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "ACMEncoder.h"
  2. #define rev32(X) ((((DWORD)(X)&0xFF)<<24)|(((DWORD)(X)&0xFF00)<<8)|(((DWORD)(X)&0xFF0000)>>8)|(((DWORD)(X)&0xFF000000)>>24))
  3. static DWORD FileTell(HANDLE hFile)
  4. {
  5. return SetFilePointer(hFile, 0, 0, FILE_CURRENT);
  6. }
  7. static void FileAlign(HANDLE hFile)
  8. {
  9. if (FileTell(hFile)&1) SetFilePointer(hFile, 1, 0, FILE_CURRENT);
  10. }
  11. #define BUFSIZE 0x20000
  12. ACMEncoder::ACMEncoder(int srate, int nch, int bps, ACMConfig *config)
  13. {
  14. m_did_header = 0;
  15. m_srate = srate;
  16. m_nch = nch;
  17. m_bps = bps;
  18. m_error = 0;
  19. hStream = 0;
  20. hStreamResample = 0;
  21. m_acm_resample_buf = NULL;
  22. m_acm_resample_outbuf = NULL;
  23. m_bytes_done = 0;
  24. m_hlen = 0;
  25. m_nsam = 0;
  26. m_acm_buf = (unsigned char *)malloc(BUFSIZE);
  27. m_acm_outbuf = (unsigned char *)malloc(BUFSIZE);
  28. m_bytes_inbuf = 0;
  29. m_bytes_outbuf = 0;
  30. m_convert_wfx = config->convert_wfx;
  31. do_header = config->header;
  32. m_wfx_src.wFormatTag = WAVE_FORMAT_PCM;
  33. m_wfx_src.nChannels = nch;
  34. m_wfx_src.nSamplesPerSec = srate;
  35. m_wfx_src.nAvgBytesPerSec = srate * nch * (bps >> 3);
  36. m_wfx_src.nBlockAlign = nch * (bps >> 3);
  37. m_wfx_src.wBitsPerSample = bps;
  38. m_wfx_src.cbSize = 0;
  39. MMRESULT rs = acmStreamOpen(&hStream, 0, &m_wfx_src, &m_convert_wfx.wfx, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
  40. if (rs)
  41. {
  42. // need resampling
  43. WAVEFORMATEX wfx1;
  44. ZeroMemory(&wfx1, sizeof(wfx1));
  45. wfx1.wFormatTag = WAVE_FORMAT_PCM;
  46. if (acmFormatSuggest(0, &m_convert_wfx.wfx, &wfx1, sizeof(WAVEFORMATEX), ACM_FORMATSUGGESTF_WFORMATTAG)) m_error = 1;
  47. else if (acmStreamOpen(&hStream, 0, &wfx1, &m_convert_wfx.wfx, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME)) m_error = 1;
  48. else if (acmStreamOpen(&hStreamResample, 0, &m_wfx_src, &wfx1, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME)) m_error = 1;
  49. else
  50. {
  51. ZeroMemory(&ahdResample, sizeof(ahdResample));
  52. ahdResample.cbStruct = sizeof(ahdResample);
  53. ahdResample.pbSrc = m_acm_resample_buf = (unsigned char *)malloc(BUFSIZE);
  54. ahdResample.cbSrcLength = BUFSIZE;
  55. ahdResample.pbDst = m_acm_resample_outbuf = (unsigned char *)malloc(BUFSIZE);
  56. ahdResample.cbDstLength = BUFSIZE;
  57. if (acmStreamPrepareHeader(hStreamResample, &ahdResample, 0)) m_error = 1;
  58. m_bytes_inbuf_resample = 0;
  59. m_bytes_outbuf_resample = 0;
  60. }
  61. }
  62. if (!hStream)
  63. {
  64. m_error = 1;
  65. return ;
  66. }
  67. ZeroMemory(&ahd, sizeof(ahd));
  68. ahd.cbStruct = sizeof(ahd);
  69. ahd.pbSrc = m_acm_buf;
  70. ahd.cbSrcLength = BUFSIZE;
  71. ahd.pbDst = m_acm_outbuf;
  72. ahd.cbDstLength = BUFSIZE;
  73. if (acmStreamPrepareHeader(hStream, &ahd, 0)) m_error = 1;
  74. }
  75. ACMEncoder::~ACMEncoder()
  76. {
  77. free(m_acm_buf);
  78. free(m_acm_outbuf);
  79. free(m_acm_resample_buf);
  80. free(m_acm_resample_outbuf);
  81. if (hStream)
  82. {
  83. if (ahd.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStream, &ahd, 0);
  84. acmStreamClose(hStream, 0);
  85. }
  86. if (hStreamResample)
  87. {
  88. if (ahdResample.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) acmStreamUnprepareHeader(hStreamResample, &ahdResample, 0);
  89. acmStreamClose(hStreamResample, 0);
  90. }
  91. }
  92. int ACMEncoder::Encode(int framepos, void *in, int in_avail, int *in_used, void *out, int out_avail)
  93. {
  94. char *pout = (char *)out;
  95. int retval = 0;
  96. if (!m_did_header && do_header)
  97. {
  98. int s = 4 + 4 + 12 - 4;
  99. int t;
  100. if (m_convert_wfx.wfx.wFormatTag == WAVE_FORMAT_PCM) t = 0x10;
  101. else t = sizeof(WAVEFORMATEX) + m_convert_wfx.wfx.cbSize;
  102. s += 4 + t;
  103. if (s&1) s++;
  104. if (m_convert_wfx.wfx.wFormatTag != WAVE_FORMAT_PCM)
  105. s += 12;
  106. s += 8;
  107. if (out_avail < s) return 0;
  108. //xx bytes of randomness
  109. m_hlen = s;
  110. m_did_header = 1;
  111. out_avail -= s;
  112. pout += s;
  113. retval = s;
  114. }
  115. if (!m_bytes_outbuf)
  116. {
  117. if (hStreamResample)
  118. {
  119. if (!m_bytes_outbuf_resample)
  120. {
  121. DWORD flags = ACM_STREAMCONVERTF_BLOCKALIGN;
  122. int l = min(in_avail, BUFSIZE - m_bytes_inbuf_resample);
  123. if (l < 0) l = 0;
  124. if (l > 0) memcpy(m_acm_resample_buf + m_bytes_inbuf_resample, in, l);
  125. m_bytes_inbuf_resample += l;
  126. *in_used = l;
  127. m_nsam += l;
  128. ahdResample.cbSrcLength = m_bytes_inbuf_resample;
  129. acmStreamConvert(hStreamResample, &ahdResample, flags);
  130. m_bytes_inbuf_resample -= ahdResample.cbSrcLengthUsed;
  131. memcpy(m_acm_resample_buf, m_acm_resample_buf + ahdResample.cbSrcLengthUsed, m_bytes_inbuf_resample); //memmove
  132. m_bytes_outbuf_resample = ahdResample.cbDstLengthUsed;
  133. }
  134. in = (void*)m_acm_resample_outbuf;
  135. in_avail = m_bytes_outbuf_resample;
  136. m_bytes_outbuf_resample = 0;
  137. in_used = NULL;
  138. }
  139. DWORD flags = ACM_STREAMCONVERTF_BLOCKALIGN;
  140. int l = min(in_avail, BUFSIZE - m_bytes_inbuf);
  141. if (l < 0) l = 0;
  142. if (l > 0) memcpy(m_acm_buf + m_bytes_inbuf, in, l);
  143. m_bytes_inbuf += l;
  144. if (in_used)
  145. {
  146. *in_used = l;
  147. m_nsam += l;
  148. }
  149. if (m_bytes_inbuf)
  150. {
  151. ahd.cbSrcLength = m_bytes_inbuf;
  152. acmStreamConvert(hStream, &ahd, flags);
  153. m_bytes_inbuf -= ahd.cbSrcLengthUsed;
  154. memcpy(m_acm_buf, m_acm_buf + ahd.cbSrcLengthUsed, m_bytes_inbuf); //memmove
  155. m_bytes_outbuf = ahd.cbDstLengthUsed;
  156. m_bytes_done += l;
  157. }
  158. }
  159. if (m_bytes_outbuf)
  160. {
  161. int l = min(out_avail, m_bytes_outbuf);
  162. memcpy(pout, m_acm_outbuf, l);
  163. m_bytes_outbuf -= l;
  164. memcpy(m_acm_outbuf, m_acm_outbuf + l, m_bytes_outbuf);
  165. retval += l;
  166. }
  167. return retval;
  168. }
  169. void ACMEncoder::FinishAudio(const wchar_t *filename)
  170. {
  171. if (!do_header) return ;
  172. HANDLE fh = CreateFileW(filename, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  173. if (fh == INVALID_HANDLE_VALUE)
  174. return;
  175. int len, i;
  176. const unsigned char ispred1[4] =
  177. {
  178. 0x52 , 0x49 , 0x46 , 0x46
  179. };
  180. const unsigned char ispred2[12] =
  181. {
  182. 0x57, 0x41 , 0x56 , 0x45 , 0x66 , 0x6d , 0x74 , 0x20 , 0x10 , 0x0 , 0x0 , 0x0
  183. };
  184. len = m_bytes_done;
  185. DWORD a = 0;
  186. FileAlign(fh);
  187. SetFilePointer(fh, 0, 0, FILE_BEGIN);
  188. WriteFile(fh, ispred1, sizeof(ispred1), &a, NULL);
  189. i = len + (m_hlen) - 8;
  190. if (i&1) i++;
  191. a = 0; WriteFile(fh, &i, 4, &a, NULL);
  192. a = 0; WriteFile(fh, ispred2, sizeof(ispred2) - (hStream ? 4 : 0), &a, NULL);
  193. int t;
  194. if (m_convert_wfx.wfx.wFormatTag == WAVE_FORMAT_PCM) t = 0x10;
  195. else t = sizeof(WAVEFORMATEX) + m_convert_wfx.wfx.cbSize;
  196. a = 0; WriteFile(fh, &t, 4, &a, 0);
  197. a = 0; WriteFile(fh, &m_convert_wfx.wfx, t, &a, 0);
  198. FileAlign(fh);
  199. DWORD fact_ofs = 0;
  200. if (m_convert_wfx.wfx.wFormatTag != WAVE_FORMAT_PCM)
  201. {
  202. t = rev32('fact');
  203. a = 0; WriteFile(fh, &t, 4, &a, 0);
  204. t = 4;
  205. a = 0; WriteFile(fh, &t, 4, &a, 0);
  206. fact_ofs = FileTell(fh);
  207. SetFilePointer(fh, 4, 0, FILE_CURRENT);
  208. }
  209. t = rev32('data');
  210. WriteFile(fh, &t, 4, &a, 0);
  211. DWORD data_ofs = FileTell(fh);
  212. {
  213. DWORD t, bw = 0;
  214. SetFilePointer(fh, 4, 0, FILE_BEGIN);
  215. t = GetFileSize(fh, 0) - 8;
  216. WriteFile(fh, &t, 4, &bw, 0);
  217. DWORD data_size = GetFileSize(fh, 0) - (data_ofs + 4);
  218. SetFilePointer(fh, data_ofs, 0, FILE_BEGIN);
  219. bw = 0; WriteFile(fh, &data_size, 4, &bw, 0);
  220. if (fact_ofs)
  221. {
  222. SetFilePointer(fh, fact_ofs, 0, FILE_BEGIN);
  223. t = m_nsam / ((m_bps >> 3) * m_nch);
  224. WriteFile(fh, &t, 4, &bw, 0);
  225. }
  226. }
  227. CloseHandle(fh);
  228. }
  229. int ACMEncoder::GetLastError() { return m_error; }