added mpeg2 support thanks to Nicholas J Humfrey

This commit is contained in:
darkeye 2006-01-25 22:49:59 +00:00
parent 9ba6d64d1f
commit 0c4f4847c4
2 changed files with 702 additions and 0 deletions

View File

@ -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
------------------------------------------------------------------------------*/

View File

@ -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 <twolame.h>
#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> 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
------------------------------------------------------------------------------*/