diff --git a/darkice/trunk/src/TwoLameLibEncoder.cpp b/darkice/trunk/src/TwoLameLibEncoder.cpp new file mode 100644 index 0000000..1e1ced2 --- /dev/null +++ b/darkice/trunk/src/TwoLameLibEncoder.cpp @@ -0,0 +1,317 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2005 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : TwoLameLibEncoder.cpp + Version : $Revision$ + Author : $Author$ + Location : $Source$ + + Copyright notice: + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// compile the whole file only if TwoLame support configured in +#ifdef HAVE_TWOLAME_LIB + + + +#include "Exception.h" +#include "Util.h" +#include "TwoLameLibEncoder.h" + + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +/*------------------------------------------------------------------------------ + * File identity + *----------------------------------------------------------------------------*/ +static const char fileid[] = "$Id$"; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + + + +/*------------------------------------------------------------------------------ + * Initialize the object + *----------------------------------------------------------------------------*/ +void +TwoLameLibEncoder :: init ( Sink * sink ) throw ( Exception ) +{ + this->twolame_opts = NULL; + this->sink = sink; + + if ( getInBitsPerSample() != 16 ) { + throw Exception( __FILE__, __LINE__, + "specified bits per sample not supported", + getInBitsPerSample() ); + } + + if ( getInChannel() != 1 && getInChannel() != 2 ) { + throw Exception( __FILE__, __LINE__, + "unsupported number of input channels for the encoder", + getInChannel() ); + } + if ( getOutChannel() != 1 && getOutChannel() != 2 ) { + throw Exception( __FILE__, __LINE__, + "unsupported number of output channels for the encoder", + getOutChannel() ); + } + if ( getInChannel() < getOutChannel() ) { + throw Exception( __FILE__, __LINE__, + "output channels greater then input channels", + getOutChannel() ); + } +} + + +/*------------------------------------------------------------------------------ + * Open an encoding session + *----------------------------------------------------------------------------*/ +bool +TwoLameLibEncoder :: open ( void ) + throw ( Exception ) +{ + if ( isOpen() ) { + close(); + } + + // open the underlying sink + if ( !sink->open() ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib opening underlying sink error"); + } + + twolame_opts = ::twolame_init(); + + // ugly twolame returns -1 in a pointer on allocation errors + if ( !twolame_opts ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib init error", + (int) twolame_opts); + } + + if ( 0 > twolame_set_num_channels( twolame_opts, getInChannel()) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib setting channels error", + getInChannel() ); + } + + if ( 0 > twolame_set_mode( twolame_opts, + getOutChannel() == 1 ? TWOLAME_MONO : TWOLAME_JOINT_STEREO) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib setting mode error", + TWOLAME_JOINT_STEREO ); + } + + if ( 0 > twolame_set_in_samplerate( twolame_opts, getInSampleRate()) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib setting input sample rate error", + getInSampleRate() ); + } + + if ( 0 > twolame_set_out_samplerate( twolame_opts, getOutSampleRate()) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib setting output sample rate error", + getOutSampleRate() ); + } + + switch ( getOutBitrateMode() ) { + + case cbr: { + + if ( 0 > twolame_set_brate( twolame_opts, getOutBitrate()) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib setting output bit rate error", + getOutBitrate() ); + } + } break; + + default: { + throw Exception( __FILE__, __LINE__, + "Unsupported bitrate mode." ); + } + } + + + // let TwoLAME init its own params based on our settings + if ( 0 > twolame_init_params( twolame_opts) ) { + throw Exception( __FILE__, __LINE__, + "TwoLAME lib initializing params error" ); + } + + // Information about TwoLame's setup + if (getReportVerbosity() >= 3) { + twolame_print_config( twolame_opts); + } + + return true; +} + + +/*------------------------------------------------------------------------------ + * Write data to the encoder + *----------------------------------------------------------------------------*/ +unsigned int +TwoLameLibEncoder :: write ( const void * buf, + unsigned int len ) throw ( Exception ) +{ + if ( !isOpen() || len == 0 ) { + return 0; + } + + unsigned int bitsPerSample = getInBitsPerSample(); + unsigned int inChannels = getInChannel(); + + unsigned int sampleSize = (bitsPerSample / 8) * inChannels; + unsigned char * b = (unsigned char*) buf; + unsigned int processed = len - (len % sampleSize); + unsigned int nSamples = processed / sampleSize; + short int * leftBuffer = new short int[nSamples]; + short int * rightBuffer = new short int[nSamples]; + + if ( bitsPerSample == 8 ) { + Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels); + } else if ( bitsPerSample == 16 ) { + Util::conv16( b, + processed, + leftBuffer, + rightBuffer, + inChannels, + isInBigEndian()); + } else { + delete[] leftBuffer; + delete[] rightBuffer; + throw Exception( __FILE__, __LINE__, + "unsupported number of bits per sample for the encoder", + bitsPerSample ); + } + + // data chunk size estimate according to TwoLAME documentation + // NOTE: mp2Size is calculated based on the number of input channels + // which may be bigger than need, as output channels can be less + unsigned int mp2Size = (unsigned int) (1.25 * nSamples + 7200); + unsigned char * mp2Buf = new unsigned char[mp2Size]; + int ret; + + ret = twolame_encode_buffer( twolame_opts, + leftBuffer, + inChannels == 2 ? rightBuffer : leftBuffer, + nSamples, + mp2Buf, + mp2Size ); + + delete[] leftBuffer; + delete[] rightBuffer; + + if ( ret < 0 ) { + reportEvent( 3, "TwoLAME encoding error", ret); + delete[] mp2Buf; + return 0; + } + + unsigned int written = sink->write( mp2Buf, ret); + delete[] mp2Buf; + // just let go data that could not be written + if ( written < (unsigned int) ret ) { + reportEvent( 2, + "couldn't write all from encoder to underlying sink", + ret - written); + } + + return processed; +} + + +/*------------------------------------------------------------------------------ + * Flush the data from the encoder + *----------------------------------------------------------------------------*/ +void +TwoLameLibEncoder :: flush ( void ) + throw ( Exception ) +{ + if ( !isOpen() ) { + return; + } + + // data chunk size estimate according to TwoLAME documentation + unsigned int mp2Size = 7200; + unsigned char * mp2Buf = new unsigned char[mp2Size]; + int ret; + + ret = twolame_encode_flush( twolame_opts, mp2Buf, mp2Size ); + + unsigned int written = sink->write( mp2Buf, ret); + delete[] mp2Buf; + + // just let go data that could not be written + if ( written < (unsigned int) ret ) { + reportEvent( 2, + "couldn't write all from encoder to underlying sink", + ret - written); + } + + sink->flush(); +} + + +/*------------------------------------------------------------------------------ + * Close the encoding session + *----------------------------------------------------------------------------*/ +void +TwoLameLibEncoder :: close ( void ) throw ( Exception ) +{ + if ( isOpen() ) { + flush(); + twolame_close( &twolame_opts ); + sink->close(); + } +} + + +#endif // HAVE_TWOLAME_LIB + + +/*------------------------------------------------------------------------------ + + $Source$ + + $Log$ + Revision 1.1 2006/01/25 22:49:59 darkeye + added mpeg2 support thanks to Nicholas J Humfrey + + + Revision 1.1 2005/05/02 23:05:02 nhumfrey + initial version - based on LameLibEncoder 1.19 + +------------------------------------------------------------------------------*/ + diff --git a/darkice/trunk/src/TwoLameLibEncoder.h b/darkice/trunk/src/TwoLameLibEncoder.h new file mode 100644 index 0000000..0e519e1 --- /dev/null +++ b/darkice/trunk/src/TwoLameLibEncoder.h @@ -0,0 +1,385 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2005 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : TwoLameLibEncoder.cpp + Version : $Revision$ + Author : $Author$ + Location : $Source$ + + Copyright notice: + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +------------------------------------------------------------------------------*/ +#ifndef TWOLAME_LIB_ENCODER_H +#define TWOLAME_LIB_ENCODER_H + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_TWOLAME_LIB +#include +#else +#error configure with twolame +#endif + + +#include "Ref.h" +#include "Exception.h" +#include "Reporter.h" +#include "AudioEncoder.h" +#include "Sink.h" + + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * A class representing the TwoLame encoder linked as a shared object or as + * a static library. + * + * @author $Author$ + * @version $Revision$ + */ +class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter +{ + private: + + /** + * TwoLame library global flags + */ + twolame_options * twolame_opts; + + /** + * The Sink to dump mp2 data to + */ + Ref sink; + + /** + * Initialize the object. + * + * @param sink the sink to send mp2 output to + * @exception Exception + */ + void + init ( Sink * sink ) throw ( Exception ); + + /** + * De-initialize the object. + * + * @exception Exception + */ + inline void + strip ( void ) throw ( Exception ) + { + } + + + protected: + + /** + * Default constructor. Always throws an Exception. + * + * @exception Exception + */ + inline + TwoLameLibEncoder ( void ) throw ( Exception ) + { + throw Exception( __FILE__, __LINE__); + } + + + public: + + /** + * Constructor. + * + * @param sink the sink to send mp2 output to + * @param inSampleRate sample rate of the input. + * @param inBitsPerSample number of bits per sample of the input. + * @param inChannel number of channels of the input. + * @param inBigEndian shows if the input is big or little endian + * @param outBitrateMode the bit rate mode of the output. + * @param outBitrate bit rate of the output (kbits/sec). + * @param outSampleRate sample rate of the output. + * If 0, inSampleRate is used. + * @param outChannel number of channels of the output. + * If 0, inChannel is used. + * @exception Exception + */ + inline + TwoLameLibEncoder ( Sink * sink, + unsigned int inSampleRate, + unsigned int inBitsPerSample, + unsigned int inChannel, + bool inBigEndian, + BitrateMode outBitrateMode, + unsigned int outBitrate, + unsigned int outSampleRate = 0, + unsigned int outChannel = 0 ) + throw ( Exception ) + + : AudioEncoder ( inSampleRate, + inBitsPerSample, + inChannel, + inBigEndian, + outBitrateMode, + outBitrate, + 0.0f, // outQuality + outSampleRate, + outChannel ) + { + init( sink ); + } + + /** + * Constructor. + * + * @param sink the sink to send mp2 output to + * @param as get input sample rate, bits per sample and channels + * from this AudioSource. + * @param outBitrateMode the bit rate mode of the output. + * @param outBitrate bit rate of the output (kbits/sec). + * @param outSampleRate sample rate of the output. + * If 0, input sample rate is used. + * @param outChannel number of channels of the output. + * If 0, input channel is used. + * @exception Exception + */ + inline + TwoLameLibEncoder ( Sink * sink, + const AudioSource * as, + BitrateMode outBitrateMode, + unsigned int outBitrate, + unsigned int outSampleRate = 0, + unsigned int outChannel = 0 ) + throw ( Exception ) + + : AudioEncoder ( as, + outBitrateMode, + outBitrate, + 0.0f, // outQuality + outSampleRate, + outChannel ) + { + init( sink ); + } + + /** + * Copy constructor. + * + * @param encoder the TwoLameLibEncoder to copy. + */ + inline + TwoLameLibEncoder ( const TwoLameLibEncoder & encoder ) + throw ( Exception ) + : AudioEncoder( encoder ) + { + init( encoder.sink.get() ); + } + + + /** + * Destructor. + * + * @exception Exception + */ + inline virtual + ~TwoLameLibEncoder ( void ) throw ( Exception ) + { + if ( isOpen() ) { + close(); + } + strip(); + } + + /** + * Assignment operator. + * + * @param encoder the TwoLameLibEncoder to assign this to. + * @return a reference to this TwoLameLibEncoder. + * @exception Exception + */ + inline virtual TwoLameLibEncoder & + operator= ( const TwoLameLibEncoder & encoder ) throw ( Exception ) + { + if ( this != &encoder ) { + strip(); + AudioEncoder::operator=( encoder); + init( encoder.sink.get() ); + } + + return *this; + } + + /** + * Get the version string of the underlying lame library. + * + * @return the version string of the underlying lame library. + */ + inline const char * + getLameVersion( void ) + { + return get_twolame_version(); + } + + /** + * Check wether encoding is in progress. + * + * @return true if encoding is in progress, false otherwise. + */ + inline virtual bool + isRunning ( void ) const throw () + { + return isOpen(); + } + + /** + * Start encoding. This function returns as soon as possible, + * with encoding started in the background. + * + * @return true if encoding has started, false otherwise. + * @exception Exception + */ + inline virtual bool + start ( void ) throw ( Exception ) + { + return open(); + } + + /** + * Stop encoding. Stops the encoding running in the background. + * + * @exception Exception + */ + inline virtual void + stop ( void ) throw ( Exception ) + { + return close(); + } + + /** + * Open an encoding session. + * + * @return true if opening was successfull, false otherwise. + * @exception Exception + */ + virtual bool + open ( void ) throw ( Exception ); + + /** + * Check if the encoding session is open. + * + * @return true if the encoding session is open, false otherwise. + */ + inline virtual bool + isOpen ( void ) const throw () + { + return twolame_opts != 0; + } + + /** + * Check if the encoder is ready to accept data. + * + * @param sec the maximum seconds to block. + * @param usec micro seconds to block after the full seconds. + * @return true if the encoder is ready to accept data, + * false otherwise. + * @exception Exception + */ + inline virtual bool + canWrite ( unsigned int sec, + unsigned int usec ) throw ( Exception ) + { + if ( !isOpen() ) { + return false; + } + + return true; + } + + /** + * Write data to the encoder. + * Buf is expected to be a sequence of big-endian 16 bit values, + * with left and right channels interleaved. Len is the number of + * bytes, must be a multiple of 4. + * + * @param buf the data to write. + * @param len number of bytes to write from buf. + * @return the number of bytes written (may be less than len). + * @exception Exception + */ + virtual unsigned int + write ( const void * buf, + unsigned int len ) throw ( Exception ); + + /** + * Flush all data that was written to the encoder to the underlying + * connection. + * + * @exception Exception + */ + virtual void + flush ( void ) throw ( Exception ); + + /** + * Close the encoding session. + * + * @exception Exception + */ + virtual void + close ( void ) throw ( Exception ); +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +#endif /* TWOLAME_LIB_ENCODER_H */ + + +/*------------------------------------------------------------------------------ + + $Source$ + + $Log$ + Revision 1.1 2006/01/25 22:49:59 darkeye + added mpeg2 support thanks to Nicholas J Humfrey + + + Revision 1.1 2005/05/02 23:05:02 nhumfrey + initial version - based on LameLibEncoder 1.19 + +------------------------------------------------------------------------------*/ +