int crf;
/* Audio tracks:
- Indexes in hb_title_t's audios list, starting from 0.
- -1 indicates the end of the list */
+ audios: Indexes in hb_title_t's audios list, starting from 0.
+ -1 indicates the end of the list
+ channels: The # of normal channels in the last used audio
+ lfechannels: The # of lfe channels in the last used audio
+ channelsused: The # of channels we will actually use for this job -
+ calculated based on surround, channels and lfechannels
+ in work.c
+ surround: 1 if 5.1 should be preserved for AAC, 0 otherwise */
int audios[8];
+ int channels;
+ int lfechannels;
+ int channelsused;
+ int surround;
/* Audio settings:
acodec: output codec
int codec;
int rate;
int bitrate;
+ /* indicates the number of normal channels the source audio has */
int channels;
+ /* indicates the number of lfe channels the source audio has */
+ int lfechannels;
#ifdef __LIBMEDIAFORK__
/* Internal data */
uint8_t frame[3840];
hb_list_t * list;
+
+ int channelsused;
+
};
int deca52Init( hb_work_object_t *, hb_job_t * );
pv->list = hb_list_init();
pv->state = a52_init( 0 );
- // we're either extracting 5.1 from AC3 for AAC,
- // or mixing up/down to stereo otherwise
- pv->flags_out = A52_STEREO;
+
+ if (job->channelsused == 6) {
+ /* we're going to be encoding to AAC,
+ and have turned on the "preserve 5.1" flag */
+ pv->flags_out = A52_3F2R | A52_LFE;
+ } else if (job->channelsused == 1) {
+ /* keep the mono-ness of the source audio */
+ pv->flags_out = A52_MONO;
+ } else if (job->channelsused == 2 && job->channels == 5 && job->lfechannels == 1) {
+ /* we are mixing a 5.1 source down to stereo, so use dolby surround */
+ pv->flags_out = A52_DOLBY;
+ } else {
+ /* mix everything else down to stereo */
+ pv->flags_out = A52_STEREO;
+ }
+
+ /* pass the number of channels used into the private work data */
+ pv->channelsused = job->channelsused;
+
pv->level = 32768.0;
return 0;
{
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
- int i, j;
+ int i, j, k;
uint64_t pts;
int pos;
/* Feed liba52 */
a52_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 );
- /* 6 blocks per frame, 256 samples per block, 2 channels */
- buf = hb_buffer_init( 3072 * sizeof( float ) );
+ /* 6 blocks per frame, 256 samples per block, channelsused channels */
+ buf = hb_buffer_init( 6 * 256 * pv->channelsused * sizeof( float ) );
buf->start = pts + ( pos / pv->size ) * 6 * 256 * 90000 / pv->rate;
buf->stop = buf->start + 6 * 256 * 90000 / pv->rate;
a52_block( pv->state );
samples_in = a52_samples( pv->state );
- samples_out = ((float *) buf->data) + 512 * i;
+ samples_out = ((float *) buf->data) + 256 * pv->channelsused * i;
/* Interleave */
for( j = 0; j < 256; j++ )
{
- samples_out[2*j] = samples_in[j];
- samples_out[2*j+1] = samples_in[256+j];
+ for ( k = 0; k < pv->channelsused; k++ )
+ {
+ samples_out[(pv->channelsused*j)+k] = samples_in[(256*k)+j]; // DJA
+ }
}
}
hb_list_t * list;
int64_t pts;
+
+ int channelsused;
+
};
int encfaacInit( hb_work_object_t *, hb_job_t * );
pv->job = job;
- pv->faac = faacEncOpen( job->arate, 2, &pv->input_samples,
+ /* pass the number of channels used into the private work data */
+ pv->channelsused = job->channelsused;
+
+ pv->faac = faacEncOpen( job->arate, job->channelsused, &pv->input_samples,
&pv->output_bytes );
pv->buf = malloc( pv->input_samples * sizeof( float ) );
cfg->mpegVersion = MPEG4;
cfg->aacObjectType = LOW;
cfg->allowMidside = 1;
- cfg->useLfe = 0;
+
+ if (job->channelsused == 6) {
+ /* we are preserving 5.1 audio into 6-channel AAC,
+ so indicate that we have an lfe channel */
+ cfg->useLfe = 1;
+ } else {
+ cfg->useLfe = 0;
+ }
+
cfg->useTns = 0;
cfg->bitRate = job->abitrate * 500; /* Per channel */
cfg->bandWidth = 0;
cfg->outputFormat = 0;
cfg->inputFormat = FAAC_INPUT_FLOAT;
+
+ if (job->channelsused == 6) {
+ /* we are preserving 5.1 audio into 6-channel AAC, and need to
+ re-map the output of deca52 into our own mapping - the mapping
+ below is the default mapping expected by QuickTime */
+ cfg->channel_map[0] = 2;
+ cfg->channel_map[1] = 1;
+ cfg->channel_map[2] = 3;
+ cfg->channel_map[3] = 4;
+ cfg->channel_map[4] = 5;
+ cfg->channel_map[5] = 0;
+ }
+
if( !faacEncSetConfiguration( pv->faac, cfg ) )
{
hb_log( "faacEncSetConfiguration failed" );
&pts, &pos );
buf = hb_buffer_init( pv->output_bytes );
- buf->start = pts + 90000 * pos / 2 / sizeof( float ) / pv->job->arate;
- buf->stop = buf->start + 90000 * pv->input_samples / pv->job->arate / 2;
+ buf->start = pts + 90000 * pos / pv->channelsused / sizeof( float ) / pv->job->arate;
+ buf->stop = buf->start + 90000 * pv->input_samples / pv->job->arate / pv->channelsused;
buf->size = faacEncEncode( pv->faac, (int32_t *) pv->buf,
pv->input_samples, buf->data, pv->output_bytes );
buf->key = 1;
audio->channels = 5;
break;
}
+
+ if (flags & A52_LFE) {
+ audio->lfechannels = 1;
+ } else {
+ audio->lfechannels = 0;
+ }
+
/* XXX */
sprintf( audio->lang + strlen( audio->lang ),
- " (%d ch)", audio->channels );
+ " (%d.%d ch)", audio->channels, audio->lfechannels );
break;
}
}
/***********************************************************************
* Local prototypes
**********************************************************************/
-static void InitAudio( hb_work_object_t * w, int i );
+static void InitAudio( hb_work_object_t * w, int i, int channelsused );
static int SyncVideo( hb_work_object_t * w );
-static void SyncAudio( hb_work_object_t * w, int i );
+static void SyncAudio( hb_work_object_t * w, int i, int channelsused );
static int NeedSilence( hb_work_object_t * w, hb_audio_t * );
-static void InsertSilence( hb_work_object_t * w, int i );
+static void InsertSilence( hb_work_object_t * w, int i, int channelsused );
static void UpdateState( hb_work_object_t * w );
/***********************************************************************
/* Initialize libsamplerate for every audio track we have */
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
- InitAudio( w, i );
+ /* this should really pass in a channelsused value for this audio
+ but for now, it uses the global job value of channelsused */
+ InitAudio( w, i, job->channelsused );
}
/* Get subtitle info, if any */
{
for( i = 0; i < hb_list_count( pv->job->title->list_audio ); i++ )
{
- SyncAudio( w, i );
+ /* this should really pass in a channelsused value for this audio
+ but for now, it uses the global job value of channelsused */
+ SyncAudio( w, i, pv->job->channelsused );
}
}
syncClose
};
-static void InitAudio( hb_work_object_t * w, int i )
+static void InitAudio( hb_work_object_t * w, int i, int channelsused )
{
hb_work_private_t * pv = w->private_data;
hb_job_t * job = pv->job;
{
/* Initialize libsamplerate */
int error;
- sync->state = src_new( SRC_LINEAR, 2, &error );
+ sync->state = src_new( SRC_LINEAR, channelsused, &error );
sync->data.end_of_input = 0;
}
}
***********************************************************************
*
**********************************************************************/
-static void SyncAudio( hb_work_object_t * w, int i )
+static void SyncAudio( hb_work_object_t * w, int i, int channelsused )
{
hb_work_private_t * pv = w->private_data;
hb_job_t * job;
else if( buf->start > pts_expected + 9000 )
{
/* Missing audio, send a frame of silence */
- InsertSilence( w, i );
+ InsertSilence( w, i, channelsused );
continue;
}
int count_in, count_out;
- count_in = buf_raw->size / 2 / sizeof( float );
+ count_in = buf_raw->size / channelsused / sizeof( float );
count_out = ( buf_raw->stop - buf_raw->start ) * job->arate / 90000;
if( buf->start < pts_expected - 1500 )
count_out--;
sync->data.src_ratio = (double) sync->data.output_frames /
(double) sync->data.input_frames;
- buf = hb_buffer_init( sync->data.output_frames * 2 *
+ buf = hb_buffer_init( sync->data.output_frames * channelsused *
sizeof( float ) );
sync->data.data_out = (float *) buf->data;
if( src_process( sync->state, &sync->data ) )
}
hb_buffer_close( &buf_raw );
- buf->size = sync->data.output_frames_gen * 2 * sizeof( float );
+ buf->size = sync->data.output_frames_gen * channelsused * sizeof( float );
/* Set dates for resampled data */
buf->start = start;
if( NeedSilence( w, audio ) )
{
- InsertSilence( w, i );
+ InsertSilence( w, i, channelsused );
}
}
return 0;
}
-static void InsertSilence( hb_work_object_t * w, int i )
+static void InsertSilence( hb_work_object_t * w, int i, int channelsused )
{
hb_work_private_t * pv = w->private_data;
hb_job_t * job;
}
else
{
- buf = hb_buffer_init( 2 * job->arate / 20 *
+ buf = hb_buffer_init( channelsused * job->arate / 20 *
sizeof( float ) );
buf->start = sync->count_frames * 90000 / job->arate;
buf->stop = buf->start + 90000 / 20;
w->config = &audio->config;
hb_list_add( job->list_work, w );
}
+
+ /* store this audio's channel counts with the job */
+ /* this should be an array -
+ we just use the last channel count for now */
+ if (audio->channels == 5 && audio->lfechannels == 1) {
+ /* we have a 5.1 AC-3 source soundtrack */
+ if (job->acodec == HB_ACODEC_FAAC && job->surround) {
+ /* we're going to be encoding to AAC,
+ and have turned on the "preserve 5.1" flag */
+ job->channelsused = 6;
+ } else {
+ /* mix 5.1 down to Dolby Digital (2-channel) */
+ job->channelsused = 2;
+ }
+ } else if (audio->channels == 1 && audio->lfechannels == 0) {
+ /* keep the mono-ness of the source audio */
+ job->channelsused = 1;
+ } else {
+ /* mix everything else down to stereo */
+ job->channelsused = 2;
+ }
+
+ /* remember the actual number of channels and lfe channels */
+ /* again, we are using the last channel's count for now */
+ job->channels = audio->channels;
+ job->lfechannels = audio->lfechannels;
+
}
/* Init read & write threads */
static int h264_13 = 0;
static int h264_30 = 0;
static char * audios = NULL;
+static int surround = 0;
static int sub = 0;
static int width = 0;
static int height = 0;
{
job->h264_level = 13;
}
- if( h264_30 )
- {
- job->h264_level = 30;
+ if( h264_30 )
+ {
+ job->h264_level = 30;
}
if( vrate )
{
job->audios[0] = -1;
}
}
+ if( surround )
+ {
+ job->surround = 1;
+ }
if( abitrate )
{
job->abitrate = abitrate;
" default: all chapters)\n"
" -a, --audio <string> Select audio channel(s) (\"none\" for no \n"
" audio, default: first one)\n"
+ " -6, --surround Export 5.1 surround as 6-channel AAC\n"
"\n"
" -s, --subtitle <number> Select subtitle (default: none)\n"
" -e, --encoder <string> Set video library encoder (ffmpeg,xvid,\n"
{ "title", required_argument, NULL, 't' },
{ "chapters", required_argument, NULL, 'c' },
{ "audio", required_argument, NULL, 'a' },
+ { "surround", no_argument, NULL, '6' },
{ "subtitle", required_argument, NULL, 's' },
{ "encoder", required_argument, NULL, 'e' },
int c;
c = getopt_long( argc, argv,
- "hvuC:f:i:o:t:c:a:s:e:E:2dgpw:l:n:b:q:S:B:r:R:Q",
+ "hvuC:f:i:o:t:c:a:6s:e:E:2dgpw:l:n:b:q:S:B:r:R:Q",
long_options, &option_index );
if( c < 0 )
{
case 'a':
audios = strdup( optarg );
break;
+ case '6':
+ surround = 1;
+ break;
case 's':
sub = atoi( optarg );
break;
acodec = HB_ACODEC_VORBIS;
}
}
+
+ if (acodec != HB_ACODEC_FAAC)
+ {
+ /* only attempt 5.1 export if exporting to AAC */
+ surround = 0;
+ }
+
}
return 0;