darkice/darkice/trunk/src/FaacEncoder.cpp

280 lines
10 KiB
C++

/*------------------------------------------------------------------------------
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
Tyrell DarkIce
File : FaacEncoder.cpp
Version : $Revision$
Author : $Author$
Location : $HeadURL$
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 3
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 faac support configured in
#ifdef HAVE_FAAC_LIB
#include "Exception.h"
#include "Util.h"
#include "FaacEncoder.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Open an encoding session
*----------------------------------------------------------------------------*/
bool
FaacEncoder :: open ( void )
throw ( Exception )
{
if ( isOpen() ) {
close();
}
// open the underlying sink
if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__,
"faac lib opening underlying sink error");
}
char * faacVersion;
char * faacCopyright;
faacEncGetVersion(&faacVersion, &faacCopyright);
reportEvent(1, "Using faac codec version", faacVersion);
encoderHandle = faacEncOpen(getOutSampleRate(),
getInChannel(),
&inputSamples,
&maxOutputBytes);
faacEncConfiguration * faacConfig;
faacConfig = faacEncGetCurrentConfiguration(encoderHandle);
faacConfig->aacObjectType = MAIN;
faacConfig->mpegVersion = MPEG2;
faacConfig->useTns = 1;
faacConfig->shortctl = SHORTCTL_NORMAL;
faacConfig->useLfe = 0;
faacConfig->allowMidside = 1;
faacConfig->bitRate = getOutBitrate() * 1000 / getOutChannel();
faacConfig->bandWidth = lowpass;
faacConfig->quantqual = (unsigned long) (getOutQuality() * 1000.0);
faacConfig->outputFormat = 1;
faacConfig->inputFormat = FAAC_INPUT_16BIT;
if (!faacEncSetConfiguration(encoderHandle, faacConfig)) {
throw Exception(__FILE__, __LINE__,
"error configuring faac library");
}
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
if ((int) inputSamples > getInChannel() * converterData.output_frames) {
resampledOffset = new float[2 * inputSamples];
} else {
resampledOffset = new float[2 * getInChannel() * converterData.input_frames];
}
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
//needed 2x(converted input samples) to handle offsets
int outCount = 2 * getInChannel() * (inputSamples + 1);
if (resampleRatio > 1)
outCount = (int) (outCount * resampleRatio);
resampledOffset = new short int[outCount];
#endif
resampledOffsetSize = 0;
}
faacOpen = true;
return true;
}
/*------------------------------------------------------------------------------
* Write data to the encoder
*----------------------------------------------------------------------------*/
unsigned int
FaacEncoder :: write ( const void * buf,
unsigned int len ) throw ( Exception )
{
if ( !isOpen() || len == 0 ) {
return 0;
}
unsigned int channels = getInChannel();
unsigned int bitsPerSample = getInBitsPerSample();
unsigned int sampleSize = (bitsPerSample / 8) * channels;
unsigned char * b = (unsigned char*) buf;
unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize;
unsigned char * faacBuf = new unsigned char[maxOutputBytes];
int samples = (int) nSamples * channels;
int processedSamples = 0;
if ( converter ) {
unsigned int converted;
#ifdef HAVE_SRC_LIB
src_short_to_float_array ((short *) b, (float *) converterData.data_in, samples);
converterData.input_frames = nSamples;
converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
#else
int inCount = nSamples;
short int * shortBuffer = new short int[samples];
int outCount = (int) (inCount * resampleRatio);
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
converted = converter->resample( inCount,
outCount+1,
shortBuffer,
&resampledOffset[resampledOffsetSize*channels]);
delete[] shortBuffer;
#endif
resampledOffsetSize += converted;
// encode samples (if enough)
while(resampledOffsetSize - processedSamples >= inputSamples/channels) {
int outputBytes;
#ifdef HAVE_SRC_LIB
short *shortData = new short[inputSamples];
src_float_to_short_array(resampledOffset + (processedSamples * channels),
shortData, inputSamples) ;
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) shortData,
inputSamples,
faacBuf,
maxOutputBytes);
delete [] shortData;
#else
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) &resampledOffset[processedSamples*channels],
inputSamples,
faacBuf,
maxOutputBytes);
#endif
getSink()->write(faacBuf, outputBytes);
processedSamples+=inputSamples/channels;
}
if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
resampledOffsetSize -= processedSamples;
//move least part of resampled data to beginning
if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*channels*sizeof(float));
#else
resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*sampleSize);
#endif
}
} else {
while (processedSamples < samples) {
int outputBytes;
int inSamples = samples - processedSamples < (int) inputSamples
? samples - processedSamples
: inputSamples;
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) (b + processedSamples/sampleSize),
inSamples,
faacBuf,
maxOutputBytes);
getSink()->write(faacBuf, outputBytes);
processedSamples += inSamples;
}
}
delete[] faacBuf;
return samples * sampleSize;
}
/*------------------------------------------------------------------------------
* Flush the data from the encoder
*----------------------------------------------------------------------------*/
void
FaacEncoder :: flush ( void )
throw ( Exception )
{
if ( !isOpen() ) {
return;
}
getSink()->flush();
}
/*------------------------------------------------------------------------------
* Close the encoding session
*----------------------------------------------------------------------------*/
void
FaacEncoder :: close ( void ) throw ( Exception )
{
if ( isOpen() ) {
flush();
faacEncClose(encoderHandle);
faacOpen = false;
getSink()->close();
}
}
#endif // HAVE_FAAC_LIB