diff options
author | Jean-Francois Thibert <jfthibert@google.com> | 2014-08-26 19:16:06 -0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2014-08-27 14:31:39 +0200 |
commit | 12df9b9a151026c4b382df8852fad38165b49f95 (patch) | |
tree | 5b2f03eae9dc3e3eb44cdb0b1cd930a5d0e03012 | |
parent | 7a67ab5cba8ed5509be5d058fe9e5612ef39d3b0 (diff) | |
download | ffmpeg-12df9b9a151026c4b382df8852fad38165b49f95.tar.gz |
Improved AC3 decoder level support (heavy drc, dialnorm)
Added support for AC3 heavy dynamic range compression used
to restrict the output range and added a setting to specify
the output target level and use the dialog normalization
field to apply it in the digital domain.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavcodec/ac3.h | 4 | ||||
-rw-r--r-- | libavcodec/ac3dec.c | 45 | ||||
-rw-r--r-- | libavcodec/ac3dec.h | 7 | ||||
-rw-r--r-- | libavcodec/ac3dec_fixed.c | 99 | ||||
-rw-r--r-- | libavcodec/ac3dec_float.c | 2 |
5 files changed, 112 insertions, 45 deletions
diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h index 542f79d711..871640b8c8 100644 --- a/libavcodec/ac3.h +++ b/libavcodec/ac3.h @@ -67,7 +67,8 @@ #define AC3_RENAME(x) x ## _fixed #define AC3_NORM(norm) (1<<24)/(norm) #define AC3_MUL(a,b) ((((int64_t) (a)) * (b))>>12) -#define AC3_RANGE(x) (x) +#define AC3_RANGE(x) (x|((x&128)<<1)) +#define AC3_HEAVY_RANGE(x) (x<<1) #define AC3_DYNAMIC_RANGE(x) (x) #define AC3_SPX_BLEND(x) (x) #define AC3_DYNAMIC_RANGE1 0 @@ -86,6 +87,7 @@ #define AC3_NORM(norm) (1.0f/(norm)) #define AC3_MUL(a,b) ((a) * (b)) #define AC3_RANGE(x) (dynamic_range_tab[(x)]) +#define AC3_HEAVY_RANGE(x) (heavy_dynamic_range_tab[(x)]) #define AC3_DYNAMIC_RANGE(x) (powf(x, s->drc_scale)) #define AC3_SPX_BLEND(x) (x)* (1.0f/32) #define AC3_DYNAMIC_RANGE1 1.0f diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index 72c41850cd..969e37ffb8 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -65,6 +65,7 @@ static const uint8_t quantization_tab[16] = { /** dynamic range table. converts codes to scale factors. */ static float dynamic_range_tab[256]; +static float heavy_dynamic_range_tab[256]; /** Adjustments in dB gain */ static const float gain_levels[9] = { @@ -164,6 +165,14 @@ static av_cold void ac3_tables_init(void) int v = (i >> 5) - ((i >> 7) << 3) - 5; dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0x1F) | 0x20); } + + /* generate compr dynamic range table + reference: Section 7.7.2 Heavy Compression */ + for (i = 0; i < 256; i++) { + int v = (i >> 4) - ((i >> 7) << 4) - 4; + heavy_dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0xF) | 0x10); + } + } /** @@ -236,9 +245,19 @@ static int ac3_parse_header(AC3DecodeContext *s) /* read the rest of the bsi. read twice for dual mono mode. */ i = !s->channel_mode; do { - skip_bits(gbc, 5); // skip dialog normalization - if (get_bits1(gbc)) - skip_bits(gbc, 8); //skip compression + s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5); + if (s->dialog_normalization[(!s->channel_mode)-i] == 0) { + s->dialog_normalization[(!s->channel_mode)-i] = -31; + } + if (s->target_level != 0) { + s->level_gain[(!s->channel_mode)-i] = powf(2.0f, + (float)(s->target_level - + s->dialog_normalization[(!s->channel_mode)-i])/6.0f); + } + if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) { + s->heavy_dynamic_range[(!s->channel_mode)-i] = + AC3_HEAVY_RANGE(get_bits(gbc, 8)); + } if (get_bits1(gbc)) skip_bits(gbc, 8); //skip language code if (get_bits1(gbc)) @@ -819,8 +838,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk) if (get_bits1(gbc)) { /* Allow asymmetric application of DRC when drc_scale > 1. Amplification of quiet sounds is enhanced */ - INTFLOAT range = AC3_RANGE(get_bits(gbc, 8)); - if (range > 1.0 || s->drc_scale <= 1.0) + int range_bits = get_bits(gbc, 8); + INTFLOAT range = AC3_RANGE(range_bits); + if (range_bits <= 127 || s->drc_scale <= 1.0) s->dynamic_range[i] = AC3_DYNAMIC_RANGE(range); else s->dynamic_range[i] = range; @@ -1314,15 +1334,20 @@ static int decode_audio_block(AC3DecodeContext *s, int blk) /* apply scaling to coefficients (headroom, dynrng) */ for (ch = 1; ch <= s->channels; ch++) { + int audio_channel = 0; INTFLOAT gain; - if(s->channel_mode == AC3_CHMODE_DUALMONO) { - gain = s->dynamic_range[2-ch]; - } else { - gain = s->dynamic_range[0]; - } + if (s->channel_mode == AC3_CHMODE_DUALMONO) + audio_channel = 2-ch; + if (s->heavy_compression && s->compression_exists[audio_channel]) + gain = s->heavy_dynamic_range[audio_channel]; + else + gain = s->dynamic_range[audio_channel]; + #if USE_FIXED scale_coefs(s->transform_coeffs[ch], s->fixed_coeffs[ch], gain, 256); #else + if (s->target_level != 0) + gain = gain * s->level_gain[audio_channel]; gain *= 1.0 / 4194304.0f; s->fmt_conv.int32_to_float_fmul_scalar(s->transform_coeffs[ch], s->fixed_coeffs[ch], gain, 256); diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h index 3ac44ee17e..a213bc0870 100644 --- a/libavcodec/ac3dec.h +++ b/libavcodec/ac3dec.h @@ -84,6 +84,9 @@ typedef struct AC3DecodeContext { int bitstream_mode; ///< bitstream mode (bsmod) int channel_mode; ///< channel mode (acmod) int lfe_on; ///< lfe channel in use + int dialog_normalization[2]; ///< dialog level in dBFS (dialnorm) + int compression_exists[2]; ///< compression field is valid for frame (compre) + int compression_gain[2]; ///< gain to apply for heavy compression (compr) int channel_map; ///< custom channel map int preferred_downmix; ///< Preferred 2-channel downmix mode (dmixmod) int center_mix_level; ///< Center mix level index @@ -103,6 +106,8 @@ typedef struct AC3DecodeContext { float ltrt_surround_mix_level; float loro_center_mix_level; float loro_surround_mix_level; + int target_level; ///< target level in dBFS + float level_gain[2]; ///@name Frame syntax parameters int snr_offset_strategy; ///< SNR offset strategy (snroffststr) @@ -161,6 +166,8 @@ typedef struct AC3DecodeContext { ///@name Dynamic range INTFLOAT dynamic_range[2]; ///< dynamic range INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied + int heavy_compression; ///< apply heavy compression + INTFLOAT heavy_dynamic_range[2]; ///< heavy dynamic range compression ///@} ///@name Bandwidth diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c index c6cbeb9b28..f36e7b0849 100644 --- a/libavcodec/ac3dec_fixed.c +++ b/libavcodec/ac3dec_fixed.c @@ -81,40 +81,69 @@ static void scale_coefs ( int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7; mul = (dynrng & 0x1f) + 0x20; - shift = 4 - ((dynrng << 24) >> 29); - round = 1 << (shift-1); - for (i=0; i<len; i+=8) { - - temp = src[i] * mul; - temp1 = src[i+1] * mul; - temp = temp + round; - temp2 = src[i+2] * mul; - - temp1 = temp1 + round; - dst[i] = temp >> shift; - temp3 = src[i+3] * mul; - temp2 = temp2 + round; - - dst[i+1] = temp1 >> shift; - temp4 = src[i + 4] * mul; - temp3 = temp3 + round; - dst[i+2] = temp2 >> shift; - - temp5 = src[i+5] * mul; - temp4 = temp4 + round; - dst[i+3] = temp3 >> shift; - temp6 = src[i+6] * mul; - - dst[i+4] = temp4 >> shift; - temp5 = temp5 + round; - temp7 = src[i+7] * mul; - temp6 = temp6 + round; - - dst[i+5] = temp5 >> shift; - temp7 = temp7 + round; - dst[i+6] = temp6 >> shift; - dst[i+7] = temp7 >> shift; - + shift = 4 - ((dynrng << 23) >> 28); + if (shift > 0 ) { + round = 1 << (shift-1); + for (i=0; i<len; i+=8) { + + temp = src[i] * mul; + temp1 = src[i+1] * mul; + temp = temp + round; + temp2 = src[i+2] * mul; + + temp1 = temp1 + round; + dst[i] = temp >> shift; + temp3 = src[i+3] * mul; + temp2 = temp2 + round; + + dst[i+1] = temp1 >> shift; + temp4 = src[i + 4] * mul; + temp3 = temp3 + round; + dst[i+2] = temp2 >> shift; + + temp5 = src[i+5] * mul; + temp4 = temp4 + round; + dst[i+3] = temp3 >> shift; + temp6 = src[i+6] * mul; + + dst[i+4] = temp4 >> shift; + temp5 = temp5 + round; + temp7 = src[i+7] * mul; + temp6 = temp6 + round; + + dst[i+5] = temp5 >> shift; + temp7 = temp7 + round; + dst[i+6] = temp6 >> shift; + dst[i+7] = temp7 >> shift; + + } + } else { + shift = -shift; + for (i=0; i<len; i+=8) { + + temp = src[i] * mul; + temp1 = src[i+1] * mul; + temp2 = src[i+2] * mul; + + dst[i] = temp << shift; + temp3 = src[i+3] * mul; + + dst[i+1] = temp1 << shift; + temp4 = src[i + 4] * mul; + dst[i+2] = temp2 << shift; + + temp5 = src[i+5] * mul; + dst[i+3] = temp3 << shift; + temp6 = src[i+6] * mul; + + dst[i+4] = temp4 << shift; + temp7 = src[i+7] * mul; + + dst[i+5] = temp5 << shift; + dst[i+6] = temp6 << shift; + dst[i+7] = temp7 << shift; + + } } } @@ -150,6 +179,8 @@ static void ac3_downmix_c_fixed16(int16_t **samples, int16_t (*matrix)[2], #include "ac3dec.c" static const AVOption options[] = { + { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, + { "heavy_compr", "heavy dynamic range compression enabled", OFFSET(heavy_compression), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, PAR }, { NULL}, }; diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c index 7108921701..e7fc5cbed1 100644 --- a/libavcodec/ac3dec_float.c +++ b/libavcodec/ac3dec_float.c @@ -32,6 +32,8 @@ static const AVOption options[] = { { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, + { "heavy_compr", "heavy dynamic range compression enabled", OFFSET(heavy_compression), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, PAR }, + { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR }, {"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, 0, "dmix_mode"}, {"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, |