branch darkice-aacp merged

This commit is contained in:
diniz@wimobilis.com.br 2009-06-21 04:36:30 +00:00
parent 51c76638a1
commit ccedfb1220
12 changed files with 893 additions and 10 deletions

View File

@ -35,4 +35,4 @@ with contributions by:
Daniel Hazelbaker <daniel@highdesertchurch.com> Daniel Hazelbaker <daniel@highdesertchurch.com>
Alessandro Beretta <alessandro.baretta@radiomaria.org> Alessandro Beretta <alessandro.baretta@radiomaria.org>
Roland Hermans <roland.hermans@omroepvenray.nl> Roland Hermans <roland.hermans@omroepvenray.nl>
Rafael Diniz <rafael@riseup.net>

View File

@ -1,5 +1,8 @@
DarkIce next release 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 o bugfix: the configure script recognizes Ogg Vorbis shared objects
now, not just static libraries. Thanks to omroepvenray. now, not just static libraries. Thanks to omroepvenray.
o bugfix: enabling jack source compilation on Debian Lenny, o bugfix: enabling jack source compilation on Debian Lenny,

View File

@ -149,6 +149,40 @@ 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"
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 +223,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

View File

@ -20,6 +20,7 @@ DarkIce can encode in the following formats:
* mp2 - using the twolame library * mp2 - using the twolame library
* Ogg Vorbis * Ogg Vorbis
* AAC - using the faac library * AAC - using the faac library
* AAC HEv2 - using the libaacplus (3GPP reference code)
DarkIce can send the encoded stream to the following streaming servers: DarkIce can send the encoded stream to the following streaming servers:
@ -109,6 +110,7 @@ Developed with contributions by
Daniel Hazelbaker <daniel@highdesertchurch.com> Daniel Hazelbaker <daniel@highdesertchurch.com>
Alessandro Beretta <alessandro.baretta@radiomaria.org> Alessandro Beretta <alessandro.baretta@radiomaria.org>
Roland Hermans <roland.hermans@omroepvenray.nl> Roland Hermans <roland.hermans@omroepvenray.nl>
Rafael Diniz <rafael@riseup.net>
.SH LINKS .SH LINKS
Project homepage: Project homepage:
@ -142,6 +144,10 @@ homepage:
homepage: homepage:
.I http://www.audiocoding.com/ .I http://www.audiocoding.com/
.B libaacplus
homepage:
.I http://tipok.org.ua/node/17
.B DarkSnow .B DarkSnow
GTK front-end: GTK front-end:
.I http://darksnow.radiolivre.org/index.en.html .I http://darksnow.radiolivre.org/index.en.html

View File

@ -228,7 +228,7 @@ Required values:
.I format .I format
Format of the stream sent to the Format of the stream sent to the
.B IceCast2 .B IceCast2
server. Supported formats are 'vorbis', 'mp3', 'mp2' and 'aac'. server. Supported formats are 'vorbis', 'mp3', 'mp2', 'aac' and 'aacp'.
.TP .TP
.I bitrateMode .I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr", The bit rate mode of the encoding, either "cbr", "abr" or "vbr",
@ -444,7 +444,7 @@ Required values:
.TP .TP
.I format .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 .TP
.I bitrateMode .I bitrateMode
The bit rate mode of the encoding, either "cbr", "abr" or "vbr", The bit rate mode of the encoding, either "cbr", "abr" or "vbr",

View File

@ -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,
channel );
#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);

View File

@ -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);

View File

@ -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:

View File

@ -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\

View File

@ -215,12 +215,14 @@ TcpSocket :: open ( void ) throw ( Exception )
snprintf(portstr, sizeof(portstr), "%d", port); snprintf(portstr, sizeof(portstr), "%d", port);
if (getaddrinfo(host , portstr, &hints, &ptr)) { if (getaddrinfo(host , portstr, &hints, &ptr)) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno); throw Exception( __FILE__, __LINE__, "getaddrinfo error", errno);
} }
memcpy ( addr, ptr->ai_addr, ptr->ai_addrlen); memcpy ( addr, ptr->ai_addr, ptr->ai_addrlen);
freeaddrinfo(ptr); freeaddrinfo(ptr);
#else #else
if ( !(pHostEntry = gethostbyname( host)) ) { if ( !(pHostEntry = gethostbyname( host)) ) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "gethostbyname error", errno); throw Exception( __FILE__, __LINE__, "gethostbyname error", errno);
} }
@ -231,6 +233,7 @@ TcpSocket :: open ( void ) throw ( Exception )
#endif #endif
if ( (sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) { if ( (sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
sockfd = 0;
throw Exception( __FILE__, __LINE__, "socket error", errno); throw Exception( __FILE__, __LINE__, "socket error", errno);
} }
@ -281,6 +284,8 @@ TcpSocket :: canRead ( unsigned int sec,
ret = pselect( sockfd + 1, &fdset, NULL, NULL, &timespec, &sigset); ret = pselect( sockfd + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");
} }
@ -313,6 +318,8 @@ TcpSocket :: read ( void * buf,
break; break;
default: default:
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "recv error", errno); throw Exception( __FILE__, __LINE__, "recv error", errno);
} }
} }
@ -350,6 +357,8 @@ TcpSocket :: canWrite ( unsigned int sec,
ret = pselect( sockfd + 1, NULL, &fdset, NULL, &timespec, &sigset); ret = pselect( sockfd + 1, NULL, &fdset, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");
} }
@ -380,6 +389,8 @@ TcpSocket :: write ( const void * buf,
if ( errno == EAGAIN ) { if ( errno == EAGAIN ) {
ret = 0; ret = 0;
} else { } else {
::close( sockfd);
sockfd = 0;
throw Exception( __FILE__, __LINE__, "send error", errno); throw Exception( __FILE__, __LINE__, "send error", errno);
} }
} }

View File

@ -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

View File

@ -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, &copyright); */
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 */