summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorritsuka <[email protected]>2009-05-23 09:46:36 +0000
committerritsuka <[email protected]>2009-05-23 09:46:36 +0000
commit9cd4b18874948ed58b5724de086338eb3c036b07 (patch)
tree4de94af339e96401dc4c77d0741643a0cb0ed82e /libhb
parent8690c484f325fab8335f8a87a10406726994961d (diff)
- Add CoreAudio AAC as one of the encoder on Mac OS X.
- Remove hb_init() and hb_init_express() macro. Rename hb_init_real() to hb_init() - Add two more bitrate combination for audio codecs in common.h git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2441 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r--libhb/common.c4
-rw-r--r--libhb/common.h2
-rw-r--r--libhb/hb.c39
-rw-r--r--libhb/hb.h44
-rw-r--r--libhb/internal.h3
-rw-r--r--libhb/module.defs1
-rw-r--r--libhb/muxmkv.c1
-rw-r--r--libhb/platform/macosx/encca_aac.c341
-rw-r--r--libhb/work.c6
9 files changed, 386 insertions, 55 deletions
diff --git a/libhb/common.c b/libhb/common.c
index 88a8ea8ec..b84f907ab 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -31,7 +31,8 @@ hb_rate_t hb_audio_bitrates[] =
{ { "32", 32 }, { "40", 40 }, { "48", 48 }, { "56", 56 },
{ "64", 64 }, { "80", 80 }, { "96", 96 }, { "112", 112 },
{ "128", 128 }, { "160", 160 }, { "192", 192 }, { "224", 224 },
- { "256", 256 }, { "320", 320 }, { "384", 384 } };
+ { "256", 256 }, { "320", 320 }, { "384", 384 }, { "448", 448 }
+ { "768", 768 } };
int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) /
sizeof( hb_rate_t );
int hb_audio_bitrates_default = 8; /* 128 kbps */
@@ -227,6 +228,7 @@ int hb_calc_bitrate( hb_job_t * job, int size )
switch( audio->config.out.codec )
{
case HB_ACODEC_FAAC:
+ case HB_ACODEC_CA_AAC:
case HB_ACODEC_VORBIS:
samples_per_frame = 1024;
break;
diff --git a/libhb/common.h b/libhb/common.h
index 224b40c78..d7649f4c9 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -286,6 +286,7 @@ struct hb_job_s
#define HB_ACODEC_LPCM 0x002000
#define HB_ACODEC_DCA 0x004000
#define HB_ACODEC_FFMPEG 0x008000
+#define HB_ACODEC_CA_AAC 0x010000
/* Audio Mixdown */
/* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */
@@ -675,6 +676,7 @@ extern hb_work_object_t hb_declpcm;
extern hb_work_object_t hb_encfaac;
extern hb_work_object_t hb_enclame;
extern hb_work_object_t hb_encvorbis;
+extern hb_work_object_t hb_encca_aac;
#define FILTER_OK 0
#define FILTER_DELAY 1
diff --git a/libhb/hb.c b/libhb/hb.c
index 661e1df47..4f484208d 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -86,7 +86,7 @@ void hb_register( hb_work_object_t * w )
* @param update_check signals libhb to check for updated version from HandBrake website.
* @return Handle to hb_handle_t for use on all subsequent calls to libhb.
*/
-hb_handle_t * hb_init_real( int verbose, int update_check )
+hb_handle_t * hb_init( int verbose, int update_check )
{
hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 );
uint64_t date;
@@ -150,11 +150,31 @@ hb_handle_t * hb_init_real( int verbose, int update_check )
h->die = 0;
h->main_thread = hb_thread_init( "libhb", thread_func, h,
HB_NORMAL_PRIORITY );
+ hb_register( &hb_sync );
+ hb_register( &hb_decmpeg2 );
+ hb_register( &hb_decvobsub );
+ hb_register( &hb_encvobsub );
+ hb_register( &hb_deccc608 );
+ hb_register( &hb_render );
+ hb_register( &hb_encavcodec );
+ hb_register( &hb_encxvid );
+ hb_register( &hb_encx264 );
+ hb_register( &hb_enctheora );
+ hb_register( &hb_deca52 );
+ hb_register( &hb_decdca );
+ hb_register( &hb_decavcodec );
+ hb_register( &hb_decavcodecv );
+ hb_register( &hb_decavcodecvi );
+ hb_register( &hb_decavcodecai );
+ hb_register( &hb_declpcm );
+ hb_register( &hb_encfaac );
+ hb_register( &hb_enclame );
+ hb_register( &hb_encvorbis );
+#ifdef __APPLE__
+ hb_register( &hb_encca_aac );
+#endif
return h;
-
- /* Set the scan count to start at 0 */
- //scan_count = 0;
}
/**
@@ -230,13 +250,13 @@ hb_handle_t * hb_init_dl( int verbose, int update_check )
hb_register( &hb_sync );
hb_register( &hb_decmpeg2 );
hb_register( &hb_decvobsub );
- hb_register( &hb_encvobsub );
- hb_register( &hb_deccc608 );
+ hb_register( &hb_encvobsub );
+ hb_register( &hb_deccc608 );
hb_register( &hb_render );
hb_register( &hb_encavcodec );
hb_register( &hb_encxvid );
hb_register( &hb_encx264 );
- hb_register( &hb_enctheora );
+ hb_register( &hb_enctheora );
hb_register( &hb_deca52 );
hb_register( &hb_decdca );
hb_register( &hb_decavcodec );
@@ -247,6 +267,9 @@ hb_handle_t * hb_init_dl( int verbose, int update_check )
hb_register( &hb_encfaac );
hb_register( &hb_enclame );
hb_register( &hb_encvorbis );
+#ifdef __APPLE__
+ hb_register( &hb_encca_aac );
+#endif
return h;
}
@@ -1301,7 +1324,7 @@ int hb_get_scancount( hb_handle_t * h)
}
/**
- * Closes access to libhb by freeing the hb_handle_t handle ontained in hb_init_real.
+ * Closes access to libhb by freeing the hb_handle_t handle ontained in hb_init.
* @param _h Pointer to handle to hb_handle_t.
*/
void hb_close( hb_handle_t ** _h )
diff --git a/libhb/hb.h b/libhb/hb.h
index 3cf308e3a..cc7a7eecc 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -14,51 +14,9 @@ extern "C" {
#define HB_DEBUG_NONE 0
#define HB_DEBUG_ALL 1
void hb_register( hb_work_object_t * );
-hb_handle_t * hb_init_real( int verbose, int update_check );
+hb_handle_t * hb_init( int verbose, int update_check );
hb_handle_t * hb_init_dl ( int verbose, int update_check ); // hb_init for use with dylib
-#define hb_init(v,u) \
-hb_init_real( v, u ); \
-hb_register( &hb_sync ); \
-hb_register( &hb_decmpeg2 ); \
-hb_register( &hb_decvobsub ); \
-hb_register( &hb_encvobsub ); \
-hb_register( &hb_deccc608 ); \
-hb_register( &hb_render ); \
-hb_register( &hb_encavcodec ); \
-hb_register( &hb_encxvid ); \
-hb_register( &hb_encx264 ); \
-hb_register( &hb_enctheora ); \
-hb_register( &hb_deca52 ); \
-hb_register( &hb_decdca ); \
-hb_register( &hb_decavcodec ); \
-hb_register( &hb_decavcodecv ); \
-hb_register( &hb_decavcodecvi ); \
-hb_register( &hb_decavcodecai ); \
-hb_register( &hb_declpcm ); \
-hb_register( &hb_encfaac ); \
-hb_register( &hb_enclame ); \
-hb_register( &hb_encvorbis ); \
-
-#define hb_init_express(v,u) \
-hb_init_real( v, u ); \
-hb_register( &hb_sync ); \
-hb_register( &hb_decmpeg2 ); \
-hb_register( &hb_decvobsub ); \
-hb_register( &hb_encvobsub ); \
-hb_register( &hb_deccc608 ); \
-hb_register( &hb_render ); \
-hb_register( &hb_encavcodec ); \
-hb_register( &hb_encx264 ); \
-hb_register( &hb_deca52 ); \
-hb_register( &hb_decdca ); \
-hb_register( &hb_decavcodec ); \
-hb_register( &hb_decavcodecv ); \
-hb_register( &hb_decavcodecvi ); \
-hb_register( &hb_decavcodecai ); \
-hb_register( &hb_declpcm ); \
-hb_register( &hb_encfaac ); \
-
/* hb_get_version() */
char * hb_get_version( hb_handle_t * );
int hb_get_build( hb_handle_t * );
diff --git a/libhb/internal.h b/libhb/internal.h
index b05e50a48..1e5afdc1f 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -271,7 +271,8 @@ enum
WORK_DECLPCM,
WORK_ENCFAAC,
WORK_ENCLAME,
- WORK_ENCVORBIS
+ WORK_ENCVORBIS,
+ WORK_ENC_CA_AAC
};
enum
diff --git a/libhb/module.defs b/libhb/module.defs
index 725ebc116..e5ecf9722 100644
--- a/libhb/module.defs
+++ b/libhb/module.defs
@@ -41,6 +41,7 @@ ifeq ($(BUILD.system),cygwin)
LIBHB.GCC.D += SYS_CYGWIN
else ifeq ($(BUILD.system),darwin)
LIBHB.GCC.D += SYS_DARWIN
+ LIBHB.c += $(wildcard $(LIBHB.src/)platform/macosx/*.c)
else ifeq ($(BUILD.system),linux)
LIBHB.GCC.D += SYS_LINUX _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64
else ifeq ($(BUILD.system),mingw)
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index 04f9ae595..6a8a55cbe 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -226,6 +226,7 @@ static int MKVInit( hb_mux_object_t * m )
}
break;
case HB_ACODEC_FAAC:
+ case HB_ACODEC_CA_AAC:
track->codecPrivate = audio->priv.config.aac.bytes;
track->codecPrivateSize = audio->priv.config.aac.length;
track->codecID = MK_ACODEC_AAC;
diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c
new file mode 100644
index 000000000..69b29ec4b
--- /dev/null
+++ b/libhb/platform/macosx/encca_aac.c
@@ -0,0 +1,341 @@
+/* This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#include "hb.h"
+#include <AudioToolbox/AudioToolbox.h>
+#include <CoreAudio/CoreAudio.h>
+
+int encCoreAudioInit( hb_work_object_t *, hb_job_t * );
+int encCoreAudioWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+void encCoreAudioClose( hb_work_object_t * );
+
+hb_work_object_t hb_encca_aac =
+{
+ WORK_ENC_CA_AAC,
+ "AAC encoder (Apple)",
+ encCoreAudioInit,
+ encCoreAudioWork,
+ encCoreAudioClose
+};
+
+struct hb_work_private_s
+{
+ hb_job_t *job;
+
+ AudioConverterRef converter;
+ uint8_t *obuf;
+ uint8_t *buf;
+ hb_list_t *list;
+ unsigned long isamples, isamplesiz, omaxpacket, nchannels;
+ uint64_t pts, ibytes;
+};
+
+#define MP4ESDescrTag 0x03
+#define MP4DecConfigDescrTag 0x04
+#define MP4DecSpecificDescrTag 0x05
+
+// based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
+static int readDescrLen(UInt8 **buffer)
+{
+ int len = 0;
+ int count = 4;
+ while (count--) {
+ int c = *(*buffer)++;
+ len = (len << 7) | (c & 0x7f);
+ if (!(c & 0x80))
+ break;
+ }
+ return len;
+}
+
+// based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
+static int readDescr(UInt8 **buffer, int *tag)
+{
+ *tag = *(*buffer)++;
+ return readDescrLen(buffer);
+}
+
+// based off of mov_read_esds from mov.c in ffmpeg's libavformat
+static long ReadESDSDescExt(void* descExt, UInt8 **buffer, int *size, int versionFlags)
+{
+ UInt8 *esds = (UInt8 *) descExt;
+ int tag, len;
+ *size = 0;
+
+ if (versionFlags)
+ esds += 4; // version + flags
+ readDescr(&esds, &tag);
+ esds += 2; // ID
+ if (tag == MP4ESDescrTag)
+ esds++; // priority
+
+ readDescr(&esds, &tag);
+ if (tag == MP4DecConfigDescrTag) {
+ esds++; // object type id
+ esds++; // stream type
+ esds += 3; // buffer size db
+ esds += 4; // max bitrate
+ esds += 4; // average bitrate
+
+ len = readDescr(&esds, &tag);
+ if (tag == MP4DecSpecificDescrTag) {
+ *buffer = calloc(1, len + 8);
+ if (*buffer) {
+ memcpy(*buffer, esds, len);
+ *size = len;
+ }
+ }
+ }
+
+ return noErr;
+}
+
+/***********************************************************************
+ * hb_work_encCoreAudio_init
+ ***********************************************************************
+ *
+ **********************************************************************/
+int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job )
+{
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
+ hb_audio_t * audio = w->audio;
+ AudioStreamBasicDescription input, output;
+ UInt32 tmp, tmpsiz = sizeof( tmp );
+ OSStatus err;
+
+ w->private_data = pv;
+ pv->job = job;
+
+ // pass the number of channels used into the private work data
+ pv->nchannels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( audio->config.out.mixdown );
+
+ bzero( &input, sizeof( AudioStreamBasicDescription ) );
+ input.mSampleRate = ( Float64 ) audio->config.out.samplerate;
+ input.mFormatID = kAudioFormatLinearPCM;
+ input.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian;
+ input.mBytesPerPacket = 4 * pv->nchannels;
+ input.mFramesPerPacket = 1;
+ input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket;
+ input.mChannelsPerFrame = pv->nchannels;
+ input.mBitsPerChannel = 32;
+
+ bzero( &output, sizeof( AudioStreamBasicDescription ) );
+ output.mSampleRate = ( Float64 ) audio->config.out.samplerate;
+ output.mFormatID = kAudioFormatMPEG4AAC;
+ output.mChannelsPerFrame = pv->nchannels;
+ // let CoreAudio decide the rest...
+
+ // initialise encoder
+ err = AudioConverterNew( &input, &output, &pv->converter );
+ if( err != noErr)
+ {
+ hb_log( "Error creating an AudioConverter %x %d", err, output.mBytesPerFrame );
+ *job->die = 1;
+ return 0;
+ }
+
+ if( audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3 )
+ {
+ SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 };
+ AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap,
+ sizeof( channelMap ), channelMap );
+ }
+
+ // set encoder quality to maximum
+ tmp = kAudioConverterQuality_Max;
+ AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality,
+ sizeof( tmp ), &tmp );
+
+ // set encoder bitrate control mode to constrained variable
+ tmp = kAudioCodecBitRateControlMode_VariableConstrained;
+ AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode,
+ sizeof( tmp ), &tmp );
+
+ // get available bitrates
+ AudioValueRange *bitrates;
+ ssize_t bitrateCounts, n;
+ err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates,
+ &tmpsiz, NULL);
+ bitrates = malloc( tmpsiz );
+ err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates,
+ &tmpsiz, bitrates);
+ bitrateCounts = tmpsiz / sizeof( AudioValueRange );
+
+ // set bitrate
+ tmp = audio->config.out.bitrate * 1000;
+ if( tmp < bitrates[0].mMinimum )
+ tmp = bitrates[0].mMinimum;
+ if( tmp > bitrates[bitrateCounts-1].mMinimum )
+ tmp = bitrates[bitrateCounts-1].mMinimum;
+ free( bitrates );
+ AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate,
+ sizeof( tmp ), &tmp );
+
+ // get real input
+ tmpsiz = sizeof( input );
+ AudioConverterGetProperty( pv->converter,
+ kAudioConverterCurrentInputStreamDescription,
+ &tmpsiz, &input );
+ // get real output
+ tmpsiz = sizeof( output );
+ AudioConverterGetProperty( pv->converter,
+ kAudioConverterCurrentOutputStreamDescription,
+ &tmpsiz, &output );
+
+ // set sizes
+ pv->isamplesiz = input.mBytesPerPacket;
+ pv->isamples = output.mFramesPerPacket;
+
+ // get maximum output size
+ AudioConverterGetProperty( pv->converter,
+ kAudioConverterPropertyMaximumOutputPacketSize,
+ &tmpsiz, &tmp );
+ pv->omaxpacket = tmp;
+
+ // get magic cookie (elementary stream descriptor)
+ tmp = HB_CONFIG_MAX_SIZE;
+ AudioConverterGetProperty( pv->converter,
+ kAudioConverterCompressionMagicCookie,
+ &tmp, w->config->aac.bytes );
+ // CoreAudio returns a complete ESDS, but we only need
+ // the DecoderSpecific info.
+ UInt8* buffer;
+ ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0);
+ w->config->aac.length = tmpsiz;
+ memmove( w->config->aac.bytes, buffer,
+ w->config->aac.length );
+
+ pv->list = hb_list_init();
+ pv->buf = NULL;
+
+ return 0;
+}
+
+/***********************************************************************
+ * Close
+ ***********************************************************************
+ *
+ **********************************************************************/
+void encCoreAudioClose( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+
+ if( pv->converter )
+ {
+ AudioConverterDispose( pv->converter );
+ hb_list_empty( &pv->list );
+ free( pv->obuf );
+ free( pv->buf );
+ free( pv );
+ w->private_data = NULL;
+ }
+}
+
+/* Called whenever necessary by AudioConverterFillComplexBuffer */
+static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets,
+ AudioBufferList *buffers,
+ AudioStreamPacketDescription** ignored,
+ void *userdata )
+{
+ hb_work_private_t *pv = userdata;
+ pv->ibytes = hb_list_bytes( pv->list );
+
+ if( pv->ibytes == 0 ) {
+ *npackets = 0;
+ return noErr;
+ }
+
+ if( pv->buf != NULL )
+ free( pv->buf );
+
+ uint64_t pts, pos;
+ pv->ibytes = buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes );
+ buffers->mBuffers[0].mData = pv->buf = malloc( buffers->mBuffers[0].mDataByteSize );
+
+ hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
+ buffers->mBuffers[0].mDataByteSize, &pts, &pos );
+
+ *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
+
+ /* transform data from [-32768,32767] to [-1.0,1.0] */
+ float *fdata = buffers->mBuffers[0].mData;
+ int i;
+
+ for( i = 0; i < *npackets * pv->nchannels; i++ )
+ fdata[i] = fdata[i] / 32768.f;
+
+ return noErr;
+}
+
+/***********************************************************************
+ * Encode
+ ***********************************************************************
+ *
+ **********************************************************************/
+static hb_buffer_t * Encode( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+ UInt32 npackets = 1;
+
+ /* check if we need more data */
+ if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz )
+ return NULL;
+
+ hb_buffer_t * obuf;
+ AudioStreamPacketDescription odesc = { 0 };
+ AudioBufferList obuflist = { .mNumberBuffers = 1,
+ .mBuffers = { { .mNumberChannels = pv->nchannels } },
+ };
+
+ obuf = hb_buffer_init( pv->omaxpacket );
+ obuflist.mBuffers[0].mDataByteSize = obuf->size;
+ obuflist.mBuffers[0].mData = obuf->data;
+
+ AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv,
+ &npackets, &obuflist, &odesc );
+
+ if( odesc.mDataByteSize == 0 )
+ return NULL;
+
+ obuf->start = pv->pts;
+ pv->pts += 90000LL * pv->isamples / w->audio->config.out.samplerate;
+ obuf->stop = pv->pts;
+ obuf->size = odesc.mDataByteSize;
+ obuf->frametype = HB_FRAME_AUDIO;
+
+ return obuf;
+}
+
+/***********************************************************************
+ * Work
+ ***********************************************************************
+ *
+ **********************************************************************/
+int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t * pv = w->private_data;
+ hb_buffer_t * buf;
+
+ if( (*buf_in)->size <= 0 )
+ {
+ // EOF on input - send it downstream & say we're done
+ *buf_out = *buf_in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
+ hb_list_add( pv->list, *buf_in );
+ *buf_in = NULL;
+
+ *buf_out = buf = Encode( w );
+
+ while( buf )
+ {
+ buf->next = Encode( w );
+ buf = buf->next;
+ }
+
+ return HB_WORK_OK;
+}
diff --git a/libhb/work.c b/libhb/work.c
index 59dea5dfe..21232debf 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -106,6 +106,7 @@ hb_work_object_t * hb_codec_encoder( int codec )
case HB_ACODEC_FAAC: return hb_get_work( WORK_ENCFAAC );
case HB_ACODEC_LAME: return hb_get_work( WORK_ENCLAME );
case HB_ACODEC_VORBIS: return hb_get_work( WORK_ENCVORBIS );
+ case HB_ACODEC_CA_AAC: return hb_get_work( WORK_ENC_CA_AAC );
}
return NULL;
}
@@ -329,8 +330,9 @@ void hb_display_job_info( hb_job_t * job )
else
{
hb_log( " + encoder: %s", ( audio->config.out.codec == HB_ACODEC_FAAC ) ?
- "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? "lame" :
- "vorbis" ) );
+ "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ?
+ "lame" : ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ?
+ "ca_aac" : "vorbis" ) ) );
hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate );
}
}