aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llaudio/vorbisencode.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llaudio/vorbisencode.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llaudio/vorbisencode.cpp')
-rw-r--r--linden/indra/llaudio/vorbisencode.cpp506
1 files changed, 506 insertions, 0 deletions
diff --git a/linden/indra/llaudio/vorbisencode.cpp b/linden/indra/llaudio/vorbisencode.cpp
new file mode 100644
index 0000000..6007940
--- /dev/null
+++ b/linden/indra/llaudio/vorbisencode.cpp
@@ -0,0 +1,506 @@
1/**
2 * @file vorbisencode.cpp
3 * @brief Vorbis encoding routine routine for Indra.
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <math.h>
33
34#include "vorbisencode.h"
35#include "vorbis/vorbisenc.h"
36#include "llerror.h"
37#include "llrand.h"
38#include "llmath.h"
39#include "llapr.h"
40
41//#if LL_DARWIN
42// MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions.
43#if 0
44#include "VorbisFramework.h"
45
46#define vorbis_analysis mac_vorbis_analysis
47#define vorbis_analysis_headerout mac_vorbis_analysis_headerout
48#define vorbis_analysis_init mac_vorbis_analysis_init
49#define vorbis_encode_ctl mac_vorbis_encode_ctl
50#define vorbis_encode_setup_init mac_vorbis_encode_setup_init
51#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed
52
53#define vorbis_info_init mac_vorbis_info_init
54#define vorbis_info_clear mac_vorbis_info_clear
55#define vorbis_comment_init mac_vorbis_comment_init
56#define vorbis_comment_clear mac_vorbis_comment_clear
57#define vorbis_block_init mac_vorbis_block_init
58#define vorbis_block_clear mac_vorbis_block_clear
59#define vorbis_dsp_clear mac_vorbis_dsp_clear
60#define vorbis_analysis_buffer mac_vorbis_analysis_buffer
61#define vorbis_analysis_wrote mac_vorbis_analysis_wrote
62#define vorbis_analysis_blockout mac_vorbis_analysis_blockout
63
64#define ogg_stream_packetin mac_ogg_stream_packetin
65#define ogg_stream_init mac_ogg_stream_init
66#define ogg_stream_flush mac_ogg_stream_flush
67#define ogg_stream_pageout mac_ogg_stream_pageout
68#define ogg_page_eos mac_ogg_page_eos
69#define ogg_stream_clear mac_ogg_stream_clear
70
71#endif
72
73S32 check_for_invalid_wav_formats(const char *in_fname, char *error_msg)
74{
75 U16 num_channels = 0;
76 U32 sample_rate = 0;
77 U32 bits_per_sample = 0;
78 U32 physical_file_size = 0;
79 U32 chunk_length = 0;
80 U32 raw_data_length = 0;
81 U32 bytes_per_sec = 0;
82 BOOL uncompressed_pcm = FALSE;
83
84 unsigned char wav_header[44]; /*Flawfinder: ignore*/
85
86 error_msg[0] = '\0';
87
88 apr_file_t* infp = ll_apr_file_open(in_fname,LL_APR_RB);
89 if (!infp)
90 {
91 strcpy(error_msg, "CannotUploadSoundFile"); /*Flawfinder: ignore*/
92 return(LLVORBISENC_SOURCE_OPEN_ERR);
93 }
94
95 ll_apr_file_read(infp, wav_header, 44);
96 physical_file_size = ll_apr_file_seek(infp,APR_END,0);
97
98 if (strncmp((char *)&(wav_header[0]),"RIFF",4))
99 {
100 strcpy(error_msg, "SoundFileNotRIFF"); /*Flawfinder: ignore*/
101 apr_file_close(infp);
102 return(LLVORBISENC_WAV_FORMAT_ERR);
103 }
104
105 if (strncmp((char *)&(wav_header[8]),"WAVE",4))
106 {
107 strcpy(error_msg, "SoundFileNotRIFF"); /*Flawfinder: ignore*/
108 apr_file_close(infp);
109 return(LLVORBISENC_WAV_FORMAT_ERR);
110 }
111
112 // parse the chunks
113
114 U32 file_pos = 12; // start at the first chunk (usually fmt but not always)
115
116 while ((file_pos + 8)< physical_file_size)
117 {
118 ll_apr_file_seek(infp,APR_SET,file_pos);
119 ll_apr_file_read(infp, wav_header, 44);
120
121 chunk_length = ((U32) wav_header[7] << 24)
122 + ((U32) wav_header[6] << 16)
123 + ((U32) wav_header[5] << 8)
124 + wav_header[4];
125
126// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
127
128 if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
129 {
130 if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00))
131 {
132 uncompressed_pcm = TRUE;
133 }
134 num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
135 sample_rate = ((U32) wav_header[15] << 24)
136 + ((U32) wav_header[14] << 16)
137 + ((U32) wav_header[13] << 8)
138 + wav_header[12];
139 bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
140 bytes_per_sec = ((U32) wav_header[19] << 24)
141 + ((U32) wav_header[18] << 16)
142 + ((U32) wav_header[17] << 8)
143 + wav_header[16];
144 }
145 else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
146 {
147 raw_data_length = chunk_length;
148 }
149 file_pos += (chunk_length + 8);
150 chunk_length = 0;
151 }
152
153 apr_file_close(infp);
154
155 if (!uncompressed_pcm)
156 {
157 strcpy(error_msg, "SoundFileNotPCM"); /*Flawfinder: ignore*/
158 return(LLVORBISENC_PCM_FORMAT_ERR);
159 }
160
161 if ((num_channels < 1) || (num_channels > 2))
162 {
163 strcpy(error_msg, "SoundFileInvalidChannelCount"); /*Flawfinder: ignore*/
164 return(LLVORBISENC_MULTICHANNEL_ERR);
165 }
166
167 if (sample_rate != 44100)
168 {
169 strcpy(error_msg, "SoundFileInvalidSampleRate"); /*Flawfinder: ignore*/
170 return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE);
171 }
172
173 if ((bits_per_sample != 16) && (bits_per_sample != 8))
174 {
175 strcpy(error_msg, "SoundFileInvalidWordSize"); /*Flawfinder: ignore*/
176 return(LLVORBISENC_UNSUPPORTED_WORD_SIZE);
177 }
178
179 if (!raw_data_length)
180 {
181 strcpy(error_msg, "SoundFileInvalidHeader"); /*Flawfinder: ignore*/
182 return(LLVORBISENC_CLIP_TOO_LONG);
183 }
184
185 F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec;
186
187 if (clip_length > 10.0f)
188 {
189 strcpy(error_msg, "SoundFileInvalidTooLong"); /*Flawfinder: ignore*/
190 return(LLVORBISENC_CLIP_TOO_LONG);
191 }
192
193 return(LLVORBISENC_NOERR);
194}
195
196S32 encode_vorbis_file(const char *in_fname, const char *out_fname)
197{
198 return(encode_vorbis_file_at(in_fname,out_fname, 128000));
199}
200
201S32 encode_vorbis_file_at(const char *in_fname, const char *out_fname, S32 bitrate)
202{
203#define READ_BUFFER 1024
204 unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/
205
206 ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
207 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
208 ogg_packet op; /* one raw packet of data for decode */
209
210 vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
211 vorbis_comment vc; /* struct that stores all the user comments */
212
213 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
214 vorbis_block vb; /* local working space for packet->PCM decode */
215
216 int eos=0;
217 int result;
218
219 U16 num_channels = 0;
220 U32 sample_rate = 0;
221 U32 bits_per_sample = 0;
222
223 S32 format_error = 0;
224 char error_msg[MAX_STRING]; /*Flawfinder: ignore*/
225 if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg)))
226 {
227 llwarns << error_msg << ": " << in_fname << llendl;
228 return(format_error);
229 }
230
231#if 1
232 unsigned char wav_header[44]; /*Flawfinder: ignore*/
233
234 S32 data_left = 0;
235
236 apr_file_t* infp = ll_apr_file_open(in_fname,LL_APR_RB);
237 if (!infp)
238 {
239 llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
240 << llendl;
241 return(LLVORBISENC_SOURCE_OPEN_ERR);
242 }
243 apr_file_t* outfp = ll_apr_file_open(out_fname,LL_APR_WPB);
244 if (!outfp)
245 {
246 llwarns << "Couldn't open upload sound file for reading: " << in_fname
247 << llendl;
248 apr_file_close (infp);
249 return(LLVORBISENC_DEST_OPEN_ERR);
250 }
251
252 // parse the chunks
253 U32 chunk_length = 0;
254 U32 file_pos = 12; // start at the first chunk (usually fmt but not always)
255
256 while (apr_file_eof(infp) != APR_EOF)
257 {
258 ll_apr_file_seek(infp,APR_SET,file_pos);
259 ll_apr_file_read(infp, wav_header, 44);
260
261 chunk_length = ((U32) wav_header[7] << 24)
262 + ((U32) wav_header[6] << 16)
263 + ((U32) wav_header[5] << 8)
264 + wav_header[4];
265
266// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl;
267
268 if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
269 {
270 num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
271 sample_rate = ((U32) wav_header[15] << 24)
272 + ((U32) wav_header[14] << 16)
273 + ((U32) wav_header[13] << 8)
274 + wav_header[12];
275 bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
276 }
277 else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
278 {
279 ll_apr_file_seek(infp,APR_SET,file_pos+8);
280 // leave the file pointer at the beginning of the data chunk data
281 data_left = chunk_length;
282 break;
283 }
284 file_pos += (chunk_length + 8);
285 chunk_length = 0;
286 }
287
288// apr_file_close(infp);
289
290 /********** Encode setup ************/
291
292 /* choose an encoding mode */
293 /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
294 vorbis_info_init(&vi);
295
296 // always encode to mono
297// vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1);
298// if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1))
299
300// F32 quality = 0;
301// quality = (bitrate==128000 ? 0.4f : 0.1);
302
303 if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1))
304// if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality))
305// if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) ||
306// vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) ||
307// vorbis_encode_setup_init(&vi))
308 {
309// llwarns << "unable to initialize vorbis codec at quality " << quality << llendl;
310 llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl;
311 return(LLVORBISENC_DEST_OPEN_ERR);
312 }
313
314 /* add a comment */
315 vorbis_comment_init(&vc);
316// vorbis_comment_add(&vc,"Linden");
317
318 /* set up the analysis state and auxiliary encoding storage */
319 vorbis_analysis_init(&vd,&vi);
320 vorbis_block_init(&vd,&vb);
321
322 /* set up our packet->stream encoder */
323 /* pick a random serial number; that way we can more likely build
324 chained streams just by concatenation */
325 ogg_stream_init(&os,(int)frand(0xFFFFFF));
326
327 /* Vorbis streams begin with three headers; the initial header (with
328 most of the codec setup parameters) which is mandated by the Ogg
329 bitstream spec. The second header holds any comment fields. The
330 third header holds the bitstream codebook. We merely need to
331 make the headers, then pass them to libvorbis one at a time;
332 libvorbis handles the additional Ogg bitstream constraints */
333
334 {
335 ogg_packet header;
336 ogg_packet header_comm;
337 ogg_packet header_code;
338
339 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
340 ogg_stream_packetin(&os,&header); /* automatically placed in its own
341 page */
342 ogg_stream_packetin(&os,&header_comm);
343 ogg_stream_packetin(&os,&header_code);
344
345 /* We don't have to write out here, but doing so makes streaming
346 * much easier, so we do, flushing ALL pages. This ensures the actual
347 * audio data will start on a new page
348 */
349 while(!eos){
350 int result=ogg_stream_flush(&os,&og);
351 if(result==0)break;
352 ll_apr_file_write(outfp, og.header, og.header_len);
353 ll_apr_file_write(outfp, og.body, og.body_len);
354 }
355
356 }
357
358
359 while(!eos)
360 {
361 long bytes_per_sample = bits_per_sample/8;
362
363 long bytes=(long)ll_apr_file_read(infp, readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */
364
365 if (bytes==0)
366 {
367 /* end of file. this can be done implicitly in the mainline,
368 but it's easier to see here in non-clever fashion.
369 Tell the library we're at end of stream so that it can handle
370 the last frame and mark end of stream in the output properly */
371
372 vorbis_analysis_wrote(&vd,0);
373// eos = 1;
374
375 }
376 else
377 {
378 long i;
379 long samples;
380 int temp;
381
382 data_left -= bytes;
383 /* data to encode */
384
385 /* expose the buffer to submit data */
386 float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER);
387
388 i = 0;
389 samples = bytes / (num_channels * bytes_per_sample);
390
391 if (num_channels == 2)
392 {
393 if (bytes_per_sample == 2)
394 {
395 /* uninterleave samples */
396 for(i=0; i<samples ;i++)
397 {
398 temp = ((signed char *)readbuffer)[i*4+1]; /*Flawfinder: ignore*/
399 temp += ((signed char *)readbuffer)[i*4+3]; /*Flawfinder: ignore*/
400 temp <<= 8;
401 temp += readbuffer[i*4];
402 temp += readbuffer[i*4+2];
403
404 buffer[0][i] = ((float)temp) / 65536.f;
405 }
406 }
407 else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard")
408 {
409 /* uninterleave samples */
410 for(i=0; i<samples ;i++)
411 {
412 temp = readbuffer[i*2+0];
413 temp += readbuffer[i*2+1];
414 temp -= 256;
415 buffer[0][i] = ((float)temp) / 256.f;
416 }
417 }
418 }
419 else if (num_channels == 1)
420 {
421 if (bytes_per_sample == 2)
422 {
423 for(i=0; i < samples ;i++)
424 {
425 temp = ((signed char*)readbuffer)[i*2+1];
426 temp <<= 8;
427 temp += readbuffer[i*2];
428 buffer[0][i] = ((float)temp) / 32768.f;
429 }
430 }
431 else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard")
432 {
433 for(i=0; i < samples ;i++)
434 {
435 temp = readbuffer[i];
436 temp -= 128;
437 buffer[0][i] = ((float)temp) / 128.f;
438 }
439 }
440 }
441
442 /* tell the library how much we actually submitted */
443 vorbis_analysis_wrote(&vd,i);
444 }
445
446 /* vorbis does some data preanalysis, then divvies up blocks for
447 more involved (potentially parallel) processing. Get a single
448 block for encoding now */
449 while(vorbis_analysis_blockout(&vd,&vb)==1)
450 {
451
452 /* analysis */
453 /* Do the main analysis, creating a packet */
454 vorbis_analysis(&vb, NULL);
455 vorbis_bitrate_addblock(&vb);
456
457 while(vorbis_bitrate_flushpacket(&vd, &op))
458 {
459
460 /* weld the packet into the bitstream */
461 ogg_stream_packetin(&os,&op);
462
463 /* write out pages (if any) */
464 while(!eos)
465 {
466 result = ogg_stream_pageout(&os,&og);
467
468 if(result==0)
469 break;
470
471 ll_apr_file_write(outfp, og.header, og.header_len);
472 ll_apr_file_write(outfp, og.body, og.body_len);
473
474 /* this could be set above, but for illustrative purposes, I do
475 it here (to show that vorbis does know where the stream ends) */
476
477 if(ogg_page_eos(&og))
478 eos=1;
479
480 }
481 }
482 }
483 }
484
485
486
487 /* clean up and exit. vorbis_info_clear() must be called last */
488
489 ogg_stream_clear(&os);
490 vorbis_block_clear(&vb);
491 vorbis_dsp_clear(&vd);
492 vorbis_comment_clear(&vc);
493 vorbis_info_clear(&vi);
494
495 /* ogg_page and ogg_packet structs always point to storage in
496 libvorbis. They're never freed or manipulated directly */
497
498// fprintf(stderr,"Vorbis encoding: Done.\n");
499 llinfos << "Vorbis encoding: Done." << llendl;
500 apr_file_close(outfp);
501 apr_file_close(infp);
502
503#endif
504 return(LLVORBISENC_NOERR);
505
506}