00001
00032 #include "linden_common.h"
00033
00034 #include "vorbisencode.h"
00035 #include "vorbis/vorbisenc.h"
00036 #include "llerror.h"
00037 #include "llrand.h"
00038 #include "llmath.h"
00039 #include "llapr.h"
00040
00041
00042
00043 #if 0
00044 #include "VorbisFramework.h"
00045
00046 #define vorbis_analysis mac_vorbis_analysis
00047 #define vorbis_analysis_headerout mac_vorbis_analysis_headerout
00048 #define vorbis_analysis_init mac_vorbis_analysis_init
00049 #define vorbis_encode_ctl mac_vorbis_encode_ctl
00050 #define vorbis_encode_setup_init mac_vorbis_encode_setup_init
00051 #define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed
00052
00053 #define vorbis_info_init mac_vorbis_info_init
00054 #define vorbis_info_clear mac_vorbis_info_clear
00055 #define vorbis_comment_init mac_vorbis_comment_init
00056 #define vorbis_comment_clear mac_vorbis_comment_clear
00057 #define vorbis_block_init mac_vorbis_block_init
00058 #define vorbis_block_clear mac_vorbis_block_clear
00059 #define vorbis_dsp_clear mac_vorbis_dsp_clear
00060 #define vorbis_analysis_buffer mac_vorbis_analysis_buffer
00061 #define vorbis_analysis_wrote mac_vorbis_analysis_wrote
00062 #define vorbis_analysis_blockout mac_vorbis_analysis_blockout
00063
00064 #define ogg_stream_packetin mac_ogg_stream_packetin
00065 #define ogg_stream_init mac_ogg_stream_init
00066 #define ogg_stream_flush mac_ogg_stream_flush
00067 #define ogg_stream_pageout mac_ogg_stream_pageout
00068 #define ogg_page_eos mac_ogg_page_eos
00069 #define ogg_stream_clear mac_ogg_stream_clear
00070
00071 #endif
00072
00073 S32 check_for_invalid_wav_formats(const char *in_fname, char *error_msg)
00074 {
00075 U16 num_channels = 0;
00076 U32 sample_rate = 0;
00077 U32 bits_per_sample = 0;
00078 U32 physical_file_size = 0;
00079 U32 chunk_length = 0;
00080 U32 raw_data_length = 0;
00081 U32 bytes_per_sec = 0;
00082 BOOL uncompressed_pcm = FALSE;
00083
00084 unsigned char wav_header[44];
00085
00086 error_msg[0] = '\0';
00087
00088 apr_file_t* infp = ll_apr_file_open(in_fname,LL_APR_RB);
00089 if (!infp)
00090 {
00091 strcpy(error_msg, "CannotUploadSoundFile");
00092 return(LLVORBISENC_SOURCE_OPEN_ERR);
00093 }
00094
00095 ll_apr_file_read(infp, wav_header, 44);
00096 physical_file_size = ll_apr_file_seek(infp,APR_END,0);
00097
00098 if (strncmp((char *)&(wav_header[0]),"RIFF",4))
00099 {
00100 strcpy(error_msg, "SoundFileNotRIFF");
00101 apr_file_close(infp);
00102 return(LLVORBISENC_WAV_FORMAT_ERR);
00103 }
00104
00105 if (strncmp((char *)&(wav_header[8]),"WAVE",4))
00106 {
00107 strcpy(error_msg, "SoundFileNotRIFF");
00108 apr_file_close(infp);
00109 return(LLVORBISENC_WAV_FORMAT_ERR);
00110 }
00111
00112
00113
00114 U32 file_pos = 12;
00115
00116 while ((file_pos + 8)< physical_file_size)
00117 {
00118 ll_apr_file_seek(infp,APR_SET,file_pos);
00119 ll_apr_file_read(infp, wav_header, 44);
00120
00121 chunk_length = ((U32) wav_header[7] << 24)
00122 + ((U32) wav_header[6] << 16)
00123 + ((U32) wav_header[5] << 8)
00124 + wav_header[4];
00125
00126
00127
00128 if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
00129 {
00130 if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00))
00131 {
00132 uncompressed_pcm = TRUE;
00133 }
00134 num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
00135 sample_rate = ((U32) wav_header[15] << 24)
00136 + ((U32) wav_header[14] << 16)
00137 + ((U32) wav_header[13] << 8)
00138 + wav_header[12];
00139 bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
00140 bytes_per_sec = ((U32) wav_header[19] << 24)
00141 + ((U32) wav_header[18] << 16)
00142 + ((U32) wav_header[17] << 8)
00143 + wav_header[16];
00144 }
00145 else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
00146 {
00147 raw_data_length = chunk_length;
00148 }
00149 file_pos += (chunk_length + 8);
00150 chunk_length = 0;
00151 }
00152
00153 apr_file_close(infp);
00154
00155 if (!uncompressed_pcm)
00156 {
00157 strcpy(error_msg, "SoundFileNotPCM");
00158 return(LLVORBISENC_PCM_FORMAT_ERR);
00159 }
00160
00161 if ((num_channels < 1) || (num_channels > 2))
00162 {
00163 strcpy(error_msg, "SoundFileInvalidChannelCount");
00164 return(LLVORBISENC_MULTICHANNEL_ERR);
00165 }
00166
00167 if (sample_rate != 44100)
00168 {
00169 strcpy(error_msg, "SoundFileInvalidSampleRate");
00170 return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE);
00171 }
00172
00173 if ((bits_per_sample != 16) && (bits_per_sample != 8))
00174 {
00175 strcpy(error_msg, "SoundFileInvalidWordSize");
00176 return(LLVORBISENC_UNSUPPORTED_WORD_SIZE);
00177 }
00178
00179 if (!raw_data_length)
00180 {
00181 strcpy(error_msg, "SoundFileInvalidHeader");
00182 return(LLVORBISENC_CLIP_TOO_LONG);
00183 }
00184
00185 F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec;
00186
00187 if (clip_length > 10.0f)
00188 {
00189 strcpy(error_msg, "SoundFileInvalidTooLong");
00190 return(LLVORBISENC_CLIP_TOO_LONG);
00191 }
00192
00193 return(LLVORBISENC_NOERR);
00194 }
00195
00196 S32 encode_vorbis_file(const char *in_fname, const char *out_fname)
00197 {
00198 #define READ_BUFFER 1024
00199 unsigned char readbuffer[READ_BUFFER*4+44];
00200
00201 ogg_stream_state os;
00202 ogg_page og;
00203 ogg_packet op;
00204
00205 vorbis_info vi;
00206 vorbis_comment vc;
00207
00208 vorbis_dsp_state vd;
00209 vorbis_block vb;
00210
00211 int eos=0;
00212 int result;
00213
00214 U16 num_channels = 0;
00215 U32 sample_rate = 0;
00216 U32 bits_per_sample = 0;
00217
00218 S32 format_error = 0;
00219 char error_msg[MAX_STRING];
00220 if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg)))
00221 {
00222 llwarns << error_msg << ": " << in_fname << llendl;
00223 return(format_error);
00224 }
00225
00226 #if 1
00227 unsigned char wav_header[44];
00228
00229 S32 data_left = 0;
00230
00231 apr_file_t* infp = ll_apr_file_open(in_fname,LL_APR_RB);
00232 if (!infp)
00233 {
00234 llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
00235 << llendl;
00236 return(LLVORBISENC_SOURCE_OPEN_ERR);
00237 }
00238 apr_file_t* outfp = ll_apr_file_open(out_fname,LL_APR_WPB);
00239 if (!outfp)
00240 {
00241 llwarns << "Couldn't open upload sound file for reading: " << in_fname
00242 << llendl;
00243 apr_file_close (infp);
00244 return(LLVORBISENC_DEST_OPEN_ERR);
00245 }
00246
00247
00248 U32 chunk_length = 0;
00249 U32 file_pos = 12;
00250
00251 while (apr_file_eof(infp) != APR_EOF)
00252 {
00253 ll_apr_file_seek(infp,APR_SET,file_pos);
00254 ll_apr_file_read(infp, wav_header, 44);
00255
00256 chunk_length = ((U32) wav_header[7] << 24)
00257 + ((U32) wav_header[6] << 16)
00258 + ((U32) wav_header[5] << 8)
00259 + wav_header[4];
00260
00261
00262
00263 if (!(strncmp((char *)&(wav_header[0]),"fmt ",4)))
00264 {
00265 num_channels = ((U16) wav_header[11] << 8) + wav_header[10];
00266 sample_rate = ((U32) wav_header[15] << 24)
00267 + ((U32) wav_header[14] << 16)
00268 + ((U32) wav_header[13] << 8)
00269 + wav_header[12];
00270 bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22];
00271 }
00272 else if (!(strncmp((char *)&(wav_header[0]),"data",4)))
00273 {
00274 ll_apr_file_seek(infp,APR_SET,file_pos+8);
00275
00276 data_left = chunk_length;
00277 break;
00278 }
00279 file_pos += (chunk_length + 8);
00280 chunk_length = 0;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289 vorbis_info_init(&vi);
00290
00291
00292
00293
00294
00295
00296 F32 quality = 0.05f;
00297
00298
00299
00300 if (vorbis_encode_init_vbr(&vi, 1 ,sample_rate, quality))
00301
00302
00303
00304 {
00305 llwarns << "unable to initialize vorbis codec at quality " << quality << llendl;
00306
00307 return(LLVORBISENC_DEST_OPEN_ERR);
00308 }
00309
00310
00311 vorbis_comment_init(&vc);
00312
00313
00314
00315 vorbis_analysis_init(&vd,&vi);
00316 vorbis_block_init(&vd,&vb);
00317
00318
00319
00320
00321 ogg_stream_init(&os, ll_rand());
00322
00323
00324
00325
00326
00327
00328
00329
00330 {
00331 ogg_packet header;
00332 ogg_packet header_comm;
00333 ogg_packet header_code;
00334
00335 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
00336 ogg_stream_packetin(&os,&header);
00337
00338 ogg_stream_packetin(&os,&header_comm);
00339 ogg_stream_packetin(&os,&header_code);
00340
00341
00342
00343
00344
00345 while(!eos){
00346 int result=ogg_stream_flush(&os,&og);
00347 if(result==0)break;
00348 ll_apr_file_write(outfp, og.header, og.header_len);
00349 ll_apr_file_write(outfp, og.body, og.body_len);
00350 }
00351
00352 }
00353
00354
00355 while(!eos)
00356 {
00357 long bytes_per_sample = bits_per_sample/8;
00358
00359 long bytes=(long)ll_apr_file_read(infp, readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left));
00360
00361 if (bytes==0)
00362 {
00363
00364
00365
00366
00367
00368 vorbis_analysis_wrote(&vd,0);
00369
00370
00371 }
00372 else
00373 {
00374 long i;
00375 long samples;
00376 int temp;
00377
00378 data_left -= bytes;
00379
00380
00381
00382 float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER);
00383
00384 i = 0;
00385 samples = bytes / (num_channels * bytes_per_sample);
00386
00387 if (num_channels == 2)
00388 {
00389 if (bytes_per_sample == 2)
00390 {
00391
00392 for(i=0; i<samples ;i++)
00393 {
00394 temp = ((signed char *)readbuffer)[i*4+1];
00395 temp += ((signed char *)readbuffer)[i*4+3];
00396 temp <<= 8;
00397 temp += readbuffer[i*4];
00398 temp += readbuffer[i*4+2];
00399
00400 buffer[0][i] = ((float)temp) / 65536.f;
00401 }
00402 }
00403 else
00404 {
00405
00406 for(i=0; i<samples ;i++)
00407 {
00408 temp = readbuffer[i*2+0];
00409 temp += readbuffer[i*2+1];
00410 temp -= 256;
00411 buffer[0][i] = ((float)temp) / 256.f;
00412 }
00413 }
00414 }
00415 else if (num_channels == 1)
00416 {
00417 if (bytes_per_sample == 2)
00418 {
00419 for(i=0; i < samples ;i++)
00420 {
00421 temp = ((signed char*)readbuffer)[i*2+1];
00422 temp <<= 8;
00423 temp += readbuffer[i*2];
00424 buffer[0][i] = ((float)temp) / 32768.f;
00425 }
00426 }
00427 else
00428 {
00429 for(i=0; i < samples ;i++)
00430 {
00431 temp = readbuffer[i];
00432 temp -= 128;
00433 buffer[0][i] = ((float)temp) / 128.f;
00434 }
00435 }
00436 }
00437
00438
00439 vorbis_analysis_wrote(&vd,i);
00440 }
00441
00442
00443
00444
00445 while(vorbis_analysis_blockout(&vd,&vb)==1)
00446 {
00447
00448
00449
00450 vorbis_analysis(&vb, NULL);
00451 vorbis_bitrate_addblock(&vb);
00452
00453 while(vorbis_bitrate_flushpacket(&vd, &op))
00454 {
00455
00456
00457 ogg_stream_packetin(&os,&op);
00458
00459
00460 while(!eos)
00461 {
00462 result = ogg_stream_pageout(&os,&og);
00463
00464 if(result==0)
00465 break;
00466
00467 ll_apr_file_write(outfp, og.header, og.header_len);
00468 ll_apr_file_write(outfp, og.body, og.body_len);
00469
00470
00471
00472
00473 if(ogg_page_eos(&og))
00474 eos=1;
00475
00476 }
00477 }
00478 }
00479 }
00480
00481
00482
00483
00484
00485 ogg_stream_clear(&os);
00486 vorbis_block_clear(&vb);
00487 vorbis_dsp_clear(&vd);
00488 vorbis_comment_clear(&vc);
00489 vorbis_info_clear(&vi);
00490
00491
00492
00493
00494
00495 llinfos << "Vorbis encoding: Done." << llendl;
00496 apr_file_close(outfp);
00497 apr_file_close(infp);
00498
00499 #endif
00500 return(LLVORBISENC_NOERR);
00501
00502 }