branch darkice-aacp merged
This commit is contained in:
parent
51c76638a1
commit
ccedfb1220
|
@ -35,4 +35,4 @@ with contributions by:
|
|||
Daniel Hazelbaker <daniel@highdesertchurch.com>
|
||||
Alessandro Beretta <alessandro.baretta@radiomaria.org>
|
||||
Roland Hermans <roland.hermans@omroepvenray.nl>
|
||||
|
||||
Rafael Diniz <rafael@riseup.net>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
DarkIce next release
|
||||
|
||||
o added AAC HEv2 encoding support (branch darkice-aacp merged) through
|
||||
libaacplus, http://tipok.org.ua/ru/node/17
|
||||
thanks to tipok <piratfm@gmail.com> and others for the contribution.
|
||||
o bugfix: the configure script recognizes Ogg Vorbis shared objects
|
||||
now, not just static libraries. Thanks to omroepvenray.
|
||||
o bugfix: enabling jack source compilation on Debian Lenny,
|
||||
|
|
|
@ -149,6 +149,40 @@ else
|
|||
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"
|
||||
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 link the twolame library if requested
|
||||
dnl-----------------------------------------------------------------------------
|
||||
|
@ -189,8 +223,9 @@ dnl-----------------------------------------------------------------------------
|
|||
if test "x${LAME_LDFLAGS}" = "x" \
|
||||
-a "x${VORBIS_LDFLAGS}" = "x" \
|
||||
-a "x${FAAC_LDFLAGS}" = "x" \
|
||||
-a "x${AACPLUS_LDFLAGS}" = "x" \
|
||||
-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
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ DarkIce can encode in the following formats:
|
|||
* mp2 - using the twolame library
|
||||
* Ogg Vorbis
|
||||
* AAC - using the faac library
|
||||
* AAC HEv2 - using the libaacplus (3GPP reference code)
|
||||
|
||||
DarkIce can send the encoded stream to the following streaming servers:
|
||||
|
||||
|
@ -109,6 +110,7 @@ Developed with contributions by
|
|||
Daniel Hazelbaker <daniel@highdesertchurch.com>
|
||||
Alessandro Beretta <alessandro.baretta@radiomaria.org>
|
||||
Roland Hermans <roland.hermans@omroepvenray.nl>
|
||||
Rafael Diniz <rafael@riseup.net>
|
||||
|
||||
.SH LINKS
|
||||
Project homepage:
|
||||
|
@ -142,6 +144,10 @@ homepage:
|
|||
homepage:
|
||||
.I http://www.audiocoding.com/
|
||||
|
||||
.B libaacplus
|
||||
homepage:
|
||||
.I http://tipok.org.ua/node/17
|
||||
|
||||
.B DarkSnow
|
||||
GTK front-end:
|
||||
.I http://darksnow.radiolivre.org/index.en.html
|
||||
|
|
|
@ -228,7 +228,7 @@ Required values:
|
|||
.I format
|
||||
Format of the stream sent to the
|
||||
.B IceCast2
|
||||
server. Supported formats are 'vorbis', 'mp3', 'mp2' and 'aac'.
|
||||
server. Supported formats are 'vorbis', 'mp3', 'mp2', 'aac' and 'aacp'.
|
||||
.TP
|
||||
.I bitrateMode
|
||||
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
|
||||
|
@ -444,7 +444,7 @@ Required values:
|
|||
|
||||
.TP
|
||||
.I format
|
||||
Format to encode in. Must be either 'mp3', 'vorbis' or 'aac'.
|
||||
Format to encode in. Must be either 'mp3', 'mp2', 'vorbis', 'aac' or 'aacp'.
|
||||
.TP
|
||||
.I bitrateMode
|
||||
The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
|
||||
|
|
|
@ -96,6 +96,10 @@
|
|||
#include "FaacEncoder.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AACPLUS_LIB
|
||||
#include "aacPlusEncoder.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* =================================================== local data structures */
|
||||
|
||||
|
@ -454,6 +458,8 @@ DarkIce :: configIceCast2 ( const Config & config,
|
|||
format = IceCast2::mp2;
|
||||
} else if ( Util::strEq( str, "aac") ) {
|
||||
format = IceCast2::aac;
|
||||
} else if ( Util::strEq( str, "aacp") ) {
|
||||
format = IceCast2::aacp;
|
||||
} else {
|
||||
throw Exception( __FILE__, __LINE__,
|
||||
"unsupported stream format: ", str);
|
||||
|
@ -643,6 +649,24 @@ DarkIce :: configIceCast2 ( const Config & config,
|
|||
#endif // HAVE_FAAC_LIB
|
||||
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,
|
||||
channel );
|
||||
#endif // HAVE_AACPLUS_LIB
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Exception( __FILE__, __LINE__,
|
||||
"Illegal stream format: ", format);
|
||||
|
@ -878,7 +902,8 @@ DarkIce :: configFileCast ( const Config & config )
|
|||
if ( !Util::strEq( format, "vorbis")
|
||||
&& !Util::strEq( format, "mp3")
|
||||
&& !Util::strEq( format, "mp2")
|
||||
&& !Util::strEq( format, "aac") ) {
|
||||
&& !Util::strEq( format, "aac")
|
||||
&& !Util::strEq( format, "aacp") ) {
|
||||
throw Exception( __FILE__, __LINE__,
|
||||
"unsupported stream format: ", format);
|
||||
}
|
||||
|
@ -936,6 +961,12 @@ DarkIce :: configFileCast ( const Config & config )
|
|||
"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");
|
||||
lowpass = str ? Util::strToL( str) : 0;
|
||||
str = cs->get( "highpass");
|
||||
|
@ -1031,6 +1062,22 @@ DarkIce :: configFileCast ( const Config & config )
|
|||
sampleRate,
|
||||
dsp->getChannel());
|
||||
#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 {
|
||||
throw Exception( __FILE__, __LINE__,
|
||||
"Illegal stream format: ", format);
|
||||
|
|
|
@ -161,6 +161,10 @@ IceCast2 :: sendLogin ( void ) throw ( Exception )
|
|||
str = "audio/aac";
|
||||
break;
|
||||
|
||||
case aacp:
|
||||
str = "audio/aacp";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Exception( __FILE__, __LINE__,
|
||||
"unsupported stream format", format);
|
||||
|
|
|
@ -63,7 +63,7 @@ class IceCast2 : public CastSink
|
|||
/**
|
||||
* Type for specifying the format of the stream.
|
||||
*/
|
||||
enum StreamFormat { mp3, mp2, oggVorbis, aac };
|
||||
enum StreamFormat { mp3, mp2, oggVorbis, aac, aacp };
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
bin_PROGRAMS = darkice
|
||||
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
|
||||
@JACK_CFLAGS@
|
||||
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@
|
||||
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @TWOLAME_LDFLAGS@ \
|
||||
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@
|
||||
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \
|
||||
@ALSA_LDFLAGS@ @JACK_LDFLAGS@
|
||||
|
||||
darkice_SOURCES = AudioEncoder.h\
|
||||
|
@ -38,6 +38,8 @@ darkice_SOURCES = AudioEncoder.h\
|
|||
VorbisLibEncoder.h\
|
||||
FaacEncoder.cpp\
|
||||
FaacEncoder.h\
|
||||
aacPlusEncoder.cpp\
|
||||
aacPlusEncoder.h\
|
||||
aflibDebug.h\
|
||||
aflibDebug.cc\
|
||||
aflibConverter.h\
|
||||
|
|
|
@ -215,12 +215,14 @@ TcpSocket :: open ( void ) throw ( Exception )
|
|||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
|
||||
if (getaddrinfo(host , portstr, &hints, &ptr)) {
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno);
|
||||
}
|
||||
memcpy ( addr, ptr->ai_addr, ptr->ai_addrlen);
|
||||
freeaddrinfo(ptr);
|
||||
#else
|
||||
if ( !(pHostEntry = gethostbyname( host)) ) {
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "gethostbyname error", errno);
|
||||
}
|
||||
|
||||
|
@ -231,6 +233,7 @@ TcpSocket :: open ( void ) throw ( Exception )
|
|||
#endif
|
||||
|
||||
if ( (sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "socket error", errno);
|
||||
}
|
||||
|
||||
|
@ -281,6 +284,8 @@ TcpSocket :: canRead ( unsigned int sec,
|
|||
ret = pselect( sockfd + 1, &fdset, NULL, NULL, ×pec, &sigset);
|
||||
|
||||
if ( ret == -1 ) {
|
||||
::close( sockfd);
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "select error");
|
||||
}
|
||||
|
||||
|
@ -313,6 +318,8 @@ TcpSocket :: read ( void * buf,
|
|||
break;
|
||||
|
||||
default:
|
||||
::close( sockfd);
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "recv error", errno);
|
||||
}
|
||||
}
|
||||
|
@ -350,6 +357,8 @@ TcpSocket :: canWrite ( unsigned int sec,
|
|||
ret = pselect( sockfd + 1, NULL, &fdset, NULL, ×pec, &sigset);
|
||||
|
||||
if ( ret == -1 ) {
|
||||
::close( sockfd);
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "select error");
|
||||
}
|
||||
|
||||
|
@ -380,6 +389,8 @@ TcpSocket :: write ( const void * buf,
|
|||
if ( errno == EAGAIN ) {
|
||||
ret = 0;
|
||||
} else {
|
||||
::close( sockfd);
|
||||
sockfd = 0;
|
||||
throw Exception( __FILE__, __LINE__, "send error", errno);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,301 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2005 Tyrell Corporation. All rights reserved.
|
||||
|
||||
Tyrell DarkIce
|
||||
|
||||
File : aacPlusEncoder.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 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$";
|
||||
|
||||
|
||||
/* =============================================== 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");
|
||||
|
||||
bitrate = getOutBitrate() * 1000;
|
||||
bandwidth = 0;
|
||||
useParametricStereo = 0;
|
||||
numAncDataBytes=0;
|
||||
coreWriteOffset = 0;
|
||||
envReadOffset = 0;
|
||||
writeOffset = INPUT_DELAY*MAX_CHANNELS;
|
||||
writtenSamples = 0;
|
||||
aacEnc = NULL;
|
||||
hEnvEnc=NULL;
|
||||
|
||||
/* 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 (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, "nChannelsOut", getOutChannel());
|
||||
reportEvent(10, "nChannelsSBR", nChannelsSBR);
|
||||
reportEvent(10, "nChannelsAAC", 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;
|
||||
unsigned int samples = (unsigned int) nSamples * channels;
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned int i;
|
||||
int ch, outSamples, numOutBytes;
|
||||
|
||||
|
||||
reportEvent(10, "converting short to float");
|
||||
short *TimeDataPcm = (short *) buf;
|
||||
|
||||
if(channels == 2) {
|
||||
for (i=0; i<samples; i++)
|
||||
inBuf[i+writeOffset+writtenSamples] = (float) TimeDataPcm[i];
|
||||
} else {
|
||||
/* using only left channel buffer for mono encoder */
|
||||
for (i=0; i<samples; i++)
|
||||
inBuf[writeOffset+2*writtenSamples+2*i] = (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/channels,
|
||||
MAX_CHANNELS,
|
||||
inBuf+ch,
|
||||
&outSamples,
|
||||
MAX_CHANNELS);
|
||||
|
||||
reportEvent(10, "outSamples=", outSamples);
|
||||
}
|
||||
|
||||
/* encode one AAC frame */
|
||||
reportEvent(10, "encode one AAC frame");
|
||||
AacEncEncode( aacEnc,
|
||||
inBuf,
|
||||
useParametricStereo ? 1 : MAX_CHANNELS, /* stride (step) */
|
||||
ancDataBytes,
|
||||
&numAncDataBytes,
|
||||
(unsigned *) (outBuf+ADTS_HEADER_SIZE),
|
||||
&numOutBytes);
|
||||
if (useParametricStereo) {
|
||||
memcpy( inBuf,inBuf+AACENC_BLOCKSIZE,CORE_INPUT_OFFSET_PS*sizeof(float));
|
||||
} else {
|
||||
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
|
|
@ -0,0 +1,474 @@
|
|||
/*------------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2000-2007 Tyrell Corporation. All rights reserved.
|
||||
|
||||
Tyrell DarkIce
|
||||
|
||||
File : aacPlusEncoder.h
|
||||
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 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$
|
||||
* @version $Revision$
|
||||
*/
|
||||
|
||||
#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 nChannelsAAC, nChannelsSBR;
|
||||
unsigned int sampleRateAAC;
|
||||
|
||||
int bitrate;
|
||||
int bandwidth;
|
||||
|
||||
unsigned int numAncDataBytes;
|
||||
unsigned char ancDataBytes[MAX_PAYLOAD_SIZE];
|
||||
|
||||
bool useParametricStereo;
|
||||
int coreWriteOffset;
|
||||
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;
|
||||
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