added aac+ encoding support, re #2
This commit is contained in:
parent
d9aa3f0753
commit
2a98f1f03b
|
@ -149,6 +149,42 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
dnl-----------------------------------------------------------------------------
|
||||||
|
dnl link the aacplus library if requested
|
||||||
|
dnl-----------------------------------------------------------------------------
|
||||||
|
AC_SUBST(AACPLUS_INCFLAGS)
|
||||||
|
AC_SUBST(AACPLUS_LDFLAGS)
|
||||||
|
|
||||||
|
AC_ARG_WITH(aacplus,
|
||||||
|
[ --with-aacplus use aacplus for encoding AAC HEv2 streams [yes] ],
|
||||||
|
USE_AACPLUS=${withval}, USE_AACPLUS="yes" )
|
||||||
|
AC_ARG_WITH(aacplus-prefix,
|
||||||
|
[ --with-aacplus-prefix=DIR alternate location for aacplus [/usr]
|
||||||
|
look for libraries in AACPLUS-PREFIX/lib,
|
||||||
|
for headers in AACPLUS-PREFIX/include],
|
||||||
|
CONFIG_AACPLUS_PREFIX="${withval}", CONFIG_AACPLUS_PREFIX="/usr")
|
||||||
|
|
||||||
|
if test "x${USE_AACPLUS}" = "xyes" ; then
|
||||||
|
AC_MSG_CHECKING( [for aacplus library at ${CONFIG_AACPLUS_PREFIX}] )
|
||||||
|
LA_SEARCH_LIB( AACPLUS_LIB_LOC, AACPLUS_INC_LOC, libaacplus.a libaacplus.so, sbr_main.h,
|
||||||
|
${CONFIG_AACPLUS_PREFIX})
|
||||||
|
if test "x${AACPLUS_LIB_LOC}" != "x" ; then
|
||||||
|
AC_DEFINE( HAVE_AACPLUS_LIB, 1, [build with aacplus library] )
|
||||||
|
if test "x${AACPLUS_INC_LOC}" != "x${SYSTEM_INCLUDE}" ; then
|
||||||
|
AACPLUS_INCFLAGS="-I${AACPLUS_INC_LOC}"
|
||||||
|
fi
|
||||||
|
AACPLUS_LDFLAGS="-L${AACPLUS_LIB_LOC} -laacplus"
|
||||||
|
# TODO: we have to define _FFTW3 only if libaacplus builded with fftw3f
|
||||||
|
AC_DEFINE( _FFTW3, 1, [libaacplus have to be builded with fftw3f library] )
|
||||||
|
AC_MSG_RESULT( [found at ${CONFIG_AACPLUS_PREFIX}] )
|
||||||
|
else
|
||||||
|
AC_MSG_WARN( [not found, building without aacplus])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT( [building without aacplus] )
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
dnl link the twolame library if requested
|
dnl link the twolame library if requested
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
|
@ -189,8 +225,9 @@ dnl-----------------------------------------------------------------------------
|
||||||
if test "x${LAME_LDFLAGS}" = "x" \
|
if test "x${LAME_LDFLAGS}" = "x" \
|
||||||
-a "x${VORBIS_LDFLAGS}" = "x" \
|
-a "x${VORBIS_LDFLAGS}" = "x" \
|
||||||
-a "x${FAAC_LDFLAGS}" = "x" \
|
-a "x${FAAC_LDFLAGS}" = "x" \
|
||||||
|
-a "x${AACPLUS_LDFLAGS}" = "x" \
|
||||||
-a "x${TWOLAME_LDFLAGS}" = "x"; then
|
-a "x${TWOLAME_LDFLAGS}" = "x"; then
|
||||||
AC_MSG_ERROR([neither lame, Ogg Vorbis, faac nor twolame configured])
|
AC_MSG_ERROR([neither lame, Ogg Vorbis, faac, aac+ nor twolame configured])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,10 @@
|
||||||
#include "FaacEncoder.h"
|
#include "FaacEncoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_AACPLUS_LIB
|
||||||
|
#include "aacPlusEncoder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* =================================================== local data structures */
|
/* =================================================== local data structures */
|
||||||
|
|
||||||
|
@ -454,6 +458,8 @@ DarkIce :: configIceCast2 ( const Config & config,
|
||||||
format = IceCast2::mp2;
|
format = IceCast2::mp2;
|
||||||
} else if ( Util::strEq( str, "aac") ) {
|
} else if ( Util::strEq( str, "aac") ) {
|
||||||
format = IceCast2::aac;
|
format = IceCast2::aac;
|
||||||
|
} else if ( Util::strEq( str, "aacp") ) {
|
||||||
|
format = IceCast2::aacp;
|
||||||
} else {
|
} else {
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"unsupported stream format: ", str);
|
"unsupported stream format: ", str);
|
||||||
|
@ -643,6 +649,24 @@ DarkIce :: configIceCast2 ( const Config & config,
|
||||||
#endif // HAVE_FAAC_LIB
|
#endif // HAVE_FAAC_LIB
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IceCast2::aacp:
|
||||||
|
#ifndef HAVE_AACPLUS_LIB
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"DarkIce not compiled with AAC+ support, "
|
||||||
|
"thus can't aacp stream: ",
|
||||||
|
stream);
|
||||||
|
#else
|
||||||
|
audioOuts[u].encoder = new aacPlusEncoder(
|
||||||
|
audioOuts[u].server.get(),
|
||||||
|
dsp.get(),
|
||||||
|
bitrateMode,
|
||||||
|
bitrate,
|
||||||
|
quality,
|
||||||
|
sampleRate,
|
||||||
|
dsp->getChannel());
|
||||||
|
#endif // HAVE_AACPLUS_LIB
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"Illegal stream format: ", format);
|
"Illegal stream format: ", format);
|
||||||
|
@ -878,7 +902,8 @@ DarkIce :: configFileCast ( const Config & config )
|
||||||
if ( !Util::strEq( format, "vorbis")
|
if ( !Util::strEq( format, "vorbis")
|
||||||
&& !Util::strEq( format, "mp3")
|
&& !Util::strEq( format, "mp3")
|
||||||
&& !Util::strEq( format, "mp2")
|
&& !Util::strEq( format, "mp2")
|
||||||
&& !Util::strEq( format, "aac") ) {
|
&& !Util::strEq( format, "aac")
|
||||||
|
&& !Util::strEq( format, "aacp") ) {
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"unsupported stream format: ", format);
|
"unsupported stream format: ", format);
|
||||||
}
|
}
|
||||||
|
@ -936,6 +961,12 @@ DarkIce :: configFileCast ( const Config & config )
|
||||||
"average bitrate mode");
|
"average bitrate mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Util::strEq(format, "aacp") && bitrateMode != AudioEncoder::cbr) {
|
||||||
|
throw Exception(__FILE__, __LINE__,
|
||||||
|
"currently the AAC+ format only supports "
|
||||||
|
"constant bitrate mode");
|
||||||
|
}
|
||||||
|
|
||||||
str = cs->get( "lowpass");
|
str = cs->get( "lowpass");
|
||||||
lowpass = str ? Util::strToL( str) : 0;
|
lowpass = str ? Util::strToL( str) : 0;
|
||||||
str = cs->get( "highpass");
|
str = cs->get( "highpass");
|
||||||
|
@ -1031,6 +1062,22 @@ DarkIce :: configFileCast ( const Config & config )
|
||||||
sampleRate,
|
sampleRate,
|
||||||
dsp->getChannel());
|
dsp->getChannel());
|
||||||
#endif // HAVE_FAAC_LIB
|
#endif // HAVE_FAAC_LIB
|
||||||
|
} else if ( Util::strEq( format, "aacp") ) {
|
||||||
|
#ifndef HAVE_AACPLUS_LIB
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"DarkIce not compiled with AAC+ support, "
|
||||||
|
"thus can't aacplus stream: ",
|
||||||
|
stream);
|
||||||
|
#else
|
||||||
|
audioOuts[u].encoder = new aacPlusEncoder(
|
||||||
|
audioOuts[u].server.get(),
|
||||||
|
dsp.get(),
|
||||||
|
bitrateMode,
|
||||||
|
bitrate,
|
||||||
|
quality,
|
||||||
|
sampleRate,
|
||||||
|
dsp->getChannel());
|
||||||
|
#endif // HAVE_AACPLUS_LIB
|
||||||
} else {
|
} else {
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"Illegal stream format: ", format);
|
"Illegal stream format: ", format);
|
||||||
|
|
|
@ -161,6 +161,10 @@ IceCast2 :: sendLogin ( void ) throw ( Exception )
|
||||||
str = "audio/aac";
|
str = "audio/aac";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case aacp:
|
||||||
|
str = "audio/aacp";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw Exception( __FILE__, __LINE__,
|
throw Exception( __FILE__, __LINE__,
|
||||||
"unsupported stream format", format);
|
"unsupported stream format", format);
|
||||||
|
|
|
@ -63,7 +63,7 @@ class IceCast2 : public CastSink
|
||||||
/**
|
/**
|
||||||
* Type for specifying the format of the stream.
|
* Type for specifying the format of the stream.
|
||||||
*/
|
*/
|
||||||
enum StreamFormat { mp3, mp2, oggVorbis, aac };
|
enum StreamFormat { mp3, mp2, oggVorbis, aac, aacp };
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
bin_PROGRAMS = darkice
|
bin_PROGRAMS = darkice
|
||||||
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
|
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
|
||||||
@JACK_CFLAGS@
|
@JACK_CFLAGS@
|
||||||
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@
|
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@
|
||||||
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @TWOLAME_LDFLAGS@ \
|
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \
|
||||||
@ALSA_LDFLAGS@ @JACK_LDFLAGS@
|
@ALSA_LDFLAGS@ @JACK_LDFLAGS@
|
||||||
|
|
||||||
darkice_SOURCES = AudioEncoder.h\
|
darkice_SOURCES = AudioEncoder.h\
|
||||||
|
@ -38,6 +38,8 @@ darkice_SOURCES = AudioEncoder.h\
|
||||||
VorbisLibEncoder.h\
|
VorbisLibEncoder.h\
|
||||||
FaacEncoder.cpp\
|
FaacEncoder.cpp\
|
||||||
FaacEncoder.h\
|
FaacEncoder.h\
|
||||||
|
aacPlusEncoder.cpp\
|
||||||
|
aacPlusEncoder.h\
|
||||||
aflibDebug.h\
|
aflibDebug.h\
|
||||||
aflibDebug.cc\
|
aflibDebug.cc\
|
||||||
aflibConverter.h\
|
aflibConverter.h\
|
||||||
|
|
|
@ -0,0 +1,309 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2005 Tyrell Corporation. All rights reserved.
|
||||||
|
|
||||||
|
Tyrell DarkIce
|
||||||
|
|
||||||
|
File : aacPlusEncoder.cpp
|
||||||
|
Version : $Revision: 0.2 $
|
||||||
|
Author : $Author: tipok $
|
||||||
|
Location : $Source: /darkice-aacplus/src/aacPlusEncoder.cpp,v $
|
||||||
|
|
||||||
|
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 aacplus support configured in
|
||||||
|
#ifdef HAVE_AACPLUS_LIB
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "Exception.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#include "aacPlusEncoder.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================== local data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================ local constants & macros */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* File identity
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
static const char fileid[] = "$Id: aacPlusEncoder.cpp,v 0.2 2005/04/16 22:19:20 klaus Exp $";
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================== local function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================= module code */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Open an encoding session
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
bool
|
||||||
|
aacPlusEncoder :: open ( void )
|
||||||
|
throw ( Exception )
|
||||||
|
{
|
||||||
|
if ( isOpen() ) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the underlying sink
|
||||||
|
if ( !sink->open() ) {
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"aacplus lib opening underlying sink error");
|
||||||
|
}
|
||||||
|
|
||||||
|
reportEvent(1, "Using aacplus codec version", "720 3gpp");
|
||||||
|
|
||||||
|
|
||||||
|
/* set up basic parameters for aacPlus codec */
|
||||||
|
AacInitDefaultConfig(&config);
|
||||||
|
nChannelsAAC = nChannelsSBR = getOutChannel();
|
||||||
|
|
||||||
|
if ( (getInChannel() == 2) && (bitrate >= 16000) && (bitrate < 44001) ) {
|
||||||
|
useParametricStereo = 1;
|
||||||
|
nChannelsAAC = 1;
|
||||||
|
nChannelsSBR = 2;
|
||||||
|
|
||||||
|
reportEvent(10, "use Parametric Stereo");
|
||||||
|
|
||||||
|
envReadOffset = (MAX_DS_FILTER_DELAY + INPUT_DELAY)*MAX_CHANNELS;
|
||||||
|
coreWriteOffset = CORE_INPUT_OFFSET_PS;
|
||||||
|
writeOffset = envReadOffset;
|
||||||
|
} else {
|
||||||
|
/* set up 2:1 downsampling */
|
||||||
|
InitIIR21_Resampler(&(IIR21_reSampler[0]));
|
||||||
|
InitIIR21_Resampler(&(IIR21_reSampler[1]));
|
||||||
|
|
||||||
|
if(IIR21_reSampler[0].delay > MAX_DS_FILTER_DELAY){
|
||||||
|
throw Exception(__FILE__, __LINE__, "IIR21 resampler delay is bigger then MAX_DS_FILTER_DELAY");
|
||||||
|
}
|
||||||
|
writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleRateAAC = getInSampleRate();
|
||||||
|
config.bitRate = bitrate;
|
||||||
|
config.nChannelsIn=getInChannel();
|
||||||
|
config.nChannelsOut=nChannelsAAC;
|
||||||
|
config.bandWidth=bandwidth;
|
||||||
|
|
||||||
|
/* set up SBR configuration */
|
||||||
|
if(!IsSbrSettingAvail (bitrate, nChannelsAAC, sampleRateAAC, &sampleRateAAC)) {
|
||||||
|
throw Exception(__FILE__, __LINE__, "No valid SBR configuration found");
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeSbrDefaults (&sbrConfig);
|
||||||
|
sbrConfig.usePs = useParametricStereo;
|
||||||
|
|
||||||
|
AdjustSbrSettings( &sbrConfig,
|
||||||
|
bitrate,
|
||||||
|
nChannelsAAC,
|
||||||
|
sampleRateAAC,
|
||||||
|
AACENC_TRANS_FAC,
|
||||||
|
24000);
|
||||||
|
|
||||||
|
EnvOpen( &hEnvEnc,
|
||||||
|
inBuf + coreWriteOffset,
|
||||||
|
&sbrConfig,
|
||||||
|
&config.bandWidth);
|
||||||
|
|
||||||
|
/* set up AAC encoder, now that samling rate is known */
|
||||||
|
config.sampleRate = sampleRateAAC;
|
||||||
|
if ((error = AacEncOpen(&aacEnc, config)) != 0){
|
||||||
|
AacEncClose(aacEnc);
|
||||||
|
throw Exception(__FILE__, __LINE__, "Initialisation of AAC failed !");
|
||||||
|
}
|
||||||
|
|
||||||
|
init_plans();
|
||||||
|
|
||||||
|
/* create the ADTS header */
|
||||||
|
adts_hdr(outBuf, &config);
|
||||||
|
|
||||||
|
inSamples = AACENC_BLOCKSIZE * getInChannel() * 2;
|
||||||
|
|
||||||
|
aacplusOpen = true;
|
||||||
|
reportEvent(10, "bitrate=", bitrate);
|
||||||
|
reportEvent(10, "nChannelsIn", getInChannel());
|
||||||
|
reportEvent(10, "nChannelsSBR", nChannelsSBR);
|
||||||
|
reportEvent(10, "nChannelsOut", nChannelsAAC);
|
||||||
|
reportEvent(10, "sampleRateAAC", sampleRateAAC);
|
||||||
|
reportEvent(10, "inSamples", inSamples);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Write data to the encoder
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
unsigned int
|
||||||
|
aacPlusEncoder :: 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 int processed = len - (len % sampleSize);
|
||||||
|
unsigned int nSamples = processed / sampleSize;
|
||||||
|
int samples = (int) nSamples * channels;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int ch, outSamples, numOutBytes;
|
||||||
|
|
||||||
|
|
||||||
|
reportEvent(10, "converting short to float");
|
||||||
|
short *TimeDataPcm = (short *) buf;
|
||||||
|
for (i=0; i<samples; i++)
|
||||||
|
inBuf[i+writeOffset+writtenSamples] = (float) TimeDataPcm[i];
|
||||||
|
writtenSamples+=samples;
|
||||||
|
reportEvent(10, "writtenSamples", writtenSamples);
|
||||||
|
if (writtenSamples < inSamples)
|
||||||
|
return samples;
|
||||||
|
|
||||||
|
/* encode one SBR frame */
|
||||||
|
reportEvent(10, "encode one SBR frame");
|
||||||
|
EnvEncodeFrame( hEnvEnc,
|
||||||
|
inBuf + envReadOffset,
|
||||||
|
inBuf + coreWriteOffset,
|
||||||
|
MAX_CHANNELS,
|
||||||
|
&numAncDataBytes,
|
||||||
|
ancDataBytes);
|
||||||
|
|
||||||
|
reportEvent(10, "numAncDataBytes=", numAncDataBytes);
|
||||||
|
|
||||||
|
/* 2:1 downsampling for AAC core */
|
||||||
|
if (!useParametricStereo){
|
||||||
|
reportEvent(10, "2:1 downsampling for AAC core");
|
||||||
|
for( ch=0; ch<nChannelsAAC; ch++ )
|
||||||
|
IIR21_Downsample( &(IIR21_reSampler[ch]),
|
||||||
|
inBuf+writeOffset+ch,
|
||||||
|
writtenSamples/getInChannel(),
|
||||||
|
MAX_CHANNELS,
|
||||||
|
inBuf+ch,
|
||||||
|
&outSamples,
|
||||||
|
MAX_CHANNELS);
|
||||||
|
reportEvent(10, "outSamples=", outSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode one AAC frame */
|
||||||
|
if (hEnvEnc && useParametricStereo) {
|
||||||
|
reportEvent(10, "Parametric Stereo encode one AAC frame");
|
||||||
|
AacEncEncode( aacEnc,
|
||||||
|
inBuf,
|
||||||
|
1, /* stride (step) */
|
||||||
|
ancDataBytes,
|
||||||
|
&numAncDataBytes,
|
||||||
|
(unsigned *) (outBuf+ADTS_HEADER_SIZE),
|
||||||
|
&numOutBytes);
|
||||||
|
|
||||||
|
if(hEnvEnc)
|
||||||
|
memcpy( inBuf,inBuf+AACENC_BLOCKSIZE,CORE_INPUT_OFFSET_PS*sizeof(float));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
reportEvent(10, "encode one AAC frame");
|
||||||
|
AacEncEncode( aacEnc,
|
||||||
|
inBuf+coreReadOffset,
|
||||||
|
MAX_CHANNELS,
|
||||||
|
ancDataBytes,
|
||||||
|
&numAncDataBytes,
|
||||||
|
(unsigned *) (outBuf+ADTS_HEADER_SIZE),
|
||||||
|
&numOutBytes);
|
||||||
|
|
||||||
|
reportEvent(10, "done AAC=", numOutBytes);
|
||||||
|
if(hEnvEnc)
|
||||||
|
memmove( inBuf,inBuf+AACENC_BLOCKSIZE*2*MAX_CHANNELS,writeOffset*sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write one frame of encoded audio */
|
||||||
|
if (numOutBytes) {
|
||||||
|
reportEvent(10, "Write one frame of encoded audio:", numOutBytes+ADTS_HEADER_SIZE);
|
||||||
|
adts_hdr_up(outBuf, numOutBytes);
|
||||||
|
sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
writtenSamples=0;
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Flush the data from the encoder
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
aacPlusEncoder :: flush ( void )
|
||||||
|
throw ( Exception )
|
||||||
|
{
|
||||||
|
if ( !isOpen() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Close the encoding session
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
aacPlusEncoder :: close ( void ) throw ( Exception )
|
||||||
|
{
|
||||||
|
if ( isOpen() ) {
|
||||||
|
flush();
|
||||||
|
|
||||||
|
destroy_plans();
|
||||||
|
AacEncClose(aacEnc);
|
||||||
|
if (hEnvEnc) {
|
||||||
|
EnvClose(hEnvEnc);
|
||||||
|
}
|
||||||
|
|
||||||
|
aacplusOpen = false;
|
||||||
|
|
||||||
|
sink->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // HAVE_AACPLUS_LIB
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$Source: /cvsroot/darkice/darkice/src/aacPlusEncoder.cpp,v $
|
||||||
|
|
||||||
|
$Log: aacPlusEncoder.cpp,v $
|
||||||
|
Revision 0.1 2005/04/16 21:57:34 klaus
|
||||||
|
added AAC support through the aacplus codec, http://www.audiocoding.com/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -0,0 +1,477 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
|
||||||
|
|
||||||
|
Tyrell DarkIce
|
||||||
|
|
||||||
|
File : aacPlusEncoder.h
|
||||||
|
Version : $Revision: 0.2 $
|
||||||
|
Author : $Author: tipok $
|
||||||
|
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 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 AACP_ENCODER_H
|
||||||
|
#define AACP_ENCODER_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error This is a C++ include file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_AACPLUS_LIB
|
||||||
|
extern "C" {
|
||||||
|
#include <libaacplus/cfftn.h>
|
||||||
|
#include <libaacplus/FloatFR.h>
|
||||||
|
#include <libaacplus/aacenc.h>
|
||||||
|
#include <libaacplus/resampler.h>
|
||||||
|
|
||||||
|
#include <libaacplus/adts.h>
|
||||||
|
|
||||||
|
#include <libaacplus/sbr_main.h>
|
||||||
|
#include <libaacplus/aac_ram.h>
|
||||||
|
#include <libaacplus/aac_rom.h>
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error configure with aacplus
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "Ref.h"
|
||||||
|
#include "Exception.h"
|
||||||
|
#include "Reporter.h"
|
||||||
|
#include "AudioEncoder.h"
|
||||||
|
#include "Sink.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================================ constants */
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================================== macros */
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================================== data types */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing aacplus AAC+ encoder.
|
||||||
|
*
|
||||||
|
* @author $Author: tipok $
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CORE_DELAY (1600)
|
||||||
|
#define INPUT_DELAY ((CORE_DELAY)*2 +6*64-2048+1) /* ((1600 (core codec)*2 (multi rate) + 6*64 (sbr dec delay) - 2048 (sbr enc delay) + magic*/
|
||||||
|
#define MAX_DS_FILTER_DELAY 16 /* the additional max resampler filter delay (source fs)*/
|
||||||
|
|
||||||
|
#define CORE_INPUT_OFFSET_PS (0) /* (96-64) makes AAC still some 64 core samples too early wrt SBR ... maybe -32 would be even more correct, but 1024-32 would need additional SBR bitstream delay by one frame */
|
||||||
|
|
||||||
|
class aacPlusEncoder : public AudioEncoder, public virtual Reporter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* A flag to indicate if the encoding session is open.
|
||||||
|
*/
|
||||||
|
bool aacplusOpen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sink to dump aac+ data to
|
||||||
|
*/
|
||||||
|
Ref<Sink> sink;
|
||||||
|
|
||||||
|
float inBuf[(AACENC_BLOCKSIZE*2 + MAX_DS_FILTER_DELAY + INPUT_DELAY)*MAX_CHANNELS];
|
||||||
|
char outBuf[(6144/8)*MAX_CHANNELS+ADTS_HEADER_SIZE];
|
||||||
|
IIR21_RESAMPLER IIR21_reSampler[MAX_CHANNELS];
|
||||||
|
|
||||||
|
AACENC_CONFIG config;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
int nChannelsAAC, nChannelsSBR;
|
||||||
|
unsigned int sampleRateAAC;
|
||||||
|
int bitrate;
|
||||||
|
int bandwidth;
|
||||||
|
|
||||||
|
unsigned int numAncDataBytes;
|
||||||
|
unsigned char ancDataBytes[MAX_PAYLOAD_SIZE];
|
||||||
|
|
||||||
|
int numSamplesRead;
|
||||||
|
int useParametricStereo;
|
||||||
|
int coreWriteOffset;
|
||||||
|
int coreReadOffset;
|
||||||
|
int envReadOffset;
|
||||||
|
int writeOffset;
|
||||||
|
struct AAC_ENCODER *aacEnc;
|
||||||
|
unsigned int inSamples;
|
||||||
|
unsigned int writtenSamples;
|
||||||
|
|
||||||
|
HANDLE_SBR_ENCODER hEnvEnc;
|
||||||
|
sbrConfiguration sbrConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the object.
|
||||||
|
*
|
||||||
|
* @param sink the sink to send mp3 output to
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline void
|
||||||
|
init ( Sink * sink) throw (Exception)
|
||||||
|
{
|
||||||
|
this->aacplusOpen = false;
|
||||||
|
this->sink = sink;
|
||||||
|
|
||||||
|
/* TODO: if we have float as input, we don't need conversion */
|
||||||
|
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 32 ) {
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"specified bits per sample not supported",
|
||||||
|
getInBitsPerSample() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( getInChannel() != 2 ) {
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"unsupported number of input channels for the encoder",
|
||||||
|
getInChannel() );
|
||||||
|
}
|
||||||
|
if ( getOutChannel() != 2 ) {
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"unsupported number of output channels for the encoder",
|
||||||
|
getOutChannel() );
|
||||||
|
}
|
||||||
|
/* TODO: this will be neede when we implement mono aac+ encoding */
|
||||||
|
if ( getInChannel() != getOutChannel() ) {
|
||||||
|
throw Exception( __FILE__, __LINE__,
|
||||||
|
"input channels and output channels do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
bitrate = getOutBitrate() * 1000;
|
||||||
|
bandwidth = 0;
|
||||||
|
useParametricStereo = 0;
|
||||||
|
numAncDataBytes=0;
|
||||||
|
coreWriteOffset = 0;
|
||||||
|
coreReadOffset = 0;
|
||||||
|
envReadOffset = 0;
|
||||||
|
writeOffset = INPUT_DELAY*MAX_CHANNELS;
|
||||||
|
writtenSamples = 0;
|
||||||
|
aacEnc = NULL;
|
||||||
|
hEnvEnc=NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* De-initialize the object.
|
||||||
|
*
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline void
|
||||||
|
strip ( void ) throw ( Exception )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor. Always throws an Exception.
|
||||||
|
*
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
aacPlusEncoder ( void ) throw ( Exception )
|
||||||
|
{
|
||||||
|
throw Exception( __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param sink the sink to send mp3 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 outQuality the quality of the stream.
|
||||||
|
* @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.
|
||||||
|
* @param lowpass frequency threshold for the lowpass filter.
|
||||||
|
* Input above this frequency is cut.
|
||||||
|
* If 0, aacplus's default values are used,
|
||||||
|
* which depends on the out sample rate.
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
aacPlusEncoder ( Sink * sink,
|
||||||
|
unsigned int inSampleRate,
|
||||||
|
unsigned int inBitsPerSample,
|
||||||
|
unsigned int inChannel,
|
||||||
|
bool inBigEndian,
|
||||||
|
BitrateMode outBitrateMode,
|
||||||
|
unsigned int outBitrate,
|
||||||
|
double outQuality,
|
||||||
|
unsigned int outSampleRate = 0,
|
||||||
|
unsigned int outChannel = 0,
|
||||||
|
int lowpass = 0)
|
||||||
|
throw ( Exception )
|
||||||
|
|
||||||
|
: AudioEncoder ( sink,
|
||||||
|
inSampleRate,
|
||||||
|
inBitsPerSample,
|
||||||
|
inChannel,
|
||||||
|
inBigEndian,
|
||||||
|
outBitrateMode,
|
||||||
|
outBitrate,
|
||||||
|
outQuality,
|
||||||
|
outSampleRate,
|
||||||
|
outChannel )
|
||||||
|
{
|
||||||
|
init( sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param sink the sink to send mp3 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 outQuality the quality of the stream.
|
||||||
|
* @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.
|
||||||
|
* @param lowpass frequency threshold for the lowpass filter.
|
||||||
|
* Input above this frequency is cut.
|
||||||
|
* If 0, aacplus's default values are used,
|
||||||
|
* which depends on the out sample rate.
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
aacPlusEncoder ( Sink * sink,
|
||||||
|
const AudioSource * as,
|
||||||
|
BitrateMode outBitrateMode,
|
||||||
|
unsigned int outBitrate,
|
||||||
|
double outQuality,
|
||||||
|
unsigned int outSampleRate = 0,
|
||||||
|
unsigned int outChannel = 0,
|
||||||
|
int lowpass = 0)
|
||||||
|
throw ( Exception )
|
||||||
|
|
||||||
|
: AudioEncoder ( sink,
|
||||||
|
as,
|
||||||
|
outBitrateMode,
|
||||||
|
outBitrate,
|
||||||
|
outQuality,
|
||||||
|
outSampleRate,
|
||||||
|
outChannel )
|
||||||
|
{
|
||||||
|
init( sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor.
|
||||||
|
*
|
||||||
|
* @param encoder the aacPlusEncoder to copy.
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
aacPlusEncoder ( const aacPlusEncoder & encoder )
|
||||||
|
throw ( Exception )
|
||||||
|
: AudioEncoder( encoder )
|
||||||
|
{
|
||||||
|
init( encoder.sink.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline virtual
|
||||||
|
~aacPlusEncoder ( void ) throw ( Exception )
|
||||||
|
{
|
||||||
|
if ( isOpen() ) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
strip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assignment operator.
|
||||||
|
*
|
||||||
|
* @param encoder the aacPlusEncoder to assign this to.
|
||||||
|
* @return a reference to this aacPlusEncoder.
|
||||||
|
* @exception Exception
|
||||||
|
*/
|
||||||
|
inline virtual aacPlusEncoder &
|
||||||
|
operator= ( const aacPlusEncoder & encoder ) throw ( Exception )
|
||||||
|
{
|
||||||
|
if ( this != &encoder ) {
|
||||||
|
strip();
|
||||||
|
AudioEncoder::operator=( encoder);
|
||||||
|
init( encoder.sink.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version string of the underlying aacplus library.
|
||||||
|
*
|
||||||
|
* @return the version string of the underlying aacplus library.
|
||||||
|
*/
|
||||||
|
inline const char *
|
||||||
|
getAacPlusVersion( void )
|
||||||
|
{
|
||||||
|
char * id;
|
||||||
|
//char * copyright;
|
||||||
|
|
||||||
|
/* aacplusEncGetVersion(&id, ©right); */
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 aacplusOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 /* AACP_ENCODER_H */
|
||||||
|
|
Loading…
Reference in New Issue