From ddc7ac09960746920ae8e48ac6f38a61c9f56d47 Mon Sep 17 00:00:00 2001 From: maurj Date: Wed, 11 Apr 2007 15:23:57 +0000 Subject: Added libhb and CLI support for Dolby Pro Logic II 5.0 matrix encoding. *NOT YET ADDED TO THE GUI*. Handbrake now uses a more general "audio mixdown" concept. For each audio track to be converted you specify a mixdown. These are defined in common.h. This checkin only allows you to specify one mixdown for all tracks in the CLI, although everything is in place internally to specify a different mixdown per track. In the CLI, the "-6 --surround" option has been repurposed as a "-6 --mixdown" option, with a string parameter of mono/stereo/dpl1/dpl2/6ch. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@494 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/common.c | 9 +++ libhb/common.h | 83 ++++++++++++++++++------ libhb/deca52.c | 32 +++------- libhb/encfaac.c | 16 ++--- libhb/encvorbis.c | 16 ++--- libhb/internal.h | 14 +--- libhb/muxavi.c | 2 +- libhb/scan.c | 61 ++++++++++++++---- libhb/sync.c | 12 ++-- libhb/work.c | 187 +++++++++++++++++++++++++++++++++++++++++------------- 10 files changed, 300 insertions(+), 132 deletions(-) (limited to 'libhb') diff --git a/libhb/common.c b/libhb/common.c index 560a839e6..d0dcef877 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -36,6 +36,15 @@ int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) / sizeof( hb_rate_t ); int hb_audio_bitrates_default = 8; /* 128 kbps */ +hb_mixdown_t hb_audio_mixdowns[] = +{ { "Mono", "HB_AMIXDOWN_MONO", HB_AMIXDOWN_MONO }, + { "Stereo", "HB_AMIXDOWN_STEREO", HB_AMIXDOWN_STEREO }, + { "Dolby Surround", "HB_AMIXDOWN_DOLBY", HB_AMIXDOWN_DOLBY }, + { "Dolby Pro Logic II", "HB_AMIXDOWN_DOLBYPLII", HB_AMIXDOWN_DOLBYPLII }, + { "6-channel discrete", "HB_AMIXDOWN_6CH", HB_AMIXDOWN_6CH } }; +int hb_audio_mixdowns_count = sizeof( hb_audio_mixdowns ) / + sizeof( hb_mixdown_t ); + /********************************************************************** * hb_reduce ********************************************************************** diff --git a/libhb/common.h b/libhb/common.h index d09c2d279..4934063e5 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -31,6 +31,7 @@ typedef struct hb_handle_s hb_handle_t; typedef struct hb_list_s hb_list_t; typedef struct hb_rate_s hb_rate_t; +typedef struct hb_mixdown_s hb_mixdown_t; typedef struct hb_job_s hb_job_t; typedef struct hb_title_s hb_title_t; typedef struct hb_chapter_s hb_chapter_t; @@ -70,17 +71,26 @@ struct hb_rate_s int rate; }; +struct hb_mixdown_s +{ + char * human_readable_name; + char * internal_name; + int amixdown; +}; + #define HB_ASPECT_BASE 9 #define HB_VIDEO_RATE_BASE 27000000 -extern hb_rate_t hb_video_rates[]; -extern int hb_video_rates_count; -extern hb_rate_t hb_audio_rates[]; -extern int hb_audio_rates_count; -extern int hb_audio_rates_default; -extern hb_rate_t hb_audio_bitrates[]; -extern int hb_audio_bitrates_count; -extern int hb_audio_bitrates_default; +extern hb_rate_t hb_video_rates[]; +extern int hb_video_rates_count; +extern hb_rate_t hb_audio_rates[]; +extern int hb_audio_rates_count; +extern int hb_audio_rates_default; +extern hb_rate_t hb_audio_bitrates[]; +extern int hb_audio_bitrates_count; +extern int hb_audio_bitrates_default; +extern hb_mixdown_t hb_audio_mixdowns[]; +extern int hb_audio_mixdowns_count; /****************************************************************************** * hb_job_t: settings to be filled by the UI @@ -151,10 +161,36 @@ struct hb_job_s int areBframes; /* Audio tracks: - audios: Indexes in hb_title_t's audios list, starting from 0. - -1 indicates the end of the list - surround: 1 if 5.1 should be preserved for AAC, 0 otherwise */ + audios: Indexes in hb_title_t's audios list, starting from 0. + -1 indicates the end of the list + audio_mixdowns: The mixdown to be used for each audio track in audios[] */ + +/* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */ +#define HB_AMIXDOWN_A52_FORMAT_MASK 0x00FF0000 +#define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000F000 +#define HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK 0x00000F00 +#define HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK 0x000000F0 +#define HB_AMIXDOWN_LFE_CHANNEL_COUNT_MASK 0x0000000F +/* define the HB_AMIXDOWN_XXXX values */ +#define HB_AMIXDOWN_MONO 0x01011100 // A52_FORMAT of A52_MONO = 1 = 0x01 +#define HB_AMIXDOWN_STEREO 0x02022200 // A52_FORMAT of A52_STEREO = 2 = 0x02 +#define HB_AMIXDOWN_DOLBY 0x040A2310 // A52_FORMAT of A52_DOLBY = 10 = 0x0A +#define HB_AMIXDOWN_DOLBYPLII 0x084A2320 // A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74 = 0x4A +#define HB_AMIXDOWN_6CH 0x10176321 // A52_FORMAT of A52_3F2R | A52_LFE = 23 = 0x17 +/* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */ +#define HB_AMIXDOWN_GET_A52_FORMAT( a ) ( ( a & HB_AMIXDOWN_A52_FORMAT_MASK ) >> 16 ) +#define HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK ) >> 12 ) +#define HB_AMIXDOWN_GET_FRONT_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK ) >> 8 ) +#define HB_AMIXDOWN_GET_REAR_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK ) >> 4 ) +#define HB_AMIXDOWN_GET_LFE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_LFE_CHANNEL_COUNT_MASK ) ) +#define HB_AMIXDOWN_GET_NORMAL_CHANNEL_COUNT( a ) ( (( a & HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK ) >> 8) + (( a & HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK ) >> 4) ) int audios[8]; + int audio_mixdowns[8]; + + /* this "surround" property will be removed shortly, + as soon as the AMIXDOWN code has been integrated into the Mac GUI + it's still included here to avoid breaking the Mac GUI short-term + however, it won't be applied in deca52.c etc. any more */ int surround; /* Audio settings: @@ -225,14 +261,16 @@ struct hb_audio_s int codec; int rate; int bitrate; - /* 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 */ - int channels; - int lfechannels; - int channelsused; + /* src_discrete_front_channels: The # of discrete front channels in the source audio + src_discrete_rear_channels: The # of discrete rear channels in the source audio + src_discrete_lfe_channels: The # of discrete lfe channels in the source audio + src_encoded_front_channels: The # of front channels encoded into the source audio + src_encoded_rear_channels: The # of rear channels encoded into the source audio */ + int src_discrete_front_channels; + int src_discrete_rear_channels; + int src_discrete_lfe_channels; + int src_encoded_front_channels; + int src_encoded_rear_channels; #ifdef __LIBHB__ /* Internal data */ @@ -243,6 +281,10 @@ struct hb_audio_s hb_esconfig_t config; hb_mux_data_t * mux_data; + + /* amixdown is the mixdown format to be used for this audio track */ + int amixdown; + #endif }; @@ -381,6 +423,9 @@ struct hb_work_object_s hb_fifo_t * fifo_out; hb_esconfig_t * config; + /* amixdown is the mixdown format to be used if the work object is an audio track */ + int amixdown; + hb_work_private_t * private_data; hb_thread_t * thread; diff --git a/libhb/deca52.c b/libhb/deca52.c index 0664584c9..5b5f080bc 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -29,7 +29,7 @@ struct hb_work_private_s hb_list_t * list; - int channelsused; + int out_discrete_channels; }; @@ -69,27 +69,11 @@ int deca52Init( hb_work_object_t * w, hb_job_t * job ) /* Decide what format we want out of a52dec work.c has already done some of this deduction for us in do_job() */ - if (w->config->a52.channelsused == 6) { - /* we're going to be encoding to a 6ch-supporting format, - and have turned on the "preserve 5.1" flag */ - pv->flags_out = A52_3F2R | A52_LFE; - } else if (w->config->a52.channelsused == 1) { - /* we're going to be encoding to a 1ch-supporting format, - so mix down to a mono track */ - pv->flags_out = A52_MONO; - } else if (w->config->a52.channelsused == 2 && w->config->a52.channels == 5 && w->config->a52.lfechannels == 1) { - /* we are mixing a 5.1 source down to stereo, so use dolby surround */ - pv->flags_out = A52_DOLBY; - } else if (w->config->a52.channelsused == 2 && ((w->config->a52.ac3flags & A52_CHANNEL_MASK) == A52_DOLBY)) { - /* we have a dolby stereo surround source, so preserve it */ - pv->flags_out = A52_DOLBY; - } else { - /* mix everything else down to plain stereo */ - pv->flags_out = A52_STEREO; - } + pv->flags_out = HB_AMIXDOWN_GET_A52_FORMAT(w->amixdown); /* pass the number of channels used into the private work data */ - pv->channelsused = w->config->a52.channelsused; + /* will only be actually used if we're not doing AC3 passthru */ + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown); pv->level = 32768.0; @@ -206,7 +190,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) a52_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 ); /* 6 blocks per frame, 256 samples per block, channelsused channels */ - buf = hb_buffer_init( 6 * 256 * pv->channelsused * sizeof( float ) ); + buf = hb_buffer_init( 6 * 256 * pv->out_discrete_channels * sizeof( float ) ); buf->start = pts + ( pos / pv->size ) * 6 * 256 * 90000 / pv->rate; buf->stop = buf->start + 6 * 256 * 90000 / pv->rate; @@ -217,14 +201,14 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) a52_block( pv->state ); samples_in = a52_samples( pv->state ); - samples_out = ((float *) buf->data) + 256 * pv->channelsused * i; + samples_out = ((float *) buf->data) + 256 * pv->out_discrete_channels * i; /* Interleave */ for( j = 0; j < 256; j++ ) { - for ( k = 0; k < pv->channelsused; k++ ) + for ( k = 0; k < pv->out_discrete_channels; k++ ) { - samples_out[(pv->channelsused*j)+k] = samples_in[(256*k)+j]; // DJA + samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j]; // DJA } } } diff --git a/libhb/encfaac.c b/libhb/encfaac.c index 7ed9853d7..d46e8aedd 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -20,7 +20,7 @@ struct hb_work_private_s hb_list_t * list; int64_t pts; - int channelsused; + int out_discrete_channels; }; @@ -54,9 +54,9 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) pv->job = job; /* pass the number of channels used into the private work data */ - pv->channelsused = w->config->aac.channelsused; + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown); - pv->faac = faacEncOpen( job->arate, pv->channelsused, &pv->input_samples, + pv->faac = faacEncOpen( job->arate, pv->out_discrete_channels, &pv->input_samples, &pv->output_bytes ); pv->buf = malloc( pv->input_samples * sizeof( float ) ); @@ -65,7 +65,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) cfg->aacObjectType = LOW; cfg->allowMidside = 1; - if (pv->channelsused == 6) { + if (pv->out_discrete_channels == 6) { /* we are preserving 5.1 audio into 6-channel AAC, so indicate that we have an lfe channel */ cfg->useLfe = 1; @@ -74,12 +74,12 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) } cfg->useTns = 0; - cfg->bitRate = job->abitrate * 1000 / pv->channelsused; /* Per channel */ + cfg->bitRate = job->abitrate * 1000 / pv->out_discrete_channels; /* Per channel */ cfg->bandWidth = 0; cfg->outputFormat = 0; cfg->inputFormat = FAAC_INPUT_FLOAT; - if (pv->channelsused == 6) { + if (pv->out_discrete_channels == 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 */ @@ -147,8 +147,8 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) &pts, &pos ); buf = hb_buffer_init( pv->output_bytes ); - 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->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / pv->job->arate; + buf->stop = buf->start + 90000 * pv->input_samples / pv->job->arate / pv->out_discrete_channels; buf->size = faacEncEncode( pv->faac, (int32_t *) pv->buf, pv->input_samples, buf->data, pv->output_bytes ); buf->key = 1; diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c index 169cb938f..df91e14e8 100644 --- a/libhb/encvorbis.c +++ b/libhb/encvorbis.c @@ -37,7 +37,7 @@ struct hb_work_private_s uint64_t pts; hb_list_t * list; - int channelsused; + int out_discrete_channels; int channel_map[6]; }; @@ -48,7 +48,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; - pv->channelsused = w->config->vorbis.channelsused; + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown); pv->job = job; @@ -56,7 +56,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) /* init */ vorbis_info_init( &pv->vi ); - if( vorbis_encode_setup_managed( &pv->vi, pv->channelsused, + if( vorbis_encode_setup_managed( &pv->vi, pv->out_discrete_channels, job->arate, -1, 1000 * job->abitrate, -1 ) || vorbis_encode_ctl( &pv->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) || vorbis_encode_setup_init( &pv->vi ) ) @@ -84,12 +84,12 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) header[i].packet, header[i].bytes ); } - pv->input_samples = pv->channelsused * OGGVORBIS_FRAME_SIZE; + pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE; pv->buf = malloc( pv->input_samples * sizeof( float ) ); pv->list = hb_list_init(); - switch (pv->channelsused) { + switch (pv->out_discrete_channels) { case 1: pv->channel_map[0] = 0; break; @@ -102,7 +102,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) pv->channel_map[5] = 3; break; default: - hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->channelsused); + hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->out_discrete_channels); case 2: // Assume stereo pv->channel_map[0] = 0; @@ -199,9 +199,9 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) buffer = vorbis_analysis_buffer( &pv->vd, OGGVORBIS_FRAME_SIZE ); for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) { - for( j = 0; j < pv->channelsused; j++) + for( j = 0; j < pv->out_discrete_channels; j++) { - buffer[j][i] = ((float *) pv->buf)[(pv->channelsused * i + pv->channel_map[j])] / 32768.f; + buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->channel_map[j])] / 32768.f; } } vorbis_analysis_wrote( &pv->vd, OGGVORBIS_FRAME_SIZE ); diff --git a/libhb/internal.h b/libhb/internal.h index 577ad3032..bc6f5063c 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -119,6 +119,7 @@ void hb_dvd_close( hb_dvd_t ** ); #define HB_CONFIG_MAX_SIZE 8192 union hb_esconfig_u { + struct { uint8_t bytes[HB_CONFIG_MAX_SIZE]; @@ -137,29 +138,20 @@ union hb_esconfig_u { uint8_t bytes[HB_CONFIG_MAX_SIZE]; int length; - /* Total channels actually used for this audio track */ - int channelsused; - int lfechannels; } aac; struct { uint8_t headers[3][HB_CONFIG_MAX_SIZE]; - int channelsused; char *language; } vorbis; struct { - /* indicates the number of normal channels the source audio has */ - int channels; - /* indicates the number of lfe channels the source audio has */ - int lfechannels; - /* ac3flags: stores the flags from the AC3 source, as found in scan.c */ + /* ac3flags stores the flags from the AC3 source, as found in scan.c */ int ac3flags; - /* Total channels actually used for this audio track */ - int channelsused; } a52; + }; enum diff --git a/libhb/muxavi.c b/libhb/muxavi.c index 8746a3cdd..214393d68 100644 --- a/libhb/muxavi.c +++ b/libhb/muxavi.c @@ -369,7 +369,7 @@ static int AVIInit( hb_mux_object_t * m ) { f.BytesCount = sizeof( hb_wave_formatex_t ) - 8; f.FormatTag = 0x2000; - f.Channels = audio->channels; + f.Channels = 2; f.SamplesPerSec = audio->rate; } else diff --git a/libhb/scan.c b/libhb/scan.c index e969a4380..9e9f9542a 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -468,39 +468,76 @@ static void LookForAC3( hb_title_t * title, hb_buffer_t * b ) case A52_MONO: case A52_CHANNEL1: case A52_CHANNEL2: - audio->channels = 1; + audio->src_discrete_front_channels = 1; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 1; + audio->src_encoded_rear_channels = 0; break; case A52_STEREO: - case A52_DOLBY: case A52_CHANNEL: - audio->channels = 2; + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 0; + break; + case A52_DOLBY: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; break; case A52_3F: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 0; + break; case A52_2F1R: - audio->channels = 3; + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 1; break; case A52_3F1R: - case A52_2F2R: - audio->channels = 4; + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; + break; + case A52_2F2R: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 2; break; case A52_3F2R: - audio->channels = 5; + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 2; break; } if (flags & A52_LFE) { - audio->lfechannels = 1; + audio->src_discrete_lfe_channels = 1; } else { - audio->lfechannels = 0; + audio->src_discrete_lfe_channels = 0; } - /* store the AC3 tags for future reference + /* store the AC3 FLAGS for future reference This enables us to find out if we had a stereo or Dolby source later on */ audio->config.a52.ac3flags = flags; /* XXX */ - sprintf( audio->lang + strlen( audio->lang ), - " (%d.%d ch)", audio->channels, audio->lfechannels ); + if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) { + sprintf( audio->lang + strlen( audio->lang ), + " (Dolby Surround)" ); + } else { + sprintf( audio->lang + strlen( audio->lang ), + " (%d.%d ch)", + audio->src_discrete_front_channels + audio->src_discrete_rear_channels, audio->src_discrete_lfe_channels ); + } + break; } } diff --git a/libhb/sync.c b/libhb/sync.c index b8f49fd01..79423b70c 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -196,7 +196,7 @@ static void InitAudio( hb_work_object_t * w, int i ) c->bit_rate = sync->audio->bitrate; c->sample_rate = sync->audio->rate; - c->channels = sync->audio->channels; + c->channels = 2; if( avcodec_open( c, codec ) < 0 ) { @@ -224,7 +224,7 @@ static void InitAudio( hb_work_object_t * w, int i ) { /* Initialize libsamplerate */ int error; - sync->state = src_new( SRC_LINEAR, sync->audio->channelsused, &error ); + sync->state = src_new( SRC_LINEAR, HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown), &error ); sync->data.end_of_input = 0; } } @@ -502,7 +502,7 @@ static void SyncAudio( hb_work_object_t * w, int i ) int count_in, count_out; - count_in = buf_raw->size / audio->channelsused / sizeof( float ); + count_in = buf_raw->size / HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) / sizeof( float ); count_out = ( buf_raw->stop - buf_raw->start ) * job->arate / 90000; if( buf->start < pts_expected - 1500 ) count_out--; @@ -516,7 +516,7 @@ static void SyncAudio( hb_work_object_t * w, int i ) sync->data.src_ratio = (double) sync->data.output_frames / (double) sync->data.input_frames; - buf = hb_buffer_init( sync->data.output_frames * audio->channelsused * + buf = hb_buffer_init( sync->data.output_frames * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) * sizeof( float ) ); sync->data.data_out = (float *) buf->data; if( src_process( sync->state, &sync->data ) ) @@ -526,7 +526,7 @@ static void SyncAudio( hb_work_object_t * w, int i ) } hb_buffer_close( &buf_raw ); - buf->size = sync->data.output_frames_gen * audio->channelsused * sizeof( float ); + buf->size = sync->data.output_frames_gen * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) * sizeof( float ); /* Set dates for resampled data */ buf->start = start; @@ -609,7 +609,7 @@ static void InsertSilence( hb_work_object_t * w, int i ) } else { - buf = hb_buffer_init( sync->audio->channelsused * job->arate / 20 * + buf = hb_buffer_init( HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown) * job->arate / 20 * sizeof( float ) ); buf->start = sync->count_frames * 90000 / job->arate; buf->stop = buf->start + 90000 / 20; diff --git a/libhb/work.c b/libhb/work.c index 0a9392187..1ab422a66 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -5,6 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #include "hb.h" +#include "a52dec/a52.h" typedef struct { @@ -89,7 +90,7 @@ static hb_work_object_t * getWork( int id ) static void do_job( hb_job_t * job, int cpu_count ) { hb_title_t * title; - int i; + int i, j; hb_work_object_t * w; /* FIXME: This feels really hackish, anything better? */ @@ -218,7 +219,144 @@ static void do_job( hb_job_t * job, int cpu_count ) { audio = hb_list_item( title->list_audio, i ); hb_log( " + %x, %s", audio->id, audio->lang ); + + /* sense-check the current mixdown options */ + + /* log the requested mixdown */ + for (j = 0; j < hb_audio_mixdowns_count; j++) { + if (hb_audio_mixdowns[j].amixdown == job->audio_mixdowns[i]) { + hb_log( " + Requested mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name ); + break; + } + } + + if(audio->codec != HB_ACODEC_AC3) { + + /* assume a stereo input and output for non-AC3 audio input (LPCM, MP2), + regardless of the mixdown passed to us */ + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + + } else { + + /* sense-check the AC3 mixdown */ + + /* audioCodecSupportsMono and audioCodecSupports6Ch are the same for now, + but this may change in the future, so they are separated for flexibility */ + int audioCodecSupportsMono = (job->acodec == HB_ACODEC_FAAC); + int audioCodecSupports6Ch = (job->acodec == HB_ACODEC_FAAC); + + /* find out what the format of our source AC3 audio is */ + switch (audio->config.a52.ac3flags & A52_CHANNEL_MASK) { + + /* mono sources */ + case A52_MONO: + case A52_CHANNEL1: + case A52_CHANNEL2: + /* regardless of what stereo mixdown we've requested, a mono source always get mixed down + to mono if we can, and mixed up to stereo if we can't */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 1) { + job->audio_mixdowns[i] = HB_AMIXDOWN_MONO; + } else { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + break; + + /* stereo input */ + case A52_CHANNEL: + case A52_STEREO: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use stereo if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + /* otherwise, preserve stereo regardless of if we requested something higher */ + } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_STEREO) { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + break; + + /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */ + /* the A52 flags don't allow for a way to distinguish between DPL1 and DPL2 on a DVD, + so we always assume a DPL1 source for A52_DOLBY */ + case A52_DOLBY: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* preserve dolby if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + /* otherwise, preserve dolby even if we requested something higher */ + /* a stereo mixdown will still be honoured here */ + } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } + break; + + /* 3F/2R input */ + case A52_3F2R: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use dpl2 if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } else { + /* check if we have 3F2R input and also have an LFE - i.e. we have a 5.1 source) */ + if (audio->config.a52.ac3flags & A52_LFE) { + /* we have a 5.1 source */ + /* if we requested 6ch, but our audio format doesn't support it, then mix to DPLII instead */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_6CH && audioCodecSupports6Ch == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } + } else { + /* we have a 5.0 source, so we can't do 6ch conversion + default to DPL II instead */ + if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBYPLII) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } + } + } + /* all other mixdowns will have been preserved here */ + break; + + /* 3F/1R input */ + case A52_3F1R: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use dpl1 if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } else { + /* we have a 4.0 or 4.1 source, so we can't do DPLII or 6ch conversion + default to DPL I instead */ + if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } + } + /* all other mixdowns will have been preserved here */ + break; + + default: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 1) { + job->audio_mixdowns[i] = HB_AMIXDOWN_MONO; + /* mix everything else down to stereo */ + } else { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + + } + } + + /* log the output mixdown */ + for (j = 0; j < hb_audio_mixdowns_count; j++) { + if (hb_audio_mixdowns[j].amixdown == job->audio_mixdowns[i]) { + hb_log( " + Actual mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name ); + break; + } + } + + /* we now know we have a valid mixdown for the input source and the audio output format */ + /* remember the mixdown for this track */ + audio->amixdown = job->audio_mixdowns[i]; + + audio->config.vorbis.language = audio->lang_simple; + /* set up the audio work structures */ audio->fifo_in = hb_fifo_init( 2048 ); audio->fifo_raw = hb_fifo_init( 8 ); audio->fifo_sync = hb_fifo_init( 8 ); @@ -239,6 +377,7 @@ static void do_job( hb_job_t * job, int cpu_count ) w->fifo_in = audio->fifo_in; w->fifo_out = audio->fifo_raw; w->config = &audio->config; + w->amixdown = audio->amixdown; /* FIXME: This feels really hackish, anything better? */ audio_w = calloc( sizeof( hb_work_object_t ), 1 ); @@ -258,11 +397,13 @@ static void do_job( hb_job_t * job, int cpu_count ) w = getWork( WORK_ENCVORBIS ); break; } + if( job->acodec != HB_ACODEC_AC3 ) { w->fifo_in = audio->fifo_sync; w->fifo_out = audio->fifo_out; w->config = &audio->config; + w->amixdown = audio->amixdown; /* FIXME: This feels really hackish, anything better? */ audio_w = calloc( sizeof( hb_work_object_t ), 1 ); @@ -270,48 +411,8 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_list_add( job->list_work, audio_w ); } - - /* store this audio's channel counts in the audio struct */ - - /* we will only end up with a channelsused value other than 2 - if we are encoding to AAC or OGM. All other audio encodings will get - a stereo mix. */ - - if (audio->channels == 5 && audio->lfechannels == 1) { - /* we have a 5.1 AC-3 source soundtrack */ - if ((job->acodec == HB_ACODEC_FAAC || job->acodec == HB_ACODEC_VORBIS) && job->surround) { - /* we're going to be encoding to a 6ch-supporting format, - and have turned on the "preserve 5.1" flag */ - audio->channelsused = 6; - } else { - /* mix 5.1 down to Dolby Digital (2-channel) */ - audio->channelsused = 2; - } - } else if (audio->channels == 1 && audio->lfechannels == 0) { - /* we have a 1.0 mono AC-3 source soundtrack */ - if (job->acodec == HB_ACODEC_FAAC || job->acodec == HB_ACODEC_VORBIS) { - /* we're going to be encoding to a 1ch-supporting format, - so mix down to a mono track */ - audio->channelsused = 1; - } else { - /* mix up the mono track to stereo */ - audio->channelsused = 2; - } - } else { - /* mix everything else down to stereo */ - /* dolby pro-logic will be preserved in deca52.c if necessary - by referring to the value of audio->config->a52.ac3flags */ - audio->channelsused = 2; - } - - /* remember the number of source channels, so that deca52.c knows what source we had */ - audio->config.a52.channels = audio->channels; - audio->config.a52.lfechannels = audio->lfechannels; - - /* pass round the number of channels we actually used */ - audio->config.aac.channelsused = audio->config.a52.channelsused = audio->config.vorbis.channelsused = audio->channelsused; - audio->config.vorbis.language = audio->lang_simple; - + + } /* Init read & write threads */ -- cgit v1.2.3