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

VorbisLibEncoder.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     : VorbisLibEncoder.cpp
00008    Version  : $Revision: 1.21 $
00009    Author   : $Author: darkeye $
00010    Location : $Source: /cvsroot/darkice/darkice/src/VorbisLibEncoder.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 only if configured for Ogg Vorbis
00037 #ifdef HAVE_VORBIS_LIB
00038 
00039 
00040 #include "Exception.h"
00041 #include "Util.h"
00042 #include "VorbisLibEncoder.h"
00043 
00044 
00045 /* ===================================================  local data structures */
00046 
00047 
00048 /* ================================================  local constants & macros */
00049 
00050 /*------------------------------------------------------------------------------
00051  *  File identity
00052  *----------------------------------------------------------------------------*/
00053 static const char fileid[] = "$Id: VorbisLibEncoder.cpp,v 1.21 2005/04/11 19:26:55 darkeye Exp $";
00054 
00055 
00056 /* ===============================================  local function prototypes */
00057 
00058 
00059 /* =============================================================  module code */
00060 
00061 /*------------------------------------------------------------------------------
00062  *  Initialize the encoder
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         // Determine if we can use linear interpolation.
00092         // The inverse of the ratio must be a power of two for linear mode to
00093         // be of sufficient quality.
00094         
00095         bool    useLinear = true;
00096         double  inverse   = 1 / resampleRatio;
00097         int     integer   = (int) inverse;
00098 
00099         // Check that the inverse of the ratio is an integer
00100         if( integer == inverse ) {
00101             while( useLinear && integer ) { // Loop through the bits
00102                 // If the lowest order bit is not the only one set
00103                 if( integer & 1 && integer != 1 ) {
00104                     // Not a power of two; cannot use linear
00105                     useLinear = false;
00106                 } else {
00107                     // Shift all the bits over and try again
00108                     integer >>= 1;
00109                 }
00110             }
00111         } else {
00112            useLinear = false;
00113         }
00114 
00115         // If we get here and useLinear is still true, then we have
00116         // a power of two.
00117            
00118         // open the aflibConverter in
00119         // - high quality
00120         // - linear or quadratic (non-linear) based on algorithm
00121         // - not filter interpolation
00122         converter = new aflibConverter( true, useLinear, false);
00123     }
00124 
00125     encoderOpen = false;
00126 }
00127 
00128 
00129 /*------------------------------------------------------------------------------
00130  *  Open an encoding session
00131  *----------------------------------------------------------------------------*/
00132 bool
00133 VorbisLibEncoder :: open ( void )
00134                                                             throw ( Exception )
00135 {
00136     int     ret;
00137 
00138     if ( isOpen() ) {
00139         close();
00140     }
00141 
00142     // open the underlying sink
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             /* set non-managed VBR around the average bitrate */
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     // create an empty vorbis_comment structure
00208     vorbis_comment_init( &vorbisComment);
00209     // Add comment to vorbis headers to show title in players
00210     // stupid cast to (char*) because of stupid vorbis API
00211     if ( sink->getName() ) {
00212         vorbis_comment_add_tag(&vorbisComment, "TITLE", (char*)sink->getName());
00213     }
00214 
00215     // create the vorbis stream headers and send them to the underlying sink
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     // initialize the resampling coverter if needed
00241     if ( converter ) {
00242         converter->initialize( resampleRatio, getInChannel());
00243     }
00244 
00245     encoderOpen = true;
00246 
00247     return true;
00248 }
00249 
00250 
00251 /*------------------------------------------------------------------------------
00252  *  Write data to the encoder
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     // convert the byte-based raw input into a short buffer
00293     // with channels still interleaved
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         // resample if needed
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  *  Flush the data from the encoder
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  *  Send pending Vorbis blocks to the underlying stream
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                     // just let go data that could not be written
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  *  Close the encoding session
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   $Source: /cvsroot/darkice/darkice/src/VorbisLibEncoder.cpp,v $
00416 
00417   $Log: VorbisLibEncoder.cpp,v $
00418   Revision 1.21  2005/04/11 19:26:55  darkeye
00419   cosmetic changes
00420   fixed warning for implicit cast from doulbe to int
00421 
00422   Revision 1.20  2005/04/03 05:18:24  jbebel
00423   Add test to determine if the sample rate conversion ratio is a power of 2.
00424   If so, use linear interpolation.  Otherwise use more complicated quadratic
00425   interpolation which tends to sound terrible, but is better than trying to
00426   use linear for a non-standard conversion.
00427 
00428   Revision 1.19  2004/03/13 10:41:39  darkeye
00429   added possibility to downsample from stereo to mono when encoding
00430   to Ogg Vorbis
00431 
00432   Revision 1.18  2004/02/15 13:07:42  darkeye
00433   ogg vorbis recording to only a file caused a segfault. now fixed
00434 
00435   Revision 1.17  2003/02/09 13:15:57  darkeye
00436   added feature for setting the TITLE comment field for vorbis streams
00437 
00438   Revision 1.16  2002/10/19 13:31:46  darkeye
00439   some cleanup with the open() / close() functions
00440 
00441   Revision 1.15  2002/10/19 12:22:10  darkeye
00442   return 0 immediately for write() if supplied length is 0
00443 
00444   Revision 1.14  2002/08/22 21:52:08  darkeye
00445   bug fix: maximum bitrate setting fixed for Ogg Vorbis streams
00446 
00447   Revision 1.13  2002/08/20 19:35:37  darkeye
00448   added possibility to specify maximum bitrate for Ogg Vorbis streams
00449 
00450   Revision 1.12  2002/08/03 10:30:46  darkeye
00451   resampling bugs fixed for vorbis streams
00452 
00453   Revision 1.11  2002/07/20 16:37:06  darkeye
00454   added fault tolerance in case a server connection is dropped
00455 
00456   Revision 1.10  2002/07/20 10:59:00  darkeye
00457   added support for Ogg Vorbis 1.0, removed support for rc2
00458 
00459   Revision 1.9  2002/05/28 12:35:41  darkeye
00460   code cleanup: compiles under gcc-c++ 3.1, using -pedantic option
00461 
00462   Revision 1.8  2002/04/13 11:26:00  darkeye
00463   added cbr, abr and vbr setting feature with encoding quality
00464 
00465   Revision 1.7  2002/03/28 16:47:38  darkeye
00466   moved functions conv8() and conv16() to class Util (as conv())
00467   added resampling functionality
00468   added support for variable bitrates
00469 
00470   Revision 1.6  2002/02/20 10:35:35  darkeye
00471   updated to work with Ogg Vorbis libs rc3 and current IceCast2 cvs
00472 
00473   Revision 1.5  2001/10/21 13:08:18  darkeye
00474   fixed incorrect vorbis bitrate setting
00475 
00476   Revision 1.4  2001/10/19 12:39:42  darkeye
00477   created configure options to compile with or without lame / Ogg Vorbis
00478 
00479   Revision 1.3  2001/09/18 14:57:19  darkeye
00480   finalized Solaris port
00481 
00482   Revision 1.2  2001/09/15 11:36:22  darkeye
00483   added function vorbisBlocksOut(), finalized vorbis support
00484 
00485   Revision 1.1  2001/09/14 19:31:06  darkeye
00486   added IceCast2 / vorbis support
00487 
00488 
00489   
00490 ------------------------------------------------------------------------------*/
00491 

Generated on Thu Apr 14 13:59:13 2005 for DarkIce by  doxygen 1.4.1