PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llaudio/llvorbisencode.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 506 lines | 327 code | 90 blank | 89 comment | 51 complexity | 83862154a615793a8a32ddbe39226d66 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file vorbisencode.cpp
  3. * @brief Vorbis encoding routine routine for Indra.
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "vorbis/vorbisenc.h"
  28. #include "llvorbisencode.h"
  29. #include "llerror.h"
  30. #include "llrand.h"
  31. #include "llmath.h"
  32. #include "llapr.h"
  33. //#if LL_DARWIN
  34. // MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions.
  35. #if 0
  36. #include "VorbisFramework.h"
  37. #define vorbis_analysis mac_vorbis_analysis
  38. #define vorbis_analysis_headerout mac_vorbis_analysis_headerout
  39. #define vorbis_analysis_init mac_vorbis_analysis_init
  40. #define vorbis_encode_ctl mac_vorbis_encode_ctl
  41. #define vorbis_encode_setup_init mac_vorbis_encode_setup_init
  42. #define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed
  43. #define vorbis_info_init mac_vorbis_info_init
  44. #define vorbis_info_clear mac_vorbis_info_clear
  45. #define vorbis_comment_init mac_vorbis_comment_init
  46. #define vorbis_comment_clear mac_vorbis_comment_clear
  47. #define vorbis_block_init mac_vorbis_block_init
  48. #define vorbis_block_clear mac_vorbis_block_clear
  49. #define vorbis_dsp_clear mac_vorbis_dsp_clear
  50. #define vorbis_analysis_buffer mac_vorbis_analysis_buffer
  51. #define vorbis_analysis_wrote mac_vorbis_analysis_wrote
  52. #define vorbis_analysis_blockout mac_vorbis_analysis_blockout
  53. #define ogg_stream_packetin mac_ogg_stream_packetin
  54. #define ogg_stream_init mac_ogg_stream_init
  55. #define ogg_stream_flush mac_ogg_stream_flush
  56. #define ogg_stream_pageout mac_ogg_stream_pageout
  57. #define ogg_page_eos mac_ogg_page_eos
  58. #define ogg_stream_clear mac_ogg_stream_clear
  59. #endif
  60. S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& error_msg)
  61. {
  62. U16 num_channels = 0;
  63. U32 sample_rate = 0;
  64. U32 bits_per_sample = 0;
  65. U32 physical_file_size = 0;
  66. U32 chunk_length = 0;
  67. U32 raw_data_length = 0;
  68. U32 bytes_per_sec = 0;
  69. BOOL uncompressed_pcm = FALSE;
  70. unsigned char wav_header[44]; /*Flawfinder: ignore*/
  71. error_msg.clear();
  72. //********************************
  73. LLAPRFile infile ;
  74. infile.open(in_fname,LL_APR_RB);
  75. //********************************
  76. if (!infile.getFileHandle())
  77. {
  78. error_msg = "CannotUploadSoundFile";
  79. return(LLVORBISENC_SOURCE_OPEN_ERR);
  80. }
  81. infile.read(wav_header, 44);
  82. physical_file_size = infile.seek(APR_END,0);
  83. if (strncmp((char *)&(wav_header[0]),"RIFF",4))
  84. {
  85. error_msg = "SoundFileNotRIFF";
  86. return(LLVORBISENC_WAV_FORMAT_ERR);
  87. }
  88. if (strncmp((char *)&(wav_header[8]),"WAVE",4))
  89. {
  90. error_msg = "SoundFileNotRIFF";
  91. return(LLVORBISENC_WAV_FORMAT_ERR);
  92. }
  93. // parse the chunks
  94. U32 file_pos = 12; // start at the first chunk (usually fmt but not always)
  95. while ((file_pos + 8)< physical_file_size)
  96. {
  97. infile.seek(APR_SET,file_pos);
  98. infile.read(wav_header, 44);
  99. chunk_length = ((U32) wav_header[7] << 24)
  100. + ((U32) wav_header[6] << 16)
  101. + ((U32) wav_header[5] << 8)
  102. + wav_header[4];
  103. if (chunk_length > physical_file_size - file_pos - 4)
  104. {
  105. infile.close();
  106. error_msg = "SoundFileInvalidChunkSize";
  107. return(LLVORBISENC_CHUNK_SIZE_ERR);
  108. }
  109. // llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
  110. if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
  111. {
  112. if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00))
  113. {
  114. uncompressed_pcm = TRUE;
  115. }
  116. num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
  117. sample_rate = ((U32) wav_header[15] << 24)
  118. + ((U32) wav_header[14] << 16)
  119. + ((U32) wav_header[13] << 8)
  120. + wav_header[12];
  121. bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
  122. bytes_per_sec = ((U32) wav_header[19] << 24)
  123. + ((U32) wav_header[18] << 16)
  124. + ((U32) wav_header[17] << 8)
  125. + wav_header[16];
  126. }
  127. else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
  128. {
  129. raw_data_length = chunk_length;
  130. }
  131. file_pos += (chunk_length + 8);
  132. chunk_length = 0;
  133. }
  134. //****************
  135. infile.close();
  136. //****************
  137. if (!uncompressed_pcm)
  138. {
  139. error_msg = "SoundFileNotPCM";
  140. return(LLVORBISENC_PCM_FORMAT_ERR);
  141. }
  142. if ((num_channels < 1) || (num_channels > LLVORBIS_CLIP_MAX_CHANNELS))
  143. {
  144. error_msg = "SoundFileInvalidChannelCount";
  145. return(LLVORBISENC_MULTICHANNEL_ERR);
  146. }
  147. if (sample_rate != LLVORBIS_CLIP_SAMPLE_RATE)
  148. {
  149. error_msg = "SoundFileInvalidSampleRate";
  150. return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE);
  151. }
  152. if ((bits_per_sample != 16) && (bits_per_sample != 8))
  153. {
  154. error_msg = "SoundFileInvalidWordSize";
  155. return(LLVORBISENC_UNSUPPORTED_WORD_SIZE);
  156. }
  157. if (!raw_data_length)
  158. {
  159. error_msg = "SoundFileInvalidHeader";
  160. return(LLVORBISENC_CLIP_TOO_LONG);
  161. }
  162. F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec;
  163. if (clip_length > LLVORBIS_CLIP_MAX_TIME)
  164. {
  165. error_msg = "SoundFileInvalidTooLong";
  166. return(LLVORBISENC_CLIP_TOO_LONG);
  167. }
  168. return(LLVORBISENC_NOERR);
  169. }
  170. S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname)
  171. {
  172. #define READ_BUFFER 1024
  173. unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/
  174. ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
  175. ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
  176. ogg_packet op; /* one raw packet of data for decode */
  177. vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
  178. vorbis_comment vc; /* struct that stores all the user comments */
  179. vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
  180. vorbis_block vb; /* local working space for packet->PCM decode */
  181. int eos=0;
  182. int result;
  183. U16 num_channels = 0;
  184. U32 sample_rate = 0;
  185. U32 bits_per_sample = 0;
  186. S32 format_error = 0;
  187. std::string error_msg;
  188. if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg)))
  189. {
  190. llwarns << error_msg << ": " << in_fname << llendl;
  191. return(format_error);
  192. }
  193. #if 1
  194. unsigned char wav_header[44]; /*Flawfinder: ignore*/
  195. S32 data_left = 0;
  196. LLAPRFile infile ;
  197. infile.open(in_fname,LL_APR_RB);
  198. if (!infile.getFileHandle())
  199. {
  200. llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
  201. << llendl;
  202. return(LLVORBISENC_SOURCE_OPEN_ERR);
  203. }
  204. LLAPRFile outfile ;
  205. outfile.open(out_fname,LL_APR_WPB);
  206. if (!outfile.getFileHandle())
  207. {
  208. llwarns << "Couldn't open upload sound file for reading: " << in_fname
  209. << llendl;
  210. return(LLVORBISENC_DEST_OPEN_ERR);
  211. }
  212. // parse the chunks
  213. U32 chunk_length = 0;
  214. U32 file_pos = 12; // start at the first chunk (usually fmt but not always)
  215. while (infile.eof() != APR_EOF)
  216. {
  217. infile.seek(APR_SET,file_pos);
  218. infile.read(wav_header, 44);
  219. chunk_length = ((U32) wav_header[7] << 24)
  220. + ((U32) wav_header[6] << 16)
  221. + ((U32) wav_header[5] << 8)
  222. + wav_header[4];
  223. // llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
  224. if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
  225. {
  226. num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
  227. sample_rate = ((U32) wav_header[15] << 24)
  228. + ((U32) wav_header[14] << 16)
  229. + ((U32) wav_header[13] << 8)
  230. + wav_header[12];
  231. bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
  232. }
  233. else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
  234. {
  235. infile.seek(APR_SET,file_pos+8);
  236. // leave the file pointer at the beginning of the data chunk data
  237. data_left = chunk_length;
  238. break;
  239. }
  240. file_pos += (chunk_length + 8);
  241. chunk_length = 0;
  242. }
  243. /********** Encode setup ************/
  244. /* choose an encoding mode */
  245. /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
  246. vorbis_info_init(&vi);
  247. // always encode to mono
  248. // SL-52913 & SL-53779 determined this quality level to be our 'good
  249. // enough' general-purpose quality level with a nice low bitrate.
  250. // Equivalent to oggenc -q0.5
  251. F32 quality = 0.05f;
  252. // quality = (bitrate==128000 ? 0.4f : 0.1);
  253. // if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1))
  254. if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality))
  255. // if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) ||
  256. // vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) ||
  257. // vorbis_encode_setup_init(&vi))
  258. {
  259. llwarns << "unable to initialize vorbis codec at quality " << quality << llendl;
  260. // llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl;
  261. return(LLVORBISENC_DEST_OPEN_ERR);
  262. }
  263. /* add a comment */
  264. vorbis_comment_init(&vc);
  265. // vorbis_comment_add(&vc,"Linden");
  266. /* set up the analysis state and auxiliary encoding storage */
  267. vorbis_analysis_init(&vd,&vi);
  268. vorbis_block_init(&vd,&vb);
  269. /* set up our packet->stream encoder */
  270. /* pick a random serial number; that way we can more likely build
  271. chained streams just by concatenation */
  272. ogg_stream_init(&os, ll_rand());
  273. /* Vorbis streams begin with three headers; the initial header (with
  274. most of the codec setup parameters) which is mandated by the Ogg
  275. bitstream spec. The second header holds any comment fields. The
  276. third header holds the bitstream codebook. We merely need to
  277. make the headers, then pass them to libvorbis one at a time;
  278. libvorbis handles the additional Ogg bitstream constraints */
  279. {
  280. ogg_packet header;
  281. ogg_packet header_comm;
  282. ogg_packet header_code;
  283. vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
  284. ogg_stream_packetin(&os,&header); /* automatically placed in its own
  285. page */
  286. ogg_stream_packetin(&os,&header_comm);
  287. ogg_stream_packetin(&os,&header_code);
  288. /* We don't have to write out here, but doing so makes streaming
  289. * much easier, so we do, flushing ALL pages. This ensures the actual
  290. * audio data will start on a new page
  291. */
  292. while(!eos){
  293. int result=ogg_stream_flush(&os,&og);
  294. if(result==0)break;
  295. outfile.write(og.header, og.header_len);
  296. outfile.write(og.body, og.body_len);
  297. }
  298. }
  299. while(!eos)
  300. {
  301. long bytes_per_sample = bits_per_sample/8;
  302. long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */
  303. if (bytes==0)
  304. {
  305. /* end of file. this can be done implicitly in the mainline,
  306. but it's easier to see here in non-clever fashion.
  307. Tell the library we're at end of stream so that it can handle
  308. the last frame and mark end of stream in the output properly */
  309. vorbis_analysis_wrote(&vd,0);
  310. // eos = 1;
  311. }
  312. else
  313. {
  314. long i;
  315. long samples;
  316. int temp;
  317. data_left -= bytes;
  318. /* data to encode */
  319. /* expose the buffer to submit data */
  320. float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER);
  321. i = 0;
  322. samples = bytes / (num_channels * bytes_per_sample);
  323. if (num_channels == 2)
  324. {
  325. if (bytes_per_sample == 2)
  326. {
  327. /* uninterleave samples */
  328. for(i=0; i<samples ;i++)
  329. {
  330. temp = ((signed char *)readbuffer)[i*4+1]; /*Flawfinder: ignore*/
  331. temp += ((signed char *)readbuffer)[i*4+3]; /*Flawfinder: ignore*/
  332. temp <<= 8;
  333. temp += readbuffer[i*4];
  334. temp += readbuffer[i*4+2];
  335. buffer[0][i] = ((float)temp) / 65536.f;
  336. }
  337. }
  338. else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard")
  339. {
  340. /* uninterleave samples */
  341. for(i=0; i<samples ;i++)
  342. {
  343. temp = readbuffer[i*2+0];
  344. temp += readbuffer[i*2+1];
  345. temp -= 256;
  346. buffer[0][i] = ((float)temp) / 256.f;
  347. }
  348. }
  349. }
  350. else if (num_channels == 1)
  351. {
  352. if (bytes_per_sample == 2)
  353. {
  354. for(i=0; i < samples ;i++)
  355. {
  356. temp = ((signed char*)readbuffer)[i*2+1];
  357. temp <<= 8;
  358. temp += readbuffer[i*2];
  359. buffer[0][i] = ((float)temp) / 32768.f;
  360. }
  361. }
  362. else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard")
  363. {
  364. for(i=0; i < samples ;i++)
  365. {
  366. temp = readbuffer[i];
  367. temp -= 128;
  368. buffer[0][i] = ((float)temp) / 128.f;
  369. }
  370. }
  371. }
  372. /* tell the library how much we actually submitted */
  373. vorbis_analysis_wrote(&vd,i);
  374. }
  375. /* vorbis does some data preanalysis, then divvies up blocks for
  376. more involved (potentially parallel) processing. Get a single
  377. block for encoding now */
  378. while(vorbis_analysis_blockout(&vd,&vb)==1)
  379. {
  380. /* analysis */
  381. /* Do the main analysis, creating a packet */
  382. vorbis_analysis(&vb, NULL);
  383. vorbis_bitrate_addblock(&vb);
  384. while(vorbis_bitrate_flushpacket(&vd, &op))
  385. {
  386. /* weld the packet into the bitstream */
  387. ogg_stream_packetin(&os,&op);
  388. /* write out pages (if any) */
  389. while(!eos)
  390. {
  391. result = ogg_stream_pageout(&os,&og);
  392. if(result==0)
  393. break;
  394. outfile.write(og.header, og.header_len);
  395. outfile.write(og.body, og.body_len);
  396. /* this could be set above, but for illustrative purposes, I do
  397. it here (to show that vorbis does know where the stream ends) */
  398. if(ogg_page_eos(&og))
  399. eos=1;
  400. }
  401. }
  402. }
  403. }
  404. /* clean up and exit. vorbis_info_clear() must be called last */
  405. ogg_stream_clear(&os);
  406. vorbis_block_clear(&vb);
  407. vorbis_dsp_clear(&vd);
  408. vorbis_comment_clear(&vc);
  409. vorbis_info_clear(&vi);
  410. /* ogg_page and ogg_packet structs always point to storage in
  411. libvorbis. They're never freed or manipulated directly */
  412. // fprintf(stderr,"Vorbis encoding: Done.\n");
  413. llinfos << "Vorbis encoding: Done." << llendl;
  414. #endif
  415. return(LLVORBISENC_NOERR);
  416. }