summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2010-10-04 23:16:57 +0000
committerjstebbins <[email protected]>2010-10-04 23:16:57 +0000
commitafffc15c0fec6680f6a612c729d184d92fbc809c (patch)
tree84266ecb82c48e371039feac8527f06573e57dc4 /libhb
parente10652943a245468659a3ed0dfed452ccd12ae0c (diff)
Add ac3 encoding
Uses ffmpeg's ac3 encoder. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3570 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r--libhb/common.c12
-rw-r--r--libhb/common.h26
-rw-r--r--libhb/deca52.c2
-rw-r--r--libhb/decavcodec.c51
-rw-r--r--libhb/decdca.c2
-rw-r--r--libhb/encac3.c257
-rw-r--r--libhb/hb.c2
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/muxmkv.c6
-rw-r--r--libhb/muxmp4.c216
-rw-r--r--libhb/sync.c16
-rw-r--r--libhb/work.c44
12 files changed, 494 insertions, 141 deletions
diff --git a/libhb/common.c b/libhb/common.c
index 35417cb6c..0c9ac629e 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -34,7 +34,7 @@ hb_rate_t hb_audio_bitrates[] =
{ "64", 64 }, { "80", 80 }, { "96", 96 }, { "112", 112 },
{ "128", 128 }, { "160", 160 }, { "192", 192 }, { "224", 224 },
{ "256", 256 }, { "320", 320 }, { "384", 384 }, { "448", 448 },
- { "768", 768 } };
+ { "512", 512 }, { "576", 576 }, { "640", 640 }, { "768", 768 } };
int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) /
sizeof( hb_rate_t );
int hb_audio_bitrates_default = 8; /* 128 kbps */
@@ -255,6 +255,8 @@ int hb_calc_bitrate( hb_job_t * job, int size )
case HB_ACODEC_LAME:
samples_per_frame = 1152;
break;
+ case HB_ACODEC_AC3_PASS:
+ case HB_ACODEC_DCA_PASS:
case HB_ACODEC_AC3:
case HB_ACODEC_DCA:
samples_per_frame = 1536;
@@ -263,8 +265,8 @@ int hb_calc_bitrate( hb_job_t * job, int size )
return 0;
}
- if( audio->config.out.codec == HB_ACODEC_AC3 ||
- audio->config.out.codec == HB_ACODEC_DCA)
+ if( audio->config.out.codec == HB_ACODEC_AC3_PASS ||
+ audio->config.out.codec == HB_ACODEC_DCA_PASS)
{
/*
* For pass through we take the bitrate from the input audio
@@ -904,7 +906,8 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg)
*/
audio->config.out.track = hb_list_count(job->list_audio) + 1;
audio->config.out.codec = audiocfg->out.codec;
- if( audiocfg->out.codec == audio->config.in.codec )
+ if( (audiocfg->out.codec & HB_ACODEC_MASK) == audio->config.in.codec &&
+ (audiocfg->out.codec & HB_ACODEC_PASS_FLAG ) )
{
/* Pass-through, copy from input. */
audio->config.out.samplerate = audio->config.in.samplerate;
@@ -915,6 +918,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg)
else
{
/* Non pass-through, use what is given. */
+ audio->config.out.codec &= ~HB_ACODEC_PASS_FLAG;
audio->config.out.samplerate = audiocfg->out.samplerate;
audio->config.out.bitrate = audiocfg->out.bitrate;
audio->config.out.dynamic_range_compression = audiocfg->out.dynamic_range_compression;
diff --git a/libhb/common.h b/libhb/common.h
index bba48350c..fcb4d4d04 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -307,16 +307,21 @@ struct hb_job_s
/* Audio starts here */
/* Audio Codecs */
-#define HB_ACODEC_MASK 0x00FF00
-#define HB_ACODEC_FAAC 0x000100
-#define HB_ACODEC_LAME 0x000200
-#define HB_ACODEC_VORBIS 0x000400
-#define HB_ACODEC_AC3 0x000800
-#define HB_ACODEC_MPGA 0x001000
-#define HB_ACODEC_LPCM 0x002000
-#define HB_ACODEC_DCA 0x004000
-#define HB_ACODEC_FFMPEG 0x008000
-#define HB_ACODEC_CA_AAC 0x010000
+#define HB_ACODEC_MASK 0x000FFF00
+#define HB_ACODEC_FAAC 0x00000100
+#define HB_ACODEC_LAME 0x00000200
+#define HB_ACODEC_VORBIS 0x00000400
+#define HB_ACODEC_AC3 0x00000800
+#define HB_ACODEC_MPGA 0x00001000
+#define HB_ACODEC_LPCM 0x00002000
+#define HB_ACODEC_DCA 0x00004000
+#define HB_ACODEC_FFMPEG 0x00008000
+#define HB_ACODEC_CA_AAC 0x00010000
+#define HB_ACODEC_PASS_FLAG 0x40000000
+#define HB_ACODEC_PASS_MASK (HB_ACODEC_AC3 | HB_ACODEC_DCA)
+#define HB_ACODEC_AC3_PASS (HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG)
+#define HB_ACODEC_DCA_PASS (HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG)
+#define HB_ACODEC_ANY (HB_ACODEC_MASK | HB_ACODEC_PASS_FLAG)
/* Audio Mixdown */
/* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */
@@ -771,6 +776,7 @@ extern hb_work_object_t hb_enclame;
extern hb_work_object_t hb_encvorbis;
extern hb_work_object_t hb_muxer;
extern hb_work_object_t hb_encca_aac;
+extern hb_work_object_t hb_encac3;
#define FILTER_OK 0
#define FILTER_DELAY 1
diff --git a/libhb/deca52.c b/libhb/deca52.c
index 785bf6aef..0958a9139 100644
--- a/libhb/deca52.c
+++ b/libhb/deca52.c
@@ -259,7 +259,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
double frame_dur = (6. * 256. * 90000.) / pv->rate;
/* AC3 passthrough: don't decode the AC3 frame */
- if( audio->config.out.codec == HB_ACODEC_AC3 )
+ if( audio->config.out.codec == HB_ACODEC_AC3_PASS )
{
buf = hb_buffer_init( size );
memcpy( buf->data, pv->frame, size );
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index abf7ed179..bbdd4d668 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -111,6 +111,7 @@ struct hb_work_private_s
struct SwsContext *sws_context; // if we have to rescale or convert color space
hb_downmix_t *downmix;
hb_sample_t *downmix_buffer;
+ hb_chan_map_t *out_map;
};
static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size );
@@ -203,13 +204,25 @@ static int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
pv->context = avcodec_alloc_context();
hb_avcodec_open( pv->context, codec );
- if ( w->audio != NULL &&
- hb_need_downmix( w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown) )
+ if ( w->audio != NULL )
{
- pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown);
- hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_qt_chan_map );
+ if ( w->audio->config.out.codec == HB_ACODEC_AC3 )
+ {
+ // ffmpegs audio encoder expect an smpte chan map as input.
+ // So we need to map the decoders output to smpte.
+ pv->out_map = &hb_smpte_chan_map;
+ }
+ else
+ {
+ pv->out_map = &hb_qt_chan_map;
+ }
+ if ( hb_need_downmix( w->audio->config.in.channel_layout,
+ w->audio->config.out.mixdown) )
+ {
+ pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
+ w->audio->config.out.mixdown);
+ hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, pv->out_map );
+ }
}
return 0;
@@ -1129,13 +1142,25 @@ static int decavcodecviInit( hb_work_object_t * w, hb_job_t * job )
pv->pts_next = -1;
pv->pts = -1;
- if ( w->audio != NULL &&
- hb_need_downmix( w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown) )
+ if ( w->audio != NULL )
{
- pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown);
- hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_qt_chan_map );
+ if ( w->audio->config.out.codec == HB_ACODEC_AC3 )
+ {
+ // ffmpegs audio encoder expect an smpte chan map as input.
+ // So we need to map the decoders output to smpte.
+ pv->out_map = &hb_smpte_chan_map;
+ }
+ else
+ {
+ pv->out_map = &hb_qt_chan_map;
+ }
+ if ( hb_need_downmix( w->audio->config.in.channel_layout,
+ w->audio->config.out.mixdown) )
+ {
+ pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
+ w->audio->config.out.mixdown);
+ hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, pv->out_map );
+ }
}
return 0;
@@ -1308,7 +1333,7 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
fl32[i] = buffer[i];
}
int n_ch_samples = nsamples / context->channels;
- hb_layout_remap( &hb_smpte_chan_map, &hb_qt_chan_map,
+ hb_layout_remap( &hb_smpte_chan_map, pv->out_map,
audio->config.in.channel_layout,
fl32, n_ch_samples );
}
diff --git a/libhb/decdca.c b/libhb/decdca.c
index 89c2b1c17..ea4cb560c 100644
--- a/libhb/decdca.c
+++ b/libhb/decdca.c
@@ -231,7 +231,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w )
double frame_dur = (double)(pv->frame_length & ~0xFF) / (double)pv->rate * 90000.;
/* DCA passthrough: don't decode the DCA frame */
- if( audio->config.out.codec == HB_ACODEC_DCA )
+ if( audio->config.out.codec == HB_ACODEC_DCA_PASS )
{
buf = hb_buffer_init( pv->size );
memcpy( buf->data, pv->frame, pv->size );
diff --git a/libhb/encac3.c b/libhb/encac3.c
new file mode 100644
index 000000000..5c45b9800
--- /dev/null
+++ b/libhb/encac3.c
@@ -0,0 +1,257 @@
+/* $Id: encac3.c,v 1.23 2005/10/13 23:47:06 titer Exp $
+
+ 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 "hbffmpeg.h"
+#include "downmix.h"
+
+struct hb_work_private_s
+{
+ hb_job_t * job;
+ AVCodecContext * context;
+
+ int out_discrete_channels;
+ unsigned long input_samples;
+ unsigned long output_bytes;
+ hb_list_t * list;
+ uint8_t * buf;
+ int16_t * samples;
+};
+
+int encac3Init( hb_work_object_t *, hb_job_t * );
+int encac3Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+void encac3Close( hb_work_object_t * );
+
+#define AC3_SAMPLES_PER_FRAME 1536
+#define AC3_MAX_CODED_FRAME_SIZE 3840
+
+hb_work_object_t hb_encac3 =
+{
+ WORK_ENCAC3,
+ "AC-3 encoder (libavcodec)",
+ encac3Init,
+ encac3Work,
+ encac3Close
+};
+
+int encac3Init( hb_work_object_t * w, hb_job_t * job )
+{
+ AVCodec * codec;
+ AVCodecContext * context;
+ hb_audio_t * audio = w->audio;
+
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
+
+ pv->job = job;
+
+ pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
+ pv->input_samples = AC3_SAMPLES_PER_FRAME * pv->out_discrete_channels;
+ pv->output_bytes = AC3_MAX_CODED_FRAME_SIZE;
+
+ pv->buf = malloc( pv->input_samples * sizeof( float ) );
+ pv->samples = malloc( pv->input_samples * sizeof( int16_t ) );
+
+ codec = avcodec_find_encoder( CODEC_ID_AC3 );
+ if( !codec )
+ {
+ hb_log( "encac3Init: avcodec_find_encoder "
+ "failed" );
+ }
+ context = avcodec_alloc_context();
+
+ context->channel_layout = CH_LAYOUT_STEREO;
+ switch( audio->config.out.mixdown )
+ {
+ case HB_AMIXDOWN_MONO:
+ context->channel_layout = CH_LAYOUT_MONO;
+ break;
+
+ case HB_AMIXDOWN_STEREO:
+ case HB_AMIXDOWN_DOLBY:
+ case HB_AMIXDOWN_DOLBYPLII:
+ context->channel_layout = CH_LAYOUT_STEREO;
+ break;
+
+ case HB_AMIXDOWN_6CH:
+ context->channel_layout = CH_LAYOUT_5POINT0|CH_LOW_FREQUENCY;
+ break;
+
+ default:
+ hb_log(" encac3Init: bad mixdown" );
+ break;
+ }
+
+ context->bit_rate = audio->config.out.bitrate * 1000;
+ context->sample_rate = audio->config.out.samplerate;
+ context->channels = pv->out_discrete_channels;
+
+ if( hb_avcodec_open( context, codec ) )
+ {
+ hb_log( "encac3Init: avcodec_open failed" );
+ }
+ pv->context = context;
+
+ pv->list = hb_list_init();
+
+ return 0;
+}
+
+/***********************************************************************
+ * Close
+ ***********************************************************************
+ *
+ **********************************************************************/
+void encac3Close( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+
+ if ( pv )
+ {
+ if( pv->context )
+ {
+ hb_deep_log( 2, "encac3: closing libavcodec" );
+ if ( pv->context->codec )
+ avcodec_flush_buffers( pv->context );
+ hb_avcodec_close( pv->context );
+ }
+
+ if ( pv->buf )
+ {
+ free( pv->buf );
+ pv->buf = NULL;
+ }
+
+ if ( pv->samples )
+ {
+ free( pv->samples );
+ pv->samples = NULL;
+ }
+
+ if ( pv->list )
+ hb_list_empty( &pv->list );
+
+ free( pv );
+ w->private_data = NULL;
+ }
+}
+
+static hb_buffer_t * Encode( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+ uint64_t pts, pos;
+ hb_audio_t * audio = w->audio;
+ hb_buffer_t * buf;
+ int ii;
+
+ if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) )
+ {
+ return NULL;
+ }
+
+ hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ),
+ &pts, &pos);
+
+ hb_chan_map_t *map = NULL;
+ if ( audio->config.in.codec == HB_ACODEC_AC3 )
+ {
+ map = &hb_ac3_chan_map;
+ }
+ else if ( audio->config.in.codec == HB_ACODEC_DCA )
+ {
+ map = &hb_qt_chan_map;
+ }
+ if ( map )
+ {
+ int layout;
+ switch (audio->config.out.mixdown)
+ {
+ case HB_AMIXDOWN_MONO:
+ layout = HB_INPUT_CH_LAYOUT_MONO;
+ break;
+ case HB_AMIXDOWN_STEREO:
+ case HB_AMIXDOWN_DOLBY:
+ case HB_AMIXDOWN_DOLBYPLII:
+ layout = HB_INPUT_CH_LAYOUT_STEREO;
+ break;
+ case HB_AMIXDOWN_6CH:
+ default:
+ layout = HB_INPUT_CH_LAYOUT_3F2R | HB_INPUT_CH_LAYOUT_HAS_LFE;
+ break;
+ }
+ hb_layout_remap( map, &hb_smpte_chan_map, layout,
+ (float*)pv->buf, AC3_SAMPLES_PER_FRAME);
+ }
+
+ for (ii = 0; ii < pv->input_samples; ii++)
+ {
+ pv->samples[ii] = (int16_t)((float*)pv->buf)[ii];
+ }
+
+ buf = hb_buffer_init( pv->output_bytes );
+ buf->size = avcodec_encode_audio( pv->context, buf->data, buf->alloc,
+ pv->samples );
+
+ buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate;
+ buf->stop = buf->start + 90000 * AC3_SAMPLES_PER_FRAME / audio->config.out.samplerate;
+
+ buf->frametype = HB_FRAME_AUDIO;
+
+ if ( !buf->size )
+ {
+ hb_buffer_close( &buf );
+ return Encode( w );
+ }
+ else if (buf->size < 0)
+ {
+ hb_log( "encac3: avcodec_encode_audio failed" );
+ hb_buffer_close( &buf );
+ return NULL;
+ }
+
+ return buf;
+}
+
+/***********************************************************************
+ * Work
+ ***********************************************************************
+ *
+ **********************************************************************/
+int encac3Work( 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 * in = *buf_in, * buf;
+
+ if ( in->size <= 0 )
+ {
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
+ if ( pv->context == NULL || pv->context->codec == NULL )
+ {
+ // No encoder context. Nothing we can do.
+ return HB_WORK_OK;
+ }
+
+ hb_list_add( pv->list, 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/hb.c b/libhb/hb.c
index fcb4a55df..f7489c162 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -346,6 +346,7 @@ hb_handle_t * hb_init( int verbose, int update_check )
#ifdef __APPLE__
hb_register( &hb_encca_aac );
#endif
+ hb_register( &hb_encac3 );
return h;
}
@@ -450,6 +451,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check )
#ifdef __APPLE__
hb_register( &hb_encca_aac );
#endif
+ hb_register( &hb_encac3 );
return h;
}
diff --git a/libhb/internal.h b/libhb/internal.h
index 30bf022d5..b6fbd1ddb 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -355,6 +355,7 @@ enum
WORK_ENCLAME,
WORK_ENCVORBIS,
WORK_ENC_CA_AAC,
+ WORK_ENCAC3,
WORK_MUX
};
diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c
index aa320e9aa..073b39f45 100644
--- a/libhb/muxmkv.c
+++ b/libhb/muxmkv.c
@@ -167,11 +167,13 @@ static int MKVInit( hb_mux_object_t * m )
switch (audio->config.out.codec)
{
case HB_ACODEC_DCA:
+ case HB_ACODEC_DCA_PASS:
track->codecPrivate = NULL;
track->codecPrivateSize = 0;
track->codecID = MK_ACODEC_DTS;
break;
case HB_ACODEC_AC3:
+ case HB_ACODEC_AC3_PASS:
track->codecPrivate = NULL;
track->codecPrivateSize = 0;
track->codecID = MK_ACODEC_AC3;
@@ -228,8 +230,8 @@ static int MKVInit( hb_mux_object_t * m )
track->trackType = MK_TRACK_AUDIO;
track->language = audio->config.lang.iso639_2;
track->extra.audio.samplingFreq = (float)audio->config.out.samplerate;
- if (audio->config.out.codec == HB_ACODEC_AC3 ||
- audio->config.out.codec == HB_ACODEC_DCA)
+ if (audio->config.out.codec == HB_ACODEC_AC3_PASS ||
+ audio->config.out.codec == HB_ACODEC_DCA_PASS)
{
track->extra.audio.channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout);
}
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index bc523f836..5225ea523 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -63,6 +63,14 @@ static int MP4TuneTrackDurationPerChunk( hb_mux_object_t* m, MP4TrackId trackId
return 1;
}
+static const uint16_t ac3_sample_rate_tab[3] = { 48000, 44100, 32000 };
+/* possible bitrates */
+static const uint16_t ac3_bitrate_tab[19] = {
+ 32, 40, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384, 448, 512, 576, 640
+};
+
+
/**********************************************************************
* MP4Init
**********************************************************************
@@ -225,106 +233,142 @@ static int MP4Init( hb_mux_object_t * m )
mux_data = calloc(1, sizeof( hb_mux_data_t ) );
audio->priv.mux_data = mux_data;
- if( audio->config.out.codec == HB_ACODEC_AC3 )
+ if( audio->config.out.codec == HB_ACODEC_AC3_PASS )
{
- uint8_t fscod = 0;
uint8_t bsid = audio->config.in.version;
uint8_t bsmod = audio->config.in.mode;
uint8_t acmod = audio->config.flags.ac3 & 0x7;
uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0;
uint8_t bit_rate_code = 0;
+ int ii, jj;
+ int freq = audio->config.in.samplerate;
+ int bitrate = audio->config.in.bitrate;
+ int sr_shift, sr_code;
- /*
- * Rewrite AC3 information into correct format for dac3 atom
- */
- switch( audio->config.in.samplerate )
+ for (ii = 0; ii < 3; ii++)
{
- case 48000:
- fscod = 0;
- break;
- case 44100:
- fscod = 1;
- break;
- case 32000:
- fscod = 2;
- break;
- default:
- /*
- * Error value, tells decoder to not decode this audio.
- */
- fscod = 3;
- break;
+ for (jj = 0; jj < 3; jj++)
+ {
+ if ((ac3_sample_rate_tab[jj] >> ii) == freq)
+ {
+ break;
+ }
+ }
}
+ if ( ii >= 3 )
+ {
+ hb_error("Unknown AC3 samplerate");
+ ii = jj = 0;
+ }
+ sr_shift = ii;
+ sr_code = jj;
+ for (ii = 0; ii < 19; ii++)
+ {
+ if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate)
+ break;
+ }
+ if ( ii >= 19 )
+ {
+ hb_error("Unknown AC3 bitrate");
+ ii = 0;
+ }
+ bit_rate_code = ii;
+
+ mux_data->track = MP4AddAC3AudioTrack(
+ m->file,
+ audio->config.in.samplerate,
+ sr_code,
+ bsid,
+ bsmod,
+ acmod,
+ lfeon,
+ bit_rate_code);
+
+ /* Tune track chunk duration */
+ MP4TuneTrackDurationPerChunk( m, mux_data->track );
- switch( audio->config.in.bitrate )
+ if (audio->config.out.name == NULL) {
+ MP4SetTrackBytesProperty(
+ m->file, mux_data->track,
+ "udta.name.value",
+ (const uint8_t*)"Surround", strlen("Surround"));
+ }
+ else {
+ MP4SetTrackBytesProperty(
+ m->file, mux_data->track,
+ "udta.name.value",
+ (const uint8_t*)(audio->config.out.name),
+ strlen(audio->config.out.name));
+ }
+ }
+ else if( audio->config.out.codec == HB_ACODEC_AC3 )
+ {
+ uint8_t bsid = 8;
+ uint8_t bsmod = 0;
+ uint8_t acmod = 2;
+ uint8_t lfeon = 0;
+ uint8_t bit_rate_code = 0;
+ int ii, jj;
+ int freq = audio->config.out.samplerate;
+ int bitrate = audio->config.out.bitrate;
+ int sr_shift, sr_code;
+
+ for (ii = 0; ii < 3; ii++)
+ {
+ for (jj = 0; jj < 3; jj++)
+ {
+ if ((ac3_sample_rate_tab[jj] >> ii) == freq)
+ {
+ break;
+ }
+ }
+ }
+ if ( ii >= 3 )
+ {
+ hb_error("Unknown AC3 samplerate");
+ ii = jj = 0;
+ }
+ sr_shift = ii;
+ sr_code = jj;
+ bsid = 8 + ii;
+ for (ii = 0; ii < 19; ii++)
+ {
+ if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate)
+ break;
+ }
+ if ( ii >= 19 )
{
- case 32000:
- bit_rate_code = 0;
- break;
- case 40000:
- bit_rate_code = 1;
- break;
- case 48000:
- bit_rate_code = 2;
- break;
- case 56000:
- bit_rate_code = 3;
- break;
- case 64000:
- bit_rate_code = 4;
- break;
- case 80000:
- bit_rate_code = 5;
- break;
- case 96000:
- bit_rate_code = 6;
- break;
- case 112000:
- bit_rate_code = 7;
- break;
- case 128000:
- bit_rate_code = 8;
- break;
- case 160000:
- bit_rate_code = 9;
- break;
- case 192000:
- bit_rate_code = 10;
- break;
- case 224000:
- bit_rate_code = 11;
- break;
- case 256000:
- bit_rate_code = 12;
- break;
- case 320000:
- bit_rate_code = 13;
- break;
- case 384000:
- bit_rate_code = 14;
- break;
- case 448000:
- bit_rate_code = 15;
- break;
- case 512000:
- bit_rate_code = 16;
- break;
- case 576000:
- bit_rate_code = 17;
- break;
- case 640000:
- bit_rate_code = 18;
- break;
- default:
hb_error("Unknown AC3 bitrate");
- bit_rate_code = 0;
- break;
+ ii = 0;
+ }
+ bit_rate_code = ii;
+
+ switch( audio->config.out.mixdown )
+ {
+ case HB_AMIXDOWN_MONO:
+ acmod = 1;
+ break;
+
+ case HB_AMIXDOWN_STEREO:
+ case HB_AMIXDOWN_DOLBY:
+ case HB_AMIXDOWN_DOLBYPLII:
+ acmod = 2;
+ break;
+
+ case HB_AMIXDOWN_6CH:
+ acmod = 7;
+ lfeon = 1;
+ break;
+
+ default:
+ hb_log(" MP4Init: bad mixdown" );
+ break;
}
mux_data->track = MP4AddAC3AudioTrack(
m->file,
audio->config.out.samplerate,
- fscod,
+ sr_code,
bsid,
bsmod,
acmod,
@@ -347,8 +391,10 @@ static int MP4Init( hb_mux_object_t * m )
(const uint8_t*)(audio->config.out.name),
strlen(audio->config.out.name));
}
- } else if( audio->config.out.codec == HB_ACODEC_FAAC ||
- audio->config.out.codec == HB_ACODEC_CA_AAC ) {
+ }
+ else if( audio->config.out.codec == HB_ACODEC_FAAC ||
+ audio->config.out.codec == HB_ACODEC_CA_AAC )
+ {
mux_data->track = MP4AddAudioTrack(
m->file,
audio->config.out.samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );
diff --git a/libhb/sync.c b/libhb/sync.c
index 58628f316..acc782e4a 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -898,7 +898,7 @@ void syncAudioClose( hb_work_object_t * w )
hb_work_private_t * pv = w->private_data;
hb_sync_audio_t * sync = &pv->type.audio;
- if( w->audio->config.out.codec == HB_ACODEC_AC3 )
+ if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
{
free( sync->ac3_buf );
}
@@ -1073,7 +1073,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
* Or in the case of DCA, skip some frames from the
* other streams.
*/
- if( w->audio->config.out.codec == HB_ACODEC_DCA )
+ if( w->audio->config.out.codec == HB_ACODEC_DCA_PASS )
{
hb_log( "sync: audio gap %d ms. Skipping frames. Audio %d"
" start %"PRId64", next %"PRId64,
@@ -1131,8 +1131,8 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
w->audio = hb_list_item( title->list_audio, i );
w->fifo_in = w->audio->priv.fifo_raw;
- if( w->audio->config.out.codec == HB_ACODEC_AC3 ||
- w->audio->config.out.codec == HB_ACODEC_DCA )
+ if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ||
+ w->audio->config.out.codec == HB_ACODEC_DCA_PASS )
{
w->fifo_out = w->audio->priv.fifo_out;
}
@@ -1141,7 +1141,7 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
w->fifo_out = w->audio->priv.fifo_sync;
}
- if( w->audio->config.out.codec == HB_ACODEC_AC3 )
+ if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
{
/* Have a silent AC-3 frame ready in case we have to fill a
gap */
@@ -1199,8 +1199,8 @@ static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf,
sync->next_pts += duration;
if( audio->config.in.samplerate == audio->config.out.samplerate ||
- audio->config.out.codec == HB_ACODEC_AC3 ||
- audio->config.out.codec == HB_ACODEC_DCA )
+ audio->config.out.codec == HB_ACODEC_AC3_PASS ||
+ audio->config.out.codec == HB_ACODEC_DCA_PASS )
{
/*
* If we don't have to do sample rate conversion or this audio is
@@ -1271,7 +1271,7 @@ static void InsertSilence( hb_work_object_t * w, int64_t duration )
while ( --frame_count >= 0 )
{
- if( w->audio->config.out.codec == HB_ACODEC_AC3 )
+ if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS )
{
buf = hb_buffer_init( sync->ac3_size );
buf->start = sync->next_pts;
diff --git a/libhb/work.c b/libhb/work.c
index 3c3346d19..b7dda2736 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -128,7 +128,8 @@ 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 );
+ case HB_ACODEC_CA_AAC: return hb_get_work( WORK_ENC_CA_AAC );
+ case HB_ACODEC_AC3: return hb_get_work( WORK_ENCAC3 );
}
return NULL;
}
@@ -344,7 +345,7 @@ void hb_display_job_info( hb_job_t * job )
hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.in.bitrate / 1000, audio->config.in.samplerate );
}
- if( (audio->config.out.codec != HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_DCA) )
+ if( (audio->config.out.codec != HB_ACODEC_AC3_PASS) && (audio->config.out.codec != HB_ACODEC_DCA_PASS) )
{
for (j = 0; j < hb_audio_mixdowns_count; j++)
{
@@ -355,22 +356,24 @@ void hb_display_job_info( hb_job_t * job )
}
}
- if ( audio->config.out.dynamic_range_compression && (audio->config.out.codec != HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_DCA))
+ if ( audio->config.out.dynamic_range_compression && (audio->config.out.codec != HB_ACODEC_AC3_PASS) && (audio->config.out.codec != HB_ACODEC_DCA_PASS))
{
hb_log(" + dynamic range compression: %f", audio->config.out.dynamic_range_compression);
}
- if( (audio->config.out.codec == HB_ACODEC_AC3) || (audio->config.out.codec == HB_ACODEC_DCA) )
+ if( (audio->config.out.codec == HB_ACODEC_AC3_PASS) || (audio->config.out.codec == HB_ACODEC_DCA_PASS) )
{
- hb_log( " + %s passthrough", (audio->config.out.codec == HB_ACODEC_AC3) ?
+ hb_log( " + %s passthrough", (audio->config.out.codec == HB_ACODEC_AC3_PASS) ?
"AC3" : "DCA" );
}
else
{
- hb_log( " + encoder: %s", ( audio->config.out.codec == HB_ACODEC_FAAC ) ?
- "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ?
- "lame" : ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ?
- "ca_aac" : "vorbis" ) ) );
+ hb_log( " + encoder: %s",
+ ( audio->config.out.codec == HB_ACODEC_FAAC ) ? "faac" :
+ ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? "lame" :
+ ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ? "ca_aac" :
+ ( ( audio->config.out.codec == HB_ACODEC_AC3 ) ? "ffac3" :
+ "vorbis" ) ) ) );
hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate );
}
}
@@ -513,8 +516,8 @@ static void do_job( hb_job_t * job, int cpu_count )
for( i = 0; i < hb_list_count( title->list_audio ); )
{
audio = hb_list_item( title->list_audio, i );
- if( ( ( audio->config.out.codec == HB_ACODEC_AC3 ) && ( audio->config.in.codec != HB_ACODEC_AC3 ) ) ||
- ( ( audio->config.out.codec == HB_ACODEC_DCA ) && ( audio->config.in.codec != HB_ACODEC_DCA ) ) )
+ if( ( ( audio->config.out.codec == HB_ACODEC_AC3_PASS ) && ( audio->config.in.codec != HB_ACODEC_AC3 ) ) ||
+ ( ( audio->config.out.codec == HB_ACODEC_DCA_PASS ) && ( audio->config.in.codec != HB_ACODEC_DCA ) ) )
{
hb_log( "Passthru requested and input codec is not the same as output codec for track %d",
audio->config.out.track );
@@ -522,14 +525,21 @@ static void do_job( hb_job_t * job, int cpu_count )
free( audio );
continue;
}
- if( audio->config.out.codec != HB_ACODEC_AC3 &&
- audio->config.out.codec != HB_ACODEC_DCA &&
+ if( audio->config.out.codec != HB_ACODEC_AC3_PASS &&
+ audio->config.out.codec != HB_ACODEC_DCA_PASS &&
audio->config.out.samplerate > 48000 )
{
hb_log( "Sample rate %d not supported. Down-sampling to 48kHz.",
audio->config.out.samplerate );
audio->config.out.samplerate = 48000;
}
+ if( audio->config.out.codec == HB_ACODEC_AC3 &&
+ audio->config.out.bitrate > 640 )
+ {
+ hb_log( "Bitrate %d not supported. Reducing to 640Kbps.",
+ audio->config.out.bitrate );
+ audio->config.out.bitrate = 640;
+ }
if ( audio->config.in.codec == HB_ACODEC_FFMPEG )
{
if ( aud_id_uses[audio->id] )
@@ -570,8 +580,8 @@ static void do_job( hb_job_t * job, int cpu_count )
/* sense-check the requested mixdown */
if( audio->config.out.mixdown == 0 &&
- audio->config.out.codec != HB_ACODEC_AC3 &&
- audio->config.out.codec != HB_ACODEC_DCA )
+ audio->config.out.codec != HB_ACODEC_AC3_PASS &&
+ audio->config.out.codec != HB_ACODEC_DCA_PASS )
{
/*
* Mixdown wasn't specified and this is not pass-through,
@@ -863,8 +873,8 @@ static void do_job( hb_job_t * job, int cpu_count )
/*
* Audio Encoder Thread
*/
- if( audio->config.out.codec != HB_ACODEC_AC3 &&
- audio->config.out.codec != HB_ACODEC_DCA )
+ if( audio->config.out.codec != HB_ACODEC_AC3_PASS &&
+ audio->config.out.codec != HB_ACODEC_DCA_PASS )
{
/*
* Add the encoder thread if not doing AC-3 pass through