From ccedfb12207eef0ead392d876f42261512c42aa0 Mon Sep 17 00:00:00 2001 From: "diniz@wimobilis.com.br" Date: Sun, 21 Jun 2009 04:36:30 +0000 Subject: [PATCH] branch darkice-aacp merged --- darkice/trunk/AUTHORS | 2 +- darkice/trunk/ChangeLog | 5 +- darkice/trunk/configure.in | 37 ++- darkice/trunk/man/darkice.1 | 6 + darkice/trunk/man/darkice.cfg.5 | 4 +- darkice/trunk/src/DarkIce.cpp | 49 ++- darkice/trunk/src/IceCast2.cpp | 4 + darkice/trunk/src/IceCast2.h | 2 +- darkice/trunk/src/Makefile.am | 6 +- darkice/trunk/src/TcpSocket.cpp | 13 +- darkice/trunk/src/aacPlusEncoder.cpp | 301 +++++++++++++++++ darkice/trunk/src/aacPlusEncoder.h | 474 +++++++++++++++++++++++++++ 12 files changed, 893 insertions(+), 10 deletions(-) create mode 100644 darkice/trunk/src/aacPlusEncoder.cpp create mode 100644 darkice/trunk/src/aacPlusEncoder.h diff --git a/darkice/trunk/AUTHORS b/darkice/trunk/AUTHORS index 9f01250..15a2f9d 100644 --- a/darkice/trunk/AUTHORS +++ b/darkice/trunk/AUTHORS @@ -35,4 +35,4 @@ with contributions by: Daniel Hazelbaker Alessandro Beretta Roland Hermans - + Rafael Diniz diff --git a/darkice/trunk/ChangeLog b/darkice/trunk/ChangeLog index 27aff4f..c83a0ed 100644 --- a/darkice/trunk/ChangeLog +++ b/darkice/trunk/ChangeLog @@ -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 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, diff --git a/darkice/trunk/configure.in b/darkice/trunk/configure.in index 0d4b138..af4c56d 100644 --- a/darkice/trunk/configure.in +++ b/darkice/trunk/configure.in @@ -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 diff --git a/darkice/trunk/man/darkice.1 b/darkice/trunk/man/darkice.1 index 6c59eb3..b780400 100644 --- a/darkice/trunk/man/darkice.1 +++ b/darkice/trunk/man/darkice.1 @@ -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 Alessandro Beretta Roland Hermans + Rafael Diniz .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 diff --git a/darkice/trunk/man/darkice.cfg.5 b/darkice/trunk/man/darkice.cfg.5 index fd1e018..0ab4be0 100644 --- a/darkice/trunk/man/darkice.cfg.5 +++ b/darkice/trunk/man/darkice.cfg.5 @@ -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", diff --git a/darkice/trunk/src/DarkIce.cpp b/darkice/trunk/src/DarkIce.cpp index 28796bb..0438473 100644 --- a/darkice/trunk/src/DarkIce.cpp +++ b/darkice/trunk/src/DarkIce.cpp @@ -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); diff --git a/darkice/trunk/src/IceCast2.cpp b/darkice/trunk/src/IceCast2.cpp index 917e50e..b1469fb 100644 --- a/darkice/trunk/src/IceCast2.cpp +++ b/darkice/trunk/src/IceCast2.cpp @@ -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); diff --git a/darkice/trunk/src/IceCast2.h b/darkice/trunk/src/IceCast2.h index a1d54a8..483e749 100644 --- a/darkice/trunk/src/IceCast2.h +++ b/darkice/trunk/src/IceCast2.h @@ -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: diff --git a/darkice/trunk/src/Makefile.am b/darkice/trunk/src/Makefile.am index 502f2f7..b718b54 100644 --- a/darkice/trunk/src/Makefile.am +++ b/darkice/trunk/src/Makefile.am @@ -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\ diff --git a/darkice/trunk/src/TcpSocket.cpp b/darkice/trunk/src/TcpSocket.cpp index 745d08b..28046f4 100644 --- a/darkice/trunk/src/TcpSocket.cpp +++ b/darkice/trunk/src/TcpSocket.cpp @@ -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,7 +318,9 @@ TcpSocket :: read ( void * buf, break; default: - throw Exception( __FILE__, __LINE__, "recv error", errno); + ::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); } } diff --git a/darkice/trunk/src/aacPlusEncoder.cpp b/darkice/trunk/src/aacPlusEncoder.cpp new file mode 100644 index 0000000..9b71ccb --- /dev/null +++ b/darkice/trunk/src/aacPlusEncoder.cpp @@ -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; iwrite(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 diff --git a/darkice/trunk/src/aacPlusEncoder.h b/darkice/trunk/src/aacPlusEncoder.h new file mode 100644 index 0000000..dff56c9 --- /dev/null +++ b/darkice/trunk/src/aacPlusEncoder.h @@ -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 +#include +#include +#include + +#include + +#include +#include +#include +} +#else +#error configure with aacplus +#endif + +#include +#include + +#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; + + 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 */ +