#include <math.h>
#include <string.h>
+#include "libavutil/channel_layout.h"
#include "libavutil/crc.h"
+#include "libavutil/downmix_info.h"
#include "libavutil/opt.h"
+#include "bswapdsp.h"
#include "internal.h"
#include "aac_ac3_parser.h"
#include "ac3_parser.h"
LEVEL_MINUS_9DB
};
+/** Adjustments in dB gain (LFE, +10 to -21 dB) */
+static const float gain_levels_lfe[32] = {
+ 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893,
+ 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946,
+ 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227,
+ 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253,
+ 0.125892, 0.112201, 0.100000, 0.089125
+};
+
/**
* Table for default stereo downmixing coefficients
* reference: Section 7.8.2 Downmixing Into Two Channels
ff_mdct_init(&s->imdct_256, 8, 1, 1.0);
ff_mdct_init(&s->imdct_512, 9, 1, 1.0);
ff_kbd_window_init(s->window, 5.0, 256);
- ff_dsputil_init(&s->dsp, avctx);
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
- ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ ff_bswapdsp_init(&s->bdsp);
+ avpriv_float_dsp_init(&s->fdsp, avctx->flags & AV_CODEC_FLAG_BITEXACT);
+ ff_ac3dsp_init(&s->ac3dsp, avctx->flags & AV_CODEC_FLAG_BITEXACT);
ff_fmt_convert_init(&s->fmt_conv, avctx);
av_lfg_init(&s->dith_state, 0);
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
/* allow downmixing to stereo or mono */
- if (avctx->channels > 0 && avctx->request_channels > 0 &&
- avctx->request_channels < avctx->channels &&
- avctx->request_channels <= 2) {
- avctx->channels = avctx->request_channels;
- }
+ if (avctx->channels > 1 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_MONO)
+ avctx->channels = 1;
+ else if (avctx->channels > 2 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_STEREO)
+ avctx->channels = 2;
s->downmixed = 1;
for (i = 0; i < AC3_MAX_CHANNELS; i++) {
skip_bits(gbc, 2); //skip copyright bit and original bitstream bit
- /* skip the timecodes (or extra bitstream information for Alternate Syntax)
- TODO: read & use the xbsi1 downmix levels */
- if (get_bits1(gbc))
- skip_bits(gbc, 14); //skip timecode1 / xbsi1
- if (get_bits1(gbc))
- skip_bits(gbc, 14); //skip timecode2 / xbsi2
+ /* skip the timecodes or parse the Alternate Bit Stream Syntax */
+ if (s->bitstream_id != 6) {
+ if (get_bits1(gbc))
+ skip_bits(gbc, 14); //skip timecode1
+ if (get_bits1(gbc))
+ skip_bits(gbc, 14); //skip timecode2
+ } else {
+ if (get_bits1(gbc)) {
+ s->preferred_downmix = get_bits(gbc, 2);
+ s->center_mix_level_ltrt = get_bits(gbc, 3);
+ s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
+ s->center_mix_level = get_bits(gbc, 3);
+ s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7);
+ }
+ if (get_bits1(gbc)) {
+ s->dolby_surround_ex_mode = get_bits(gbc, 2);
+ s->dolby_headphone_mode = get_bits(gbc, 2);
+ skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1)
+ }
+ }
/* skip additional bitstream info */
if (get_bits1(gbc)) {
/* get decoding parameters from header info */
s->bit_alloc_params.sr_code = hdr.sr_code;
+ s->bitstream_id = hdr.bitstream_id;
s->bitstream_mode = hdr.bitstream_mode;
s->channel_mode = hdr.channel_mode;
- s->channel_layout = hdr.channel_layout;
s->lfe_on = hdr.lfe_on;
s->bit_alloc_params.sr_shift = hdr.sr_shift;
s->sample_rate = hdr.sample_rate;
s->fbw_channels = s->channels - s->lfe_on;
s->lfe_ch = s->fbw_channels + 1;
s->frame_size = hdr.frame_size;
+ s->preferred_downmix = AC3_DMIXMOD_NOTINDICATED;
s->center_mix_level = hdr.center_mix_level;
+ s->center_mix_level_ltrt = 4; // -3.0dB
s->surround_mix_level = hdr.surround_mix_level;
+ s->surround_mix_level_ltrt = 4; // -3.0dB
+ s->lfe_mix_level_exists = 0;
s->num_blocks = hdr.num_blocks;
s->frame_type = hdr.frame_type;
s->substreamid = hdr.substreamid;
+ s->dolby_surround_mode = hdr.dolby_surround_mode;
+ s->dolby_surround_ex_mode = AC3_DSUREXMOD_NOTINDICATED;
+ s->dolby_headphone_mode = AC3_DHEADPHONMOD_NOTINDICATED;
if (s->lfe_on) {
s->start_freq[s->lfe_ch] = 0;
s->channel_in_cpl[s->lfe_ch] = 0;
}
- if (hdr.bitstream_id <= 10) {
+ if (s->bitstream_id <= 10) {
s->eac3 = 0;
s->snr_offset_strategy = 2;
s->block_switch_syntax = 1;
/**
* Grouped mantissas for 3-level 5-level and 11-level quantization
*/
-typedef struct {
+typedef struct mant_groups {
int b1_mant[2];
int b2_mant[2];
int b4_mant;
i = !s->channel_mode;
do {
if (get_bits1(gbc)) {
- s->dynamic_range[i] = ((dynamic_range_tab[get_bits(gbc, 8)] - 1.0) *
- s->drc_scale) + 1.0;
+ /* Allow asymmetric application of DRC when drc_scale > 1.
+ Amplification of quiet sounds is enhanced */
+ float range = dynamic_range_tab[get_bits(gbc, 8)];
+ if (range > 1.0 || s->drc_scale <= 1.0)
+ s->dynamic_range[i] = powf(range, s->drc_scale);
+ else
+ s->dynamic_range[i] = range;
} else if (blk == 0) {
s->dynamic_range[i] = 1.0f;
}
int blk, ch, err, ret;
const uint8_t *channel_map;
const float *output[AC3_MAX_CHANNELS];
+ enum AVMatrixEncoding matrix_encoding;
+ AVDownmixInfo *downmix_info;
/* copy input buffer to decoder context to avoid reading past the end
of the buffer, which can be caused by a damaged input stream. */
if (buf_size >= 2 && AV_RB16(buf) == 0x770B) {
// seems to be byte-swapped AC-3
int cnt = FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE) >> 1;
- s->dsp.bswap16_buf((uint16_t *)s->input_buffer, (const uint16_t *)buf, cnt);
+ s->bdsp.bswap16_buf((uint16_t *) s->input_buffer,
+ (const uint16_t *) buf, cnt);
} else
memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
buf = s->input_buffer;
s->output_mode = s->channel_mode;
if (s->lfe_on)
s->output_mode |= AC3_OUTPUT_LFEON;
- if (avctx->request_channels > 0 && avctx->request_channels <= 2 &&
- avctx->request_channels < s->channels) {
- s->out_channels = avctx->request_channels;
- s->output_mode = avctx->request_channels == 1 ? AC3_CHMODE_MONO : AC3_CHMODE_STEREO;
- s->channel_layout = avpriv_ac3_channel_layout_tab[s->output_mode];
+ if (s->channels > 1 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_MONO) {
+ s->out_channels = 1;
+ s->output_mode = AC3_CHMODE_MONO;
+ } else if (s->channels > 2 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
+ s->out_channels = 2;
+ s->output_mode = AC3_CHMODE_STEREO;
}
- avctx->channels = s->out_channels;
- avctx->channel_layout = s->channel_layout;
/* set downmixing coefficients if needed */
if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) &&
return AVERROR_INVALIDDATA;
}
avctx->channels = s->out_channels;
+ avctx->channel_layout = avpriv_ac3_channel_layout_tab[s->output_mode & ~AC3_OUTPUT_LFEON];
+ if (s->output_mode & AC3_OUTPUT_LFEON)
+ avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
/* set audio service type based on bitstream mode for AC-3 */
avctx->audio_service_type = s->bitstream_mode;
for (ch = 0; ch < s->out_channels; ch++)
memcpy(s->output[ch], output[ch], sizeof(**output) * AC3_BLOCK_SIZE);
+ /*
+ * AVMatrixEncoding
+ *
+ * Check whether the input layout is compatible, and make sure we're not
+ * downmixing (else the matrix encoding is no longer applicable).
+ */
+ matrix_encoding = AV_MATRIX_ENCODING_NONE;
+ if (s->channel_mode == AC3_CHMODE_STEREO &&
+ s->channel_mode == (s->output_mode & ~AC3_OUTPUT_LFEON)) {
+ if (s->dolby_surround_mode == AC3_DSURMOD_ON)
+ matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
+ else if (s->dolby_headphone_mode == AC3_DHEADPHONMOD_ON)
+ matrix_encoding = AV_MATRIX_ENCODING_DOLBYHEADPHONE;
+ } else if (s->channel_mode >= AC3_CHMODE_2F2R &&
+ s->channel_mode == (s->output_mode & ~AC3_OUTPUT_LFEON)) {
+ switch (s->dolby_surround_ex_mode) {
+ case AC3_DSUREXMOD_ON: // EX or PLIIx
+ matrix_encoding = AV_MATRIX_ENCODING_DOLBYEX;
+ break;
+ case AC3_DSUREXMOD_PLIIZ:
+ matrix_encoding = AV_MATRIX_ENCODING_DPLIIZ;
+ break;
+ default: // not indicated or off
+ break;
+ }
+ }
+ if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0)
+ return ret;
+
+ /* AVDownmixInfo */
+ if ((downmix_info = av_downmix_info_update_side_data(frame))) {
+ switch (s->preferred_downmix) {
+ case AC3_DMIXMOD_LTRT:
+ downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LTRT;
+ break;
+ case AC3_DMIXMOD_LORO:
+ downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LORO;
+ break;
+ case AC3_DMIXMOD_DPLII:
+ downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_DPLII;
+ break;
+ default:
+ downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_UNKNOWN;
+ break;
+ }
+ downmix_info->center_mix_level = gain_levels[s-> center_mix_level];
+ downmix_info->center_mix_level_ltrt = gain_levels[s-> center_mix_level_ltrt];
+ downmix_info->surround_mix_level = gain_levels[s-> surround_mix_level];
+ downmix_info->surround_mix_level_ltrt = gain_levels[s->surround_mix_level_ltrt];
+ if (s->lfe_mix_level_exists)
+ downmix_info->lfe_mix_level = gain_levels_lfe[s->lfe_mix_level];
+ else
+ downmix_info->lfe_mix_level = 0.0; // -inf dB
+ } else
+ return AVERROR(ENOMEM);
+
*got_frame_ptr = 1;
return FFMIN(buf_size, s->frame_size);
#define OFFSET(x) offsetof(AC3DecodeContext, x)
#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM)
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, 1.0, PAR },
+ { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
{ NULL},
};
.init = ac3_decode_init,
.close = ac3_decode_end,
.decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .capabilities = AV_CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
.priv_class = &ac3_decoder_class,
.init = ac3_decode_init,
.close = ac3_decode_end,
.decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .capabilities = AV_CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
.priv_class = &eac3_decoder_class,