Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

LameLibEncoder.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : LameLibEncoder.cpp
00008    Version  : $Revision: 1.20 $
00009    Author   : $Author: darkeye $
00010    Location : $Source: /cvsroot/darkice/darkice/src/LameLibEncoder.cpp,v $
00011    
00012    Copyright notice:
00013 
00014     This program is free software; you can redistribute it and/or
00015     modify it under the terms of the GNU General Public License  
00016     as published by the Free Software Foundation; either version 2
00017     of the License, or (at your option) any later version.
00018    
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00022     GNU General Public License for more details.
00023    
00024     You should have received a copy of the GNU General Public License
00025     along with this program; if not, write to the Free Software
00026     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ------------------------------------------------------------------------------*/
00029 
00030 /* ============================================================ include files */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 // compile the whole file only if lame support configured in
00037 #ifdef HAVE_LAME_LIB
00038 
00039 
00040 
00041 #include "Exception.h"
00042 #include "Util.h"
00043 #include "LameLibEncoder.h"
00044 
00045 
00046 /* ===================================================  local data structures */
00047 
00048 
00049 /* ================================================  local constants & macros */
00050 
00051 /*------------------------------------------------------------------------------
00052  *  File identity
00053  *----------------------------------------------------------------------------*/
00054 static const char fileid[] = "$Id: LameLibEncoder.cpp,v 1.20 2006/01/25 22:47:15 darkeye Exp $";
00055 
00056 
00057 /* ===============================================  local function prototypes */
00058 
00059 
00060 /* =============================================================  module code */
00061 
00062 /*------------------------------------------------------------------------------
00063  *  Open an encoding session
00064  *----------------------------------------------------------------------------*/
00065 bool
00066 LameLibEncoder :: open ( void )
00067                                                             throw ( Exception )
00068 {
00069     if ( isOpen() ) {
00070         close();
00071     }
00072 
00073     // open the underlying sink
00074     if ( !sink->open() ) {
00075         throw Exception( __FILE__, __LINE__,
00076                          "lame lib opening underlying sink error");
00077     }
00078  
00079     lameGlobalFlags = lame_init();
00080 
00081     // ugly lame returns -1 in a pointer on allocation errors
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     // not configurable lame settings
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     // let lame init its own params based on our settings
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  *  Write data to the encoder
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     // data chunk size estimate according to lame documentation
00310     // NOTE: mp3Size is calculated based on the number of input channels
00311     //       which may be bigger than need, as output channels can be less
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     // just let go data that could not be written
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  *  Flush the data from the encoder
00347  *----------------------------------------------------------------------------*/
00348 void
00349 LameLibEncoder :: flush ( void )
00350                                                             throw ( Exception )
00351 {
00352     if ( !isOpen() ) {
00353         return;
00354     }
00355 
00356     // data chunk size estimate according to lame documentation
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     // just let go data that could not be written
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  *  Close the encoding session
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   $Source: /cvsroot/darkice/darkice/src/LameLibEncoder.cpp,v $
00399 
00400   $Log: LameLibEncoder.cpp,v $
00401   Revision 1.20  2006/01/25 22:47:15  darkeye
00402   added mpeg2 support, thanks to Nicholas J Humfrey
00403 
00404   Revision 1.19  2005/04/13 19:04:55  jbebel
00405   Distribute lame qualities better, and prevent values greater than 9 which are invalid.
00406 
00407   Revision 1.18  2002/10/19 13:31:46  darkeye
00408   some cleanup with the open() / close() functions
00409 
00410   Revision 1.17  2002/10/19 12:22:10  darkeye
00411   return 0 immediately for write() if supplied length is 0
00412 
00413   Revision 1.16  2002/08/04 10:26:06  darkeye
00414   added additional error checking to make sure that outChannel < inChannel
00415 
00416   Revision 1.15  2002/08/03 12:41:18  darkeye
00417   added possibility to stream in mono when recording in stereo
00418 
00419   Revision 1.14  2002/07/28 00:11:58  darkeye
00420   bugfix for the previous fix :)
00421 
00422   Revision 1.13  2002/07/28 00:08:37  darkeye
00423   bugfix: mp3Buf was deleted too early
00424 
00425   Revision 1.12  2002/05/28 12:35:41  darkeye
00426   code cleanup: compiles under gcc-c++ 3.1, using -pedantic option
00427 
00428   Revision 1.11  2002/04/13 11:26:00  darkeye
00429   added cbr, abr and vbr setting feature with encoding quality
00430 
00431   Revision 1.10  2002/03/28 16:38:37  darkeye
00432   moved functions conv8() and conv16() to class Util
00433 
00434   Revision 1.9  2001/10/20 10:56:45  darkeye
00435   added possibility to disable highpass and lowpass filters for lame
00436 
00437   Revision 1.8  2001/10/19 12:39:42  darkeye
00438   created configure options to compile with or without lame / Ogg Vorbis
00439 
00440   Revision 1.7  2001/09/18 14:57:19  darkeye
00441   finalized Solaris port
00442 
00443   Revision 1.6  2001/09/15 11:35:08  darkeye
00444   minor fixes
00445 
00446   Revision 1.5  2001/09/02 09:54:12  darkeye
00447   fixed typos in CVS substition keywords
00448 
00449   Revision 1.4  2001/08/31 20:09:05  darkeye
00450   added funcitons conv8() and conv16()
00451 
00452   Revision 1.3  2001/08/30 17:25:56  darkeye
00453   renamed configure.h to config.h
00454 
00455   Revision 1.2  2001/08/29 21:06:16  darkeye
00456   added real support for 8 / 16 bit mono / stereo input
00457   (8 bit input still has to be spread on 16 bit words)
00458 
00459   Revision 1.1  2001/08/26 20:44:30  darkeye
00460   removed external command-line encoder support
00461   replaced it with a shared-object support for lame with the possibility
00462   of static linkage
00463 
00464 
00465   
00466 ------------------------------------------------------------------------------*/
00467 

Generated on Fri May 19 15:36:48 2006 for DarkIce by  doxygen 1.4.4