diff options
author | Rodeo <[email protected]> | 2012-08-02 21:43:22 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2012-08-02 21:43:22 +0000 |
commit | b3717d369763d620d548f224daeba5a7503fa972 (patch) | |
tree | 4742e9b49e03db2b1c558e10f40c2c821528e8f5 /libhb | |
parent | ad257c9dac38fe3f7502b1058247b4458465c0a8 (diff) |
Use hb_audio_resample for downmixing AC3 sources. DRC is still applied by liba52.
Add support for center & surround mix levels to hb_audio_resample.
This allows us to support upmixing all audio sources. For sources that have at least 2 front and one back or side channel(s), allow upmixing to 5.1:
3.0/3.1 (2 front and 1 back channels)
4.0/4.1 (3 front and 1 back channels)
4.0/4.1 (2 front and 2 side channels)
5.0 (3 front and 2 side channels)
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4885 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/audio_resample.c | 19 | ||||
-rw-r--r-- | libhb/audio_resample.h | 10 | ||||
-rw-r--r-- | libhb/common.c | 37 | ||||
-rw-r--r-- | libhb/deca52.c | 296 | ||||
-rw-r--r-- | libhb/decavcodec.c | 1 | ||||
-rw-r--r-- | libhb/declpcm.c | 3 | ||||
-rw-r--r-- | libhb/encavcodecaudio.c | 3 |
7 files changed, 200 insertions, 169 deletions
diff --git a/libhb/audio_resample.c b/libhb/audio_resample.c index ea09b38a2..072351192 100644 --- a/libhb/audio_resample.c +++ b/libhb/audio_resample.c @@ -18,7 +18,10 @@ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fm { hb_audio_resample_t *resample = malloc(sizeof(hb_audio_resample_t)); if (resample == NULL) + { + hb_error("hb_audio_resample_init: failed to allocate resample"); return NULL; + } resample->out.sample_fmt = output_sample_fmt; resample->out.sample_size = @@ -37,6 +40,8 @@ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fm int hb_audio_resample_update(hb_audio_resample_t *resample, enum AVSampleFormat new_sample_fmt, uint64_t new_channel_layout, + double new_surroundmixlev, + double new_centermixlev, int new_channels) { if (resample == NULL) @@ -55,7 +60,9 @@ int hb_audio_resample_update(hb_audio_resample_t *resample, int resample_changed = (resample->resample_needed && (resample->in.sample_fmt != new_sample_fmt || - resample->in.channel_layout != new_channel_layout)); + resample->in.channel_layout != new_channel_layout || + resample->in.center_mix_level != new_centermixlev || + resample->in.surround_mix_level != new_surroundmixlev)); if (resample_changed || (resample->resample_needed && resample->avresample == NULL)) @@ -87,6 +94,10 @@ int hb_audio_resample_update(hb_audio_resample_t *resample, new_sample_fmt, 0); av_opt_set_int(resample->avresample, "in_channel_layout", new_channel_layout, 0); + av_opt_set_double(resample->avresample, "center_mix_level", + new_centermixlev, 0); + av_opt_set_double(resample->avresample, "surround_mix_level", + new_surroundmixlev, 0); if (avresample_open(resample->avresample) < 0) { @@ -96,8 +107,10 @@ int hb_audio_resample_update(hb_audio_resample_t *resample, return 1; } - resample->in.sample_fmt = new_sample_fmt; - resample->in.channel_layout = new_channel_layout; + resample->in.sample_fmt = new_sample_fmt; + resample->in.channel_layout = new_channel_layout; + resample->in.center_mix_level = new_centermixlev; + resample->in.surround_mix_level = new_surroundmixlev; } return 0; diff --git a/libhb/audio_resample.h b/libhb/audio_resample.h index 4b1586e73..29a7f91d0 100644 --- a/libhb/audio_resample.h +++ b/libhb/audio_resample.h @@ -17,10 +17,14 @@ #ifndef AUDIO_RESAMPLE_H #define AUDIO_RESAMPLE_H +#include <math.h> #include <stdint.h> #include "libavutil/audioconvert.h" #include "libavresample/avresample.h" +/* Default mix level for center and surround channels */ +#define HB_MIXLEV_DEFAULT ((double)M_SQRT1_2) + typedef struct { int resample_needed; @@ -31,6 +35,8 @@ typedef struct int channels; int linesize; uint64_t channel_layout; + double center_mix_level; + double surround_mix_level; enum AVSampleFormat sample_fmt; } in; @@ -46,7 +52,7 @@ typedef struct } out; } hb_audio_resample_t; -/* Initialize an hb_audio_resample_t to convert audio to the requested +/* Initialize an hb_audio_resample_t for converting audio to the requested * sample_fmt and channel_layout, using the specified matrix_encoding. * * Input characteristics are set via hb_audio_resample_update(). @@ -65,6 +71,8 @@ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fm int hb_audio_resample_update(hb_audio_resample_t *resample, enum AVSampleFormat new_sample_fmt, uint64_t new_channel_layout, + double new_surroundmixlev, + double new_centermixlev, int new_channels); /* Free an hb_audio_remsample_t. */ diff --git a/libhb/common.c b/libhb/common.c index 9ff9f44a3..6315498cc 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -722,43 +722,36 @@ int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown) // Audio passthrough, no mixdown return HB_AMIXDOWN_NONE; } - else if ((layout & AV_CH_LAYOUT_5POINT1) == AV_CH_LAYOUT_5POINT1 || - (layout & AV_CH_LAYOUT_5POINT1_BACK) == AV_CH_LAYOUT_5POINT1_BACK) + else if ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 || + (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 || + (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD) { - // full 3F2R, possibly with additional channels, and an LFE - // limiting factor: liba52, libdca (can't upmix) - if (codec == HB_ACODEC_LAME || codec == HB_ACODEC_FFAAC) + // at least 2 front channels and one back or side channel + // allow downmixing or upmixing to 5.1 (yes, we can) + if (codec != HB_ACODEC_LAME && codec != HB_ACODEC_FFAAC) { - best_mixdown = HB_AMIXDOWN_DOLBYPLII; + best_mixdown = HB_AMIXDOWN_6CH; } else { - best_mixdown = HB_AMIXDOWN_6CH; + best_mixdown = HB_AMIXDOWN_DOLBYPLII; } } - else if ((layout & AV_CH_LAYOUT_5POINT0) == AV_CH_LAYOUT_5POINT0 || - (layout & AV_CH_LAYOUT_5POINT0_BACK) == AV_CH_LAYOUT_5POINT0_BACK) + else if (layout == AV_CH_LAYOUT_STEREO_DOWNMIX) { - // full 3F2R, possibly with additional channels, but no LFE - // limiting factor: liba52, libdca (can't upmix) - // limiting factor: libdca (can only do DPL2 with 3F2R sources) - best_mixdown = HB_AMIXDOWN_DOLBYPLII; + // Dolby in, allow Dolby out + best_mixdown = HB_AMIXDOWN_DOLBY; } - else if(layout == AV_CH_LAYOUT_STEREO) + else if (av_get_channel_layout_nb_channels(layout) > 1) { - // limiting factor: no Dolby Surround for Stereo sources + // more than one channel, allow Stereo downmix best_mixdown = HB_AMIXDOWN_STEREO; } - else if(av_get_channel_layout_nb_channels(layout) == 1) + else { // only one channel, not much point in upmixing best_mixdown = HB_AMIXDOWN_MONO; } - else - { - // everything else, including Dolby (AV_CH_LAYOUT_STEREO_DOWNMIX) - best_mixdown = HB_AMIXDOWN_DOLBY; - } // return the best that is not greater than the requested mixdown // HB_INVALID_AMIXDOWN means the caller requested the best available mixdown @@ -773,7 +766,7 @@ int hb_get_default_mixdown(uint32_t codec, uint64_t layout) int mixdown; switch (codec) { - // the AC3 encoder defaults to the best mixdown up to 6-channel + // the FLAC and AC3 encoders default to the best mixdown up to 6-channel case HB_ACODEC_FFFLAC: case HB_ACODEC_AC3: mixdown = HB_AMIXDOWN_6CH; diff --git a/libhb/deca52.c b/libhb/deca52.c index 0c1708de2..5f9960a91 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -9,6 +9,7 @@ #include "hb.h" #include "audio_remap.h" +#include "audio_resample.h" #include "a52dec/a52.h" #include "libavutil/crc.h" @@ -20,11 +21,9 @@ struct hb_work_private_s /* liba52 handle */ a52_state_t * state; - int flags_in; - int flags_out; + int flags; int rate; int bitrate; - int out_discrete_channels; int error; int frames; // number of good frames decoded int crc_errors; // number of frames with crc errors @@ -36,6 +35,11 @@ struct hb_work_private_s hb_list_t *list; const AVCRC *crc_table; uint8_t frame[3840]; + + int nchannels; + uint64_t channel_layout; + hb_audio_resample_t *resample; + int *remap_table; }; static int deca52Init( hb_work_object_t *, hb_job_t * ); @@ -55,6 +59,33 @@ hb_work_object_t hb_deca52 = deca52BSInfo }; +/* Translate acmod and lfeon on AV_CH_LAYOUT */ +static const uint64_t acmod2layout[] = +{ + AV_CH_LAYOUT_STEREO, // A52_CHANNEL (0) + AV_CH_LAYOUT_MONO, // A52_MONO (1) + AV_CH_LAYOUT_STEREO, // A52_STEREO (2) + AV_CH_LAYOUT_SURROUND, // A52_3F (3) + AV_CH_LAYOUT_2_1, // A52_2F1R (4) + AV_CH_LAYOUT_4POINT0, // A52_3F1R (5) + AV_CH_LAYOUT_2_2, // A52_2F2R (6) + AV_CH_LAYOUT_5POINT0, // A52_3F2R (7) + AV_CH_LAYOUT_MONO, // A52_CHANNEL1 (8) + AV_CH_LAYOUT_MONO, // A52_CHANNEL2 (9) + AV_CH_LAYOUT_STEREO_DOWNMIX, // A52_DOLBY (10) + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_STEREO, // A52_CHANNEL_MASK (15) +}; + +static const uint64_t lfeon2layout[] = +{ + 0, + AV_CH_LOW_FREQUENCY, +}; + /*********************************************************************** * Local prototypes **********************************************************************/ @@ -89,48 +120,36 @@ static sample_t dynrng_call (sample_t c, void *data) *********************************************************************** * Allocate the work object, initialize liba52 **********************************************************************/ -static int deca52Init( hb_work_object_t * w, hb_job_t * job ) +static int deca52Init(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; + hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); + hb_audio_t *audio = w->audio; w->private_data = pv; - pv->job = job; - - pv->crc_table = av_crc_get_table( AV_CRC_16_ANSI ); + pv->job = job; + pv->state = a52_init(0); pv->list = hb_list_init(); - pv->state = a52_init( 0 ); - pv->level = 1.0; - pv->dynamic_range_compression = audio->config.out.dynamic_range_compression; + pv->crc_table = av_crc_get_table(AV_CRC_16_ANSI); - /* Decide what format we want out of a52dec; - * work.c has already done some of this deduction for us in do_job(). */ - switch( audio->config.out.mixdown ) + /* Downmixing */ + if (audio->config.out.codec != HB_ACODEC_AC3_PASS) { - case HB_AMIXDOWN_6CH: - pv->flags_out = (A52_3F2R|A52_LFE); - break; - - case HB_AMIXDOWN_DOLBYPLII: - pv->flags_out = (A52_DOLBY|A52_USE_DPLII); - break; - - case HB_AMIXDOWN_DOLBY: - pv->flags_out = A52_DOLBY; - break; - - case HB_AMIXDOWN_MONO: - pv->flags_out = A52_MONO; - break; - - default: - pv->flags_out = A52_STEREO; - break; + /* We want AV_SAMPLE_FMT_FLT samples */ + pv->level = 1.0; + pv->dynamic_range_compression = + audio->config.out.dynamic_range_compression; + + int mode; + uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, &mode); + pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode, + audio->config.out.normalize_mix_level); + if (pv->resample == NULL) + { + hb_error("deca52Init: hb_audio_resample_init() failed"); + return 1; + } } - /* pass the number of channels used into the private work data */ - pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown ); - return 0; } @@ -139,19 +158,25 @@ static int deca52Init( hb_work_object_t * w, hb_job_t * job ) *********************************************************************** * Free memory **********************************************************************/ -static void deca52Close( hb_work_object_t * w ) +static void deca52Close(hb_work_object_t *w) { - hb_work_private_t * pv = w->private_data; + hb_work_private_t *pv = w->private_data; + w->private_data = NULL; - if ( pv->crc_errors ) + if (pv->crc_errors) { - hb_log( "deca52: %d frames decoded, %d crc errors, %d bytes dropped", - pv->frames, pv->crc_errors, pv->bytes_dropped ); + hb_log("deca52: %d frames decoded, %d crc errors, %d bytes dropped", + pv->frames, pv->crc_errors, pv->bytes_dropped); } - a52_free( pv->state ); - hb_list_empty( &pv->list ); - free( pv ); - w->private_data = NULL; + + if (pv->remap_table != NULL) + { + free(pv->remap_table); + } + hb_audio_resample_free(pv->resample); + hb_list_empty(&pv->list); + a52_free(pv->state); + free(pv); } /*********************************************************************** @@ -200,13 +225,12 @@ static int deca52Work( hb_work_object_t * w, hb_buffer_t ** buf_in, *********************************************************************** * **********************************************************************/ -static hb_buffer_t * Decode( hb_work_object_t * w ) +static hb_buffer_t* Decode(hb_work_object_t *w) { - hb_work_private_t * pv = w->private_data; - hb_buffer_t * buf; - hb_audio_t * audio = w->audio; - int i, j, k; - int size = 0; + hb_work_private_t *pv = w->private_data; + hb_audio_t *audio = w->audio; + hb_buffer_t *out; + int size = 0; // check that we're at the start of a valid frame and align to the // start of a valid frame if we're not. @@ -216,7 +240,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) { /* check if this is a valid header */ hb_list_seebytes( pv->list, pv->frame, 7 ); - size = a52_syncinfo( pv->frame, &pv->flags_in, &pv->rate, &pv->bitrate ); + size = a52_syncinfo(pv->frame, &pv->flags, &pv->rate, &pv->bitrate); if ( size > 0 ) { // header looks valid - check the crc1 @@ -277,65 +301,96 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) ipts = -1; } - double pts = ( ipts != -1 ) ? ipts : pv->next_expected_pts; double frame_dur = (6. * 256. * 90000.) / pv->rate; + double pts = (ipts != -1) ? (double)ipts : pv->next_expected_pts; /* AC3 passthrough: don't decode the AC3 frame */ - if( audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if (audio->config.out.codec == HB_ACODEC_AC3_PASS) { - buf = hb_buffer_init( size ); - memcpy( buf->data, pv->frame, size ); - buf->s.start = pts; - buf->s.duration = frame_dur; - pts += frame_dur; - buf->s.stop = pts; - pv->next_expected_pts = pts; - return buf; + out = hb_buffer_init(size); + memcpy(out->data, pv->frame, size); } - - /* Feed liba52 */ - a52_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 ); - - /* If a user specifies strong dynamic range compression (>1), adjust it. - If a user specifies default dynamic range compression (1), leave it alone. - If a user specifies no dynamic range compression (0), call a null function. */ - if( pv->dynamic_range_compression > 1.0 ) - { - a52_dynrng( pv->state, dynrng_call, &pv->dynamic_range_compression ); - } - else if( !pv->dynamic_range_compression ) + else { - a52_dynrng( pv->state, NULL, NULL ); - } + int i, j, k; + hb_buffer_t *flt; - /* 6 blocks per frame, 256 samples per block, channelsused channels */ - buf = hb_buffer_init( 6 * 256 * pv->out_discrete_channels * sizeof( float ) ); - buf->s.start = pts; - buf->s.duration = frame_dur; - pts += frame_dur; - buf->s.stop = pts; - pv->next_expected_pts = pts; + /* Feed liba52 */ + a52_frame(pv->state, pv->frame, &pv->flags, &pv->level, 0); - for( i = 0; i < 6; i++ ) - { - sample_t * samples_in; - float * samples_out; + /* If the user requested strong DRC (>1), adjust it. + * If the user requested default DRC (1), leave it alone. + * If the user requested no DRC (0), call a null function. */ + if (pv->dynamic_range_compression > 1.0) + { + a52_dynrng(pv->state, dynrng_call, &pv->dynamic_range_compression); + } + else if (!pv->dynamic_range_compression) + { + a52_dynrng(pv->state, NULL, NULL); + } + + /* Update input channel layout and prepare remapping */ + uint64_t new_layout = (acmod2layout[(pv->flags & A52_CHANNEL_MASK)] | + lfeon2layout[(pv->flags & A52_LFE) != 0]); + if (new_layout != pv->channel_layout) + { + if (pv->remap_table != NULL) + { + free(pv->remap_table); + } + pv->remap_table = hb_audio_remap_build_table(new_layout, + &hb_libav_chan_map, + &hb_liba52_chan_map); + if (pv->remap_table == NULL) + { + hb_error("deca52: hb_audio_remap_build_table() failed"); + return NULL; + } + pv->channel_layout = new_layout; + pv->nchannels = av_get_channel_layout_nb_channels(new_layout); + } - a52_block( pv->state ); - samples_in = a52_samples( pv->state ); - samples_out = ((float *) buf->data) + 256 * pv->out_discrete_channels * i; + /* 6 blocks per frame, 256 samples per block, pv->nchannels channels */ + flt = hb_buffer_init(1536 * pv->nchannels * sizeof(float)); - /* Interleave */ - for( j = 0; j < 256; j++ ) + for (i = 0; i < 6; i++) { - for ( k = 0; k < pv->out_discrete_channels; k++ ) + sample_t *samples_in; + float *samples_out; + + a52_block(pv->state); + samples_in = a52_samples(pv->state); + samples_out = ((float*)flt->data) + 256 * pv->nchannels * i; + + /* Planar -> interleaved, remap to Libav channel order */ + for (j = 0; j < 256; j++) { - samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j]; + for (k = 0; k < pv->nchannels; k++) + { + samples_out[(pv->nchannels*j)+k] = + samples_in[(256*pv->remap_table[k])+j]; + } } } + hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT, + pv->channel_layout, (double)pv->state->slev, + (double)pv->state->clev, pv->nchannels); + out = hb_audio_resample(pv->resample, (void*)flt->data, 1536); + hb_buffer_close(&flt); + } + if (out == NULL) + { + return NULL; } - return buf; + + out->s.start = pts; + out->s.duration = frame_dur; + pts += frame_dur; + out->s.stop = pts; + pv->next_expected_pts = pts; + return out; } static int find_sync( const uint8_t *buf, int len ) @@ -439,52 +494,11 @@ static int deca52BSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->mode = raw & 0x7; /* bsmod is the following 3 bits */ info->samples_per_frame = 1536; - switch( flags & A52_CHANNEL_MASK ) - { - /* mono sources */ - case A52_MONO: - case A52_CHANNEL1: - case A52_CHANNEL2: - info->channel_layout = AV_CH_LAYOUT_MONO; - break; - /* stereo input */ - case A52_CHANNEL: - case A52_STEREO: - info->channel_layout = AV_CH_LAYOUT_STEREO; - break; - /* Dolby Pro Logic (a.k.a. Dolby Surround), 4.0 channels (matrix-encoded) */ - case A52_DOLBY: - info->channel_layout = AV_CH_LAYOUT_STEREO_DOWNMIX; - break; - /* 3F/2R input */ - case A52_3F2R: - info->channel_layout = AV_CH_LAYOUT_5POINT0; - break; - /* 3F/1R input */ - case A52_3F1R: - info->channel_layout = AV_CH_LAYOUT_4POINT0; - break; - /* other inputs */ - case A52_3F: - info->channel_layout = AV_CH_LAYOUT_SURROUND; - break; - case A52_2F1R: - info->channel_layout = AV_CH_LAYOUT_2_1; - break; - case A52_2F2R: - info->channel_layout = AV_CH_LAYOUT_2_2; - break; - /* unknown */ - default: - info->channel_layout = AV_CH_LAYOUT_STEREO; - } - - if (flags & A52_LFE) - { - info->channel_layout |= AV_CH_LOW_FREQUENCY; - } + info->channel_layout = (acmod2layout[(flags & A52_CHANNEL_MASK)] | + lfeon2layout[(flags & A52_LFE) != 0]); - info->channel_map = &hb_liba52_chan_map; + // we remap to Libav order in Decode() + info->channel_map = &hb_libav_chan_map; return 1; } diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 934f7611e..5dc3b75b5 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -1454,6 +1454,7 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data, { hb_audio_resample_update(pv->resample, pv->context->sample_fmt, pv->context->channel_layout, + HB_MIXLEV_DEFAULT, HB_MIXLEV_DEFAULT, pv->context->channels); out = hb_audio_resample(pv->resample, (void*)frame.data[0], frame.nb_samples); diff --git a/libhb/declpcm.c b/libhb/declpcm.c index 0d4e449d1..1511a6abd 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -331,7 +331,8 @@ static hb_buffer_t *Decode( hb_work_object_t *w ) hb_buffer_t *out; hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT, - hdr2layout[pv->nchannels - 1], pv->nchannels); + hdr2layout[pv->nchannels - 1], HB_MIXLEV_DEFAULT, + HB_MIXLEV_DEFAULT, pv->nchannels); out = hb_audio_resample(pv->resample, (void*)pv->data, pv->nsamples); if (out == NULL) { diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index ef5297cca..8435b022d 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -121,7 +121,8 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) context->channel_layout, AV_MATRIX_ENCODING_NONE, 0); if (hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT, - context->channel_layout, context->channels)) + context->channel_layout, HB_MIXLEV_DEFAULT, + HB_MIXLEV_DEFAULT, context->channels)) { hb_error("encavcodecaInit: hb_audio_resample_update() failed"); hb_audio_resample_free(pv->resample); |