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_VORBIS_LIB
00038
00039
00040 #include "Exception.h"
00041 #include "Util.h"
00042 #include "VorbisLibEncoder.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 static const char fileid[] = "$Id: VorbisLibEncoder.cpp,v 1.22 2005/04/16 21:57:34 darkeye Exp $";
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 void
00065 VorbisLibEncoder :: init ( CastSink * sink,
00066 unsigned int outMaxBitrate )
00067 throw ( Exception )
00068 {
00069 this->sink = sink;
00070 this->outMaxBitrate = outMaxBitrate;
00071
00072 if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
00073 throw Exception( __FILE__, __LINE__,
00074 "specified bits per sample not supported",
00075 getInBitsPerSample() );
00076 }
00077
00078 if ( getInChannel() != 1 && getInChannel() != 2 ) {
00079 throw Exception( __FILE__, __LINE__,
00080 "unsupported number of channels for the encoder",
00081 getInChannel() );
00082 }
00083
00084 if ( getOutSampleRate() == getInSampleRate() ) {
00085 resampleRatio = 1;
00086 converter = 0;
00087 } else {
00088 resampleRatio = ( (double) getOutSampleRate() /
00089 (double) getInSampleRate() );
00090
00091
00092
00093
00094
00095 bool useLinear = true;
00096 double inverse = 1 / resampleRatio;
00097 int integer = (int) inverse;
00098
00099
00100 if( integer == inverse ) {
00101 while( useLinear && integer ) {
00102
00103 if( integer & 1 && integer != 1 ) {
00104
00105 useLinear = false;
00106 } else {
00107
00108 integer >>= 1;
00109 }
00110 }
00111 } else {
00112 useLinear = false;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122 converter = new aflibConverter( true, useLinear, false);
00123 }
00124
00125 encoderOpen = false;
00126 }
00127
00128
00129
00130
00131
00132 bool
00133 VorbisLibEncoder :: open ( void )
00134 throw ( Exception )
00135 {
00136 int ret;
00137
00138 if ( isOpen() ) {
00139 close();
00140 }
00141
00142
00143 if ( !sink->open() ) {
00144 throw Exception( __FILE__, __LINE__,
00145 "vorbis lib opening underlying sink error");
00146 }
00147
00148 vorbis_info_init( &vorbisInfo);
00149
00150 switch ( getOutBitrateMode() ) {
00151
00152 case cbr: {
00153 int maxBitrate = getOutMaxBitrate() * 1000;
00154 if ( !maxBitrate ) {
00155 maxBitrate = -1;
00156 }
00157 if ( (ret = vorbis_encode_init( &vorbisInfo,
00158 getOutChannel(),
00159 getOutSampleRate(),
00160 maxBitrate,
00161 getOutBitrate() * 1000,
00162 -1)) ) {
00163 throw Exception( __FILE__, __LINE__,
00164 "vorbis encode init error", ret);
00165 }
00166 } break;
00167
00168 case abr:
00169
00170 ret = vorbis_encode_setup_managed( &vorbisInfo,
00171 getOutChannel(),
00172 getOutSampleRate(),
00173 -1,
00174 getOutBitrate() * 1000,
00175 -1 )
00176 || vorbis_encode_ctl( &vorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL)
00177 || vorbis_encode_setup_init( &vorbisInfo);
00178 if ( ret ) {
00179 throw Exception( __FILE__, __LINE__,
00180 "vorbis encode init error", ret);
00181 }
00182 break;
00183
00184 case vbr:
00185 if ( (ret = vorbis_encode_init_vbr( &vorbisInfo,
00186 getOutChannel(),
00187 getOutSampleRate(),
00188 getOutQuality() )) ) {
00189 throw Exception( __FILE__, __LINE__,
00190 "vorbis encode init error", ret);
00191 }
00192 break;
00193 }
00194
00195 if ( (ret = vorbis_analysis_init( &vorbisDspState, &vorbisInfo)) ) {
00196 throw Exception( __FILE__, __LINE__, "vorbis analysis init error", ret);
00197 }
00198
00199 if ( (ret = vorbis_block_init( &vorbisDspState, &vorbisBlock)) ) {
00200 throw Exception( __FILE__, __LINE__, "vorbis block init error", ret);
00201 }
00202
00203 if ( (ret = ogg_stream_init( &oggStreamState, 0)) ) {
00204 throw Exception( __FILE__, __LINE__, "ogg stream init error", ret);
00205 }
00206
00207
00208 vorbis_comment_init( &vorbisComment);
00209
00210
00211 if ( sink->getName() ) {
00212 vorbis_comment_add_tag(&vorbisComment, "TITLE", (char*)sink->getName());
00213 }
00214
00215
00216 ogg_packet header;
00217 ogg_packet commentHeader;
00218 ogg_packet codeHeader;
00219
00220 if ( (ret = vorbis_analysis_headerout( &vorbisDspState,
00221 &vorbisComment,
00222 &header,
00223 &commentHeader,
00224 &codeHeader )) ) {
00225 throw Exception( __FILE__, __LINE__, "vorbis header init error", ret);
00226 }
00227
00228 ogg_stream_packetin( &oggStreamState, &header);
00229 ogg_stream_packetin( &oggStreamState, &commentHeader);
00230 ogg_stream_packetin( &oggStreamState, &codeHeader);
00231
00232 ogg_page oggPage;
00233 while ( ogg_stream_flush( &oggStreamState, &oggPage) ) {
00234 sink->write( oggPage.header, oggPage.header_len);
00235 sink->write( oggPage.body, oggPage.body_len);
00236 }
00237
00238 vorbis_comment_clear( &vorbisComment );
00239
00240
00241 if ( converter ) {
00242 converter->initialize( resampleRatio, getInChannel());
00243 }
00244
00245 encoderOpen = true;
00246
00247 return true;
00248 }
00249
00250
00251
00252
00253
00254 unsigned int
00255 VorbisLibEncoder :: write ( const void * buf,
00256 unsigned int len ) throw ( Exception )
00257 {
00258 if ( !isOpen() || len == 0 ) {
00259 return 0;
00260 }
00261
00262 unsigned int channels = getInChannel();
00263 unsigned int bitsPerSample = getInBitsPerSample();
00264 unsigned int sampleSize = (bitsPerSample / 8) * channels;
00265
00266 unsigned int i;
00267
00268 if ( getInChannel() == 2 && getOutChannel() == 1 ) {
00269 for ( i = 0; i < len/sampleSize; i++) {
00270 if ( bitsPerSample == 8 ) {
00271 char * buf8 = (char *) buf;
00272 unsigned int ix = sampleSize * i;
00273 buf8[i] = (buf8[ix] + buf8[++ix]) / 2;
00274 }
00275 if ( bitsPerSample == 16 ) {
00276 short * buf16 = (short *) buf;
00277 unsigned int ix = (bitsPerSample >> 3) * i;
00278 buf16[i] = (buf16[ix] + buf16[++ix]) / 2;
00279 }
00280 }
00281 len >>= 1;
00282 channels = 1;
00283 }
00284
00285 sampleSize = (bitsPerSample / 8) * channels;
00286 unsigned char * b = (unsigned char*) buf;
00287 unsigned int processed = len - (len % sampleSize);
00288 unsigned int nSamples = processed / sampleSize;
00289 float ** vorbisBuffer;
00290
00291
00292
00293
00294 unsigned int totalSamples = nSamples * channels;
00295 short int * shortBuffer = new short int[totalSamples];
00296
00297
00298 Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
00299
00300 if ( converter ) {
00301
00302 int inCount = nSamples;
00303 int outCount = (int) (inCount * resampleRatio);
00304 short int * resampledBuffer = new short int[outCount * channels];
00305 int converted;
00306
00307 converted = converter->resample( inCount,
00308 outCount,
00309 shortBuffer,
00310 resampledBuffer );
00311
00312 vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState,
00313 converted);
00314 Util::conv( resampledBuffer,
00315 converted * channels,
00316 vorbisBuffer,
00317 channels);
00318 delete[] resampledBuffer;
00319
00320 vorbis_analysis_wrote( &vorbisDspState, converted);
00321
00322 } else {
00323
00324 vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState, nSamples);
00325 Util::conv( shortBuffer, totalSamples, vorbisBuffer, channels);
00326 vorbis_analysis_wrote( &vorbisDspState, nSamples);
00327 }
00328
00329 delete[] shortBuffer;
00330 vorbisBlocksOut();
00331
00332 return processed;
00333 }
00334
00335
00336
00337
00338
00339 void
00340 VorbisLibEncoder :: flush ( void )
00341 throw ( Exception )
00342 {
00343 if ( !isOpen() ) {
00344 return;
00345 }
00346
00347 vorbis_analysis_wrote( &vorbisDspState, 0);
00348 vorbisBlocksOut();
00349 sink->flush();
00350 }
00351
00352
00353
00354
00355
00356 void
00357 VorbisLibEncoder :: vorbisBlocksOut ( void ) throw ( Exception )
00358 {
00359 while ( 1 == vorbis_analysis_blockout( &vorbisDspState, &vorbisBlock) ) {
00360 ogg_packet oggPacket;
00361 ogg_page oggPage;
00362
00363 vorbis_analysis( &vorbisBlock, &oggPacket);
00364 vorbis_bitrate_addblock( &vorbisBlock);
00365
00366 while ( vorbis_bitrate_flushpacket( &vorbisDspState, &oggPacket) ) {
00367
00368 ogg_stream_packetin( &oggStreamState, &oggPacket);
00369
00370 while ( ogg_stream_pageout( &oggStreamState, &oggPage) ) {
00371 int written;
00372
00373 written = sink->write( oggPage.header, oggPage.header_len);
00374 written += sink->write( oggPage.body, oggPage.body_len);
00375
00376 if ( written < oggPage.header_len + oggPage.body_len ) {
00377
00378 reportEvent( 2,
00379 "couldn't write full vorbis data to underlying sink",
00380 oggPage.header_len + oggPage.body_len - written);
00381 }
00382 }
00383 }
00384 }
00385 }
00386
00387
00388
00389
00390
00391 void
00392 VorbisLibEncoder :: close ( void ) throw ( Exception )
00393 {
00394 if ( isOpen() ) {
00395 flush();
00396
00397 ogg_stream_clear( &oggStreamState);
00398 vorbis_block_clear( &vorbisBlock);
00399 vorbis_dsp_clear( &vorbisDspState);
00400 vorbis_comment_clear( &vorbisComment);
00401 vorbis_info_clear( &vorbisInfo);
00402
00403 encoderOpen = false;
00404
00405 sink->close();
00406 }
00407 }
00408
00409
00410 #endif // HAVE_VORBIS_LIB
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
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494