diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llaudio/vorbisencode.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 506 |
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 | |||
73 | S32 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 | |||
196 | S32 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 | |||
201 | S32 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 | } | ||