X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdca.c;h=4c72ab36b6ad114e1dad62b403dac2804b8b8d66;hb=5a9fa84585e93a70bf586cf959065f61fa949949;hp=87112ed4ec5802aba2d0014ef319462ede781744;hpb=8a85660d3b9b610549b65cba09b4b7a1acb880bd;p=ffmpeg diff --git a/libavcodec/dca.c b/libavcodec/dca.c index 87112ed4ec5..4c72ab36b6a 100644 --- a/libavcodec/dca.c +++ b/libavcodec/dca.c @@ -136,8 +136,8 @@ static const uint32_t map_xxch_to_native[28] = { AV_CH_BACK_CENTER, AV_CH_BACK_LEFT, AV_CH_BACK_RIGHT, - AV_CH_BACK_LEFT, /* side surround left -- dup sur rear L */ - AV_CH_BACK_RIGHT, /* side surround right -- dup sur rear R */ + AV_CH_SIDE_LEFT, /* side surround left -- dup sur side L */ + AV_CH_SIDE_RIGHT, /* side surround right -- dup sur side R */ AV_CH_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER, AV_CH_TOP_FRONT_LEFT, @@ -441,11 +441,10 @@ typedef struct { /* XXCH extension information */ int xxch_chset; int xxch_nbits_spk_mask; - int xxch_num_chsets; /* number of channel sets */ uint32_t xxch_core_spkmask; - int xxch_num_chans[4]; /* num in channel set */ uint32_t xxch_spk_masks[4]; /* speaker masks, last element is core mask */ int xxch_chset_nch[4]; + float xxch_dmix_sf[DCA_CHSETS_MAX]; uint32_t xxch_downmix; /* downmix enabled per channel set */ uint32_t xxch_dmix_embedded; /* lower layer has mix pre-embedded, per chset */ @@ -540,6 +539,18 @@ static inline void get_array(GetBitContext *gb, int *dst, int len, int bits) *dst++ = get_bits(gb, bits); } +static inline int dca_xxch2index(DCAContext *s, int xxch_ch) +{ + int i, base, mask; + + /* locate channel set containing the channel */ + for (i = -1, base = 0, mask = (s->xxch_core_spkmask & ~DCA_XXCH_LFE1); + i <= s->xxch_chset && !(mask & xxch_ch); mask = s->xxch_spk_masks[++i]) + base += av_popcount(mask); + + return base + av_popcount(mask & (xxch_ch - 1)); +} + static int dca_parse_audio_coding_header(DCAContext *s, int base_channel, int xxch) { @@ -579,7 +590,9 @@ static int dca_parse_audio_coding_header(DCAContext *s, int base_channel, if (get_bits1(&s->gb)) { embedded_downmix = get_bits1(&s->gb); scale_factor = - 1.0f / dca_downmix_scale_factors[get_bits(&s->gb, 6) << 2]; + 1.0f / dca_downmix_scale_factors[(get_bits(&s->gb, 6) - 1) << 2]; + + s->xxch_dmix_sf[s->xxch_chset] = scale_factor; for (i = base_channel; i < s->prim_channels; i++) { s->xxch_downmix |= (1 << i); @@ -588,16 +601,20 @@ static int dca_parse_audio_coding_header(DCAContext *s, int base_channel, for (j = base_channel; j < s->prim_channels; j++) { memset(s->xxch_dmix_coeff[j], 0, sizeof(s->xxch_dmix_coeff[0])); - if (mask[j]) - s->xxch_dmix_embedded |= (embedded_downmix << j); + s->xxch_dmix_embedded |= (embedded_downmix << j); for (i = 0; i < s->xxch_nbits_spk_mask; i++) { if (mask[j] & (1 << i)) { + if ((1 << i) == DCA_XXCH_LFE1) { + av_log(s->avctx, AV_LOG_WARNING, + "DCA-XXCH: dmix to LFE1 not supported.\n"); + continue; + } + coeff = get_bits(&s->gb, 7); sign = (coeff & 64) ? 1.0 : -1.0; - mag = dca_downmix_scale_factors[(coeff & 63) << 2]; - ichan = av_popcount((acc_mask & ~DCA_XXCH_LFE1) - & ((1 << i) - 1)); - s->xxch_dmix_coeff[j][ichan] = sign * mag * scale_factor; + mag = dca_downmix_scale_factors[((coeff & 63) - 1) << 2]; + ichan = dca_xxch2index(s, 1 << i); + s->xxch_dmix_coeff[j][ichan] = sign * mag; } } } @@ -2064,6 +2081,8 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, int lavc; int posn; int j, k; + int ch; + int endch; s->xch_present = 0; @@ -2341,22 +2360,50 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, } /* If stream contains XXCH, we might need to undo an embedded downmix */ - if (s->xxch_downmix & s->xxch_dmix_embedded) { - mask = s->xxch_downmix & s->xxch_dmix_embedded; - for (j = 0; j < channels; j++) { - if (mask & (1 << j)) { /* this channel has been mixed-out */ - src_chan = s->samples + s->channel_order_tab[j] * 256; - for (k = 0; k < channels - !!s->lfe; k++) { - achan = s->channel_order_tab[k]; - scale = s->xxch_dmix_coeff[j][k]; - if (scale != 0.0) { - dst_chan = s->samples + achan * 256; - s->fdsp.vector_fmac_scalar(dst_chan, src_chan, - -scale, 256); + if (s->xxch_dmix_embedded) { + /* Loop over channel sets in turn */ + ch = num_core_channels; + for (chset = 0; chset < s->xxch_chset; chset++) { + endch = ch + s->xxch_chset_nch[chset]; + mask = s->xxch_dmix_embedded; + + /* undo downmix */ + for (j = ch; j < endch; j++) { + if (mask & (1 << j)) { /* this channel has been mixed-out */ + src_chan = s->samples + s->channel_order_tab[j] * 256; + for (k = 0; k < endch; k++) { + achan = s->channel_order_tab[k]; + scale = s->xxch_dmix_coeff[j][k]; + if (scale != 0.0) { + dst_chan = s->samples + achan * 256; + s->fdsp.vector_fmac_scalar(dst_chan, src_chan, + -scale, 256); + } } } } + + /* if a downmix has been embedded then undo the pre-scaling */ + if ((mask & (1 << ch)) && s->xxch_dmix_sf[chset] != 1.0f) { + scale = s->xxch_dmix_sf[chset]; + + for (j = 0; j < ch; j++) { + src_chan = s->samples + s->channel_order_tab[j] * 256; + for (k = 0; k < 256; k++) + src_chan[k] *= scale; + } + + /* LFE channel is always part of core, scale if it exists */ + if (s->lfe) { + src_chan = s->samples + s->lfe_index * 256; + for (k = 0; k < 256; k++) + src_chan[k] *= scale; + } + } + + ch = endch; } + } if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) {