280 lines
10 KiB
C++
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
|
|
|