00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035
00036
00037 #ifdef HAVE_LAME_LIB
00038
00039
00040
00041 #include "Exception.h"
00042 #include "Util.h"
00043 #include "LameLibEncoder.h"
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 static const char fileid[] = "$Id: LameLibEncoder.cpp,v 1.20 2006/01/25 22:47:15 darkeye Exp $";
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 bool
00066 LameLibEncoder :: open ( void )
00067 throw ( Exception )
00068 {
00069 if ( isOpen() ) {
00070 close();
00071 }
00072
00073
00074 if ( !sink->open() ) {
00075 throw Exception( __FILE__, __LINE__,
00076 "lame lib opening underlying sink error");
00077 }
00078
00079 lameGlobalFlags = lame_init();
00080
00081
00082 if ( !lameGlobalFlags || ((int)lameGlobalFlags) == -1 ) {
00083 throw Exception( __FILE__, __LINE__,
00084 "lame lib init error",
00085 (int) lameGlobalFlags);
00086 }
00087
00088 if ( 0 > lame_set_num_channels( lameGlobalFlags, getInChannel()) ) {
00089 throw Exception( __FILE__, __LINE__,
00090 "lame lib setting channels error",
00091 getInChannel() );
00092 }
00093
00094 if ( 0 > lame_set_mode( lameGlobalFlags,
00095 getOutChannel() == 1 ? MONO : JOINT_STEREO) ) {
00096 throw Exception( __FILE__, __LINE__,
00097 "lame lib setting mode error",
00098 JOINT_STEREO );
00099 }
00100
00101 reportEvent( 5, "set lame mode", lame_get_mode( lameGlobalFlags));
00102
00103 reportEvent( 5,
00104 "set lame channels",
00105 lame_get_num_channels( lameGlobalFlags));
00106
00107 if ( 0 > lame_set_in_samplerate( lameGlobalFlags, getInSampleRate()) ) {
00108 throw Exception( __FILE__, __LINE__,
00109 "lame lib setting input sample rate error",
00110 getInSampleRate() );
00111 }
00112
00113 reportEvent( 5,
00114 "set lame in sample rate",
00115 lame_get_in_samplerate( lameGlobalFlags));
00116
00117 if ( 0 > lame_set_out_samplerate( lameGlobalFlags, getOutSampleRate()) ) {
00118 throw Exception( __FILE__, __LINE__,
00119 "lame lib setting output sample rate error",
00120 getOutSampleRate() );
00121 }
00122
00123 reportEvent( 5,
00124 "set lame out sample rate",
00125 lame_get_out_samplerate( lameGlobalFlags));
00126
00127 switch ( getOutBitrateMode() ) {
00128
00129 case cbr: {
00130
00131 if ( 0 > lame_set_brate( lameGlobalFlags, getOutBitrate()) ) {
00132 throw Exception( __FILE__, __LINE__,
00133 "lame lib setting output bit rate error",
00134 getOutBitrate() );
00135 }
00136
00137 reportEvent( 5,
00138 "set lame bit rate",
00139 lame_get_brate( lameGlobalFlags));
00140
00141 double d = (1.0 - getOutQuality()) * 10.0;
00142
00143 if ( d > 9 ) {
00144 d = 9;
00145 }
00146
00147 int q = int (d);
00148
00149 if ( 0 > lame_set_quality( lameGlobalFlags, q) ) {
00150 throw Exception( __FILE__, __LINE__,
00151 "lame lib setting quality error", q);
00152 }
00153
00154 reportEvent( 5,
00155 "set lame quality",
00156 lame_get_quality( lameGlobalFlags));
00157 } break;
00158
00159 case abr:
00160
00161 if ( 0 > lame_set_VBR( lameGlobalFlags,vbr_abr)) {
00162 throw Exception( __FILE__, __LINE__,
00163 "lame lib setting abr error", vbr_abr);
00164 }
00165
00166 reportEvent( 5,
00167 "set lame abr bitrate",
00168 lame_get_VBR( lameGlobalFlags));
00169
00170 if ( 0 > lame_set_VBR_mean_bitrate_kbps( lameGlobalFlags,
00171 getOutBitrate())) {
00172 throw Exception( __FILE__, __LINE__,
00173 "lame lib setting abr mean bitrate error",
00174 getOutBitrate());
00175 }
00176
00177 reportEvent( 5,
00178 "set lame abr mean bitrate",
00179 lame_get_VBR_mean_bitrate_kbps( lameGlobalFlags));
00180 break;
00181
00182 case vbr: {
00183
00184 if ( 0 > lame_set_VBR( lameGlobalFlags, vbr_mtrh)) {
00185 throw Exception( __FILE__, __LINE__,
00186 "lame lib setting vbr error", vbr_mtrh );
00187 }
00188
00189 reportEvent( 5,
00190 "set lame vbr bitrate",
00191 lame_get_VBR( lameGlobalFlags));
00192
00193 double d = (1.0 - getOutQuality()) * 10.0;
00194
00195 if ( d > 9 ) {
00196 d = 9;
00197 }
00198
00199 int q = int (d);
00200
00201 if ( 0 > lame_set_VBR_q( lameGlobalFlags, q) ) {
00202 throw Exception( __FILE__, __LINE__,
00203 "lame lib setting vbr quality error", q);
00204 }
00205
00206 reportEvent( 5,
00207 "set lame vbr quality",
00208 lame_get_VBR_q( lameGlobalFlags));
00209 } break;
00210 }
00211
00212
00213 if ( 0 > lame_set_lowpassfreq( lameGlobalFlags, lowpass) ) {
00214 throw Exception( __FILE__, __LINE__,
00215 "lame lib setting lowpass frequency error",
00216 lowpass );
00217 }
00218
00219 reportEvent( 5,
00220 "set lame lowpass frequency",
00221 lame_get_lowpassfreq( lameGlobalFlags));
00222
00223 if ( 0 > lame_set_highpassfreq( lameGlobalFlags, highpass) ) {
00224 throw Exception( __FILE__, __LINE__,
00225 "lame lib setting highpass frequency error",
00226 lowpass );
00227 }
00228
00229 reportEvent( 5,
00230 "set lame highpass frequency",
00231 lame_get_highpassfreq( lameGlobalFlags));
00232
00233
00234
00235
00236
00237
00238 if ( 0 > lame_set_exp_nspsytune( lameGlobalFlags, 1) ) {
00239 throw Exception( __FILE__, __LINE__,
00240 "lame lib setting psycho acoustic model error");
00241 }
00242
00243 reportEvent( 5,
00244 "set lame psycho acoustic model",
00245 lame_get_exp_nspsytune( lameGlobalFlags));
00246
00247 if ( 0 > lame_set_error_protection( lameGlobalFlags, 1) ) {
00248 throw Exception( __FILE__, __LINE__,
00249 "lame lib setting error protection error",
00250 1 );
00251 }
00252
00253 reportEvent( 5,
00254 "set lame error protection",
00255 lame_get_error_protection( lameGlobalFlags));
00256
00257
00258 if ( 0 > lame_init_params( lameGlobalFlags) ) {
00259 throw Exception( __FILE__, __LINE__,
00260 "lame lib initializing params error" );
00261 }
00262
00263 if (getReportVerbosity() >= 3) {
00264 lame_print_config( lameGlobalFlags);
00265 }
00266
00267 return true;
00268 }
00269
00270
00271
00272
00273
00274 unsigned int
00275 LameLibEncoder :: write ( const void * buf,
00276 unsigned int len ) throw ( Exception )
00277 {
00278 if ( !isOpen() || len == 0 ) {
00279 return 0;
00280 }
00281
00282 unsigned int bitsPerSample = getInBitsPerSample();
00283 unsigned int inChannels = getInChannel();
00284
00285 unsigned int sampleSize = (bitsPerSample / 8) * inChannels;
00286 unsigned char * b = (unsigned char*) buf;
00287 unsigned int processed = len - (len % sampleSize);
00288 unsigned int nSamples = processed / sampleSize;
00289 short int * leftBuffer = new short int[nSamples];
00290 short int * rightBuffer = new short int[nSamples];
00291
00292 if ( bitsPerSample == 8 ) {
00293 Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels);
00294 } else if ( bitsPerSample == 16 ) {
00295 Util::conv16( b,
00296 processed,
00297 leftBuffer,
00298 rightBuffer,
00299 inChannels,
00300 isInBigEndian());
00301 } else {
00302 delete[] leftBuffer;
00303 delete[] rightBuffer;
00304 throw Exception( __FILE__, __LINE__,
00305 "unsupported number of bits per sample for the encoder",
00306 bitsPerSample );
00307 }
00308
00309
00310
00311
00312 unsigned int mp3Size = (unsigned int) (1.25 * nSamples + 7200);
00313 unsigned char * mp3Buf = new unsigned char[mp3Size];
00314 int ret;
00315
00316 ret = lame_encode_buffer( lameGlobalFlags,
00317 leftBuffer,
00318 inChannels == 2 ? rightBuffer : leftBuffer,
00319 nSamples,
00320 mp3Buf,
00321 mp3Size );
00322
00323 delete[] leftBuffer;
00324 delete[] rightBuffer;
00325
00326 if ( ret < 0 ) {
00327 reportEvent( 3, "lame encoding error", ret);
00328 delete[] mp3Buf;
00329 return 0;
00330 }
00331
00332 unsigned int written = sink->write( mp3Buf, ret);
00333 delete[] mp3Buf;
00334
00335 if ( written < (unsigned int) ret ) {
00336 reportEvent( 2,
00337 "couldn't write all from encoder to underlying sink",
00338 ret - written);
00339 }
00340
00341 return processed;
00342 }
00343
00344
00345
00346
00347
00348 void
00349 LameLibEncoder :: flush ( void )
00350 throw ( Exception )
00351 {
00352 if ( !isOpen() ) {
00353 return;
00354 }
00355
00356
00357 unsigned int mp3Size = 7200;
00358 unsigned char * mp3Buf = new unsigned char[mp3Size];
00359 int ret;
00360
00361 ret = lame_encode_flush( lameGlobalFlags, mp3Buf, mp3Size );
00362
00363 unsigned int written = sink->write( mp3Buf, ret);
00364 delete[] mp3Buf;
00365
00366
00367 if ( written < (unsigned int) ret ) {
00368 reportEvent( 2,
00369 "couldn't write all from encoder to underlying sink",
00370 ret - written);
00371 }
00372
00373 sink->flush();
00374 }
00375
00376
00377
00378
00379
00380 void
00381 LameLibEncoder :: close ( void ) throw ( Exception )
00382 {
00383 if ( isOpen() ) {
00384 flush();
00385 lame_close( lameGlobalFlags);
00386 lameGlobalFlags = 0;
00387
00388 sink->close();
00389 }
00390 }
00391
00392
00393 #endif // HAVE_LAME_LIB
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467