diff options
author | Nick Brereton <nick@nbrereton.net> | 2012-06-20 20:52:46 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-06-28 22:26:15 +0200 |
commit | cd8bef969ab30b6008387cbffa242bf38a449d9d (patch) | |
tree | 53eb810b7c5468adcc5de5c4df027927337f31cb /libavcodec/dca.c | |
parent | 16f6c16ac04bb61f468719d6469064a32d65424c (diff) | |
download | ffmpeg-cd8bef969ab30b6008387cbffa242bf38a449d9d.tar.gz |
Generate channel layout, reordering for DTS-XXCH extension and, undo embedded downmixes
Reviewed-by: Benjamin Larsson <benjamin@southpole.se>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavcodec/dca.c')
-rw-r--r-- | libavcodec/dca.c | 332 |
1 files changed, 275 insertions, 57 deletions
diff --git a/libavcodec/dca.c b/libavcodec/dca.c index 3cd161cbe6..6d025244c5 100644 --- a/libavcodec/dca.c +++ b/libavcodec/dca.c @@ -95,6 +95,68 @@ enum DCAExSSSpeakerMask { DCA_EXSS_REAR_HIGH_LEFT_RIGHT = 0x8000, }; +enum DCAXxchSpeakerMask { + DCA_XXCH_FRONT_CENTER = 0x0000001, + DCA_XXCH_FRONT_LEFT = 0x0000002, + DCA_XXCH_FRONT_RIGHT = 0x0000004, + DCA_XXCH_SIDE_REAR_LEFT = 0x0000008, + DCA_XXCH_SIDE_REAR_RIGHT = 0x0000010, + DCA_XXCH_LFE1 = 0x0000020, + DCA_XXCH_REAR_CENTER = 0x0000040, + DCA_XXCH_SURROUND_REAR_LEFT = 0x0000080, + DCA_XXCH_SURROUND_REAR_RIGHT = 0x0000100, + DCA_XXCH_SIDE_SURROUND_LEFT = 0x0000200, + DCA_XXCH_SIDE_SURROUND_RIGHT = 0x0000400, + DCA_XXCH_FRONT_CENTER_LEFT = 0x0000800, + DCA_XXCH_FRONT_CENTER_RIGHT = 0x0001000, + DCA_XXCH_FRONT_HIGH_LEFT = 0x0002000, + DCA_XXCH_FRONT_HIGH_CENTER = 0x0004000, + DCA_XXCH_FRONT_HIGH_RIGHT = 0x0008000, + DCA_XXCH_LFE2 = 0x0010000, + DCA_XXCH_SIDE_FRONT_LEFT = 0x0020000, + DCA_XXCH_SIDE_FRONT_RIGHT = 0x0040000, + DCA_XXCH_OVERHEAD = 0x0080000, + DCA_XXCH_SIDE_HIGH_LEFT = 0x0100000, + DCA_XXCH_SIDE_HIGH_RIGHT = 0x0200000, + DCA_XXCH_REAR_HIGH_CENTER = 0x0400000, + DCA_XXCH_REAR_HIGH_LEFT = 0x0800000, + DCA_XXCH_REAR_HIGH_RIGHT = 0x1000000, + DCA_XXCH_REAR_LOW_CENTER = 0x2000000, + DCA_XXCH_REAR_LOW_LEFT = 0x4000000, + DCA_XXCH_REAR_LOW_RIGHT = 0x8000000, +}; + +static const uint32_t map_xxch_to_libav[28] = { + AV_CH_FRONT_CENTER, + AV_CH_FRONT_LEFT, + AV_CH_FRONT_RIGHT, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + AV_CH_LOW_FREQUENCY, + 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_FRONT_LEFT_OF_CENTER, + AV_CH_FRONT_RIGHT_OF_CENTER, + AV_CH_TOP_FRONT_LEFT, + AV_CH_TOP_FRONT_CENTER, + AV_CH_TOP_FRONT_RIGHT, + AV_CH_LOW_FREQUENCY, /* lfe2 -- duplicate lfe1 position */ + AV_CH_FRONT_LEFT_OF_CENTER, /* side front left -- dup front cntr L */ + AV_CH_FRONT_RIGHT_OF_CENTER,/* side front right -- dup front cntr R */ + AV_CH_TOP_CENTER, /* overhead */ + AV_CH_TOP_FRONT_LEFT, /* side high left -- dup */ + AV_CH_TOP_FRONT_RIGHT, /* side high right -- dup */ + AV_CH_TOP_BACK_CENTER, + AV_CH_TOP_BACK_LEFT, + AV_CH_TOP_BACK_RIGHT, + AV_CH_BACK_CENTER, /* rear low center -- dup */ + AV_CH_BACK_LEFT, /* rear low left -- dup */ + AV_CH_BACK_RIGHT /* read low right -- dup */ +}; + enum DCAExtensionMask { DCA_EXT_CORE = 0x001, ///< core in core substream DCA_EXT_XXCH = 0x002, ///< XXCh channels extension in core substream @@ -377,8 +439,20 @@ typedef struct { int xch_base_channel; ///< index of first (only) channel containing XCH data /* XXCH extension information */ - int xxch_spk_layout; + 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]; + + uint32_t xxch_downmix; /* downmix enabled per channel set */ + uint32_t xxch_dmix_embedded; /* lower layer has mix pre-embedded, per chset */ + float xxch_dmix_coeff[DCA_PRIM_CHANNELS_MAX][32]; /* worst case sizing */ + + int8_t xxch_order_tab[32]; + int8_t lfe_index; /* ExSS header parser */ int static_fields; ///< static fields present @@ -474,7 +548,11 @@ static int dca_parse_audio_coding_header(DCAContext *s, int base_channel, static const int bitlen[11] = { 0, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3 }; static const int thr[11] = { 0, 1, 3, 3, 3, 3, 7, 7, 7, 7, 7 }; int hdr_pos = 0, hdr_size = 0; - int mask[8]; + float sign, mag, scale_factor; + int this_chans, acc_mask; + int embedded_downmix; + int nchans, mask[8]; + int coeff, ichan; /* xxch has arbitrary sized audio coding headers */ if (xxch) { @@ -482,22 +560,44 @@ static int dca_parse_audio_coding_header(DCAContext *s, int base_channel, hdr_size = get_bits(&s->gb, 7) + 1; } - s->total_channels = get_bits(&s->gb, 3) + 1 + base_channel; + nchans = get_bits(&s->gb, 3) + 1; + s->total_channels = nchans + base_channel; s->prim_channels = s->total_channels; - /* obtain speaker layout mask & mixdown coefficients if applicable */ + /* obtain speaker layout mask & downmix coefficients for XXCH */ if (xxch) { - s->xxch_spk_layout |= get_bits(&s->gb, s->xxch_nbits_spk_mask - 6); + acc_mask = s->xxch_core_spkmask; + + this_chans = get_bits(&s->gb, s->xxch_nbits_spk_mask - 6) << 6; + s->xxch_spk_masks[s->xxch_chset] = this_chans; + s->xxch_chset_nch[s->xxch_chset] = nchans; + + for (i = 0; i <= s->xxch_chset; i++) + acc_mask |= s->xxch_spk_masks[i]; + + /* check for downmixing information */ if (get_bits1(&s->gb)) { - get_bits1(&s->gb); - skip_bits(&s->gb, 6); + embedded_downmix = get_bits1(&s->gb); + scale_factor = + 1.0f / dca_downmix_scale_factors[get_bits(&s->gb, 6) << 2]; + for (i = base_channel; i < s->prim_channels; i++) { + s->xxch_downmix |= (1 << i); mask[i] = get_bits(&s->gb, s->xxch_nbits_spk_mask); } + 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); for (i = 0; i < s->xxch_nbits_spk_mask; i++) { if (mask[j] & (1 << i)) { - int coeff = get_bits(&s->gb, 7); + 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; } } } @@ -609,7 +709,7 @@ static int dca_parse_frame_header(DCAContext *s) if (!s->bit_rate) return AVERROR_INVALIDDATA; - s->downmix = get_bits(&s->gb, 1); + s->downmix = get_bits(&s->gb, 1); /* note: this is FixedBit == 0 */ s->dynrange = get_bits(&s->gb, 1); s->timestamp = get_bits(&s->gb, 1); s->aux_data = get_bits(&s->gb, 1); @@ -1337,7 +1437,7 @@ static int dca_filter_channels(DCAContext *s, int block_index) if (s->output & DCA_LFE) { lfe_interpolation_fir(s, s->lfe, 2 * s->lfe, s->lfe_data + 2 * s->lfe * (block_index + 4), - &s->samples[256 * dca_lfe_index[s->amode]], + &s->samples[256 * s->lfe_index], (1.0 / 256.0) * s->scale_bias); /* Outputs 20bits pcm samples */ } @@ -1782,10 +1882,11 @@ static int dca_xxch_decode_frame(DCAContext *s) for (i = 0; i < num_chsets; i++) fsize[i] = get_bits(&s->gb, 14) + 1; - core_spk = get_bits(&s->gb, spkmsk_bits); - - s->xxch_spk_layout = core_spk; + core_spk = get_bits(&s->gb, spkmsk_bits); + s->xxch_core_spkmask = core_spk; s->xxch_nbits_spk_mask = spkmsk_bits; + s->xxch_downmix = 0; + s->xxch_dmix_embedded = 0; /* skip to the end of the header */ i = get_bits_count(&s->gb); @@ -1793,8 +1894,9 @@ static int dca_xxch_decode_frame(DCAContext *s) skip_bits_long(&s->gb, hdr_pos + hdr_size * 8 - i); for (chset = 0; chset < num_chsets; chset++) { - chstart = get_bits_count(&s->gb); - base_channel = s->prim_channels; + chstart = get_bits_count(&s->gb); + base_channel = s->prim_channels; + s->xxch_chset = chset; /* XXCH and Core headers differ, see 6.4.2 "XXCH Channel Set Header" vs. 5.3.2 "Primary Audio Coding Header", DTS Spec 1.3.1 */ @@ -1814,6 +1916,7 @@ static int dca_xxch_decode_frame(DCAContext *s) if (chstart + fsize[chset] * 8 > i) skip_bits_long(&s->gb, chstart + fsize[chset] * 8 - i); } + s->xxch_chset = num_chsets; return 0; } @@ -1823,6 +1926,7 @@ static int dca_xxch_decode_frame(DCAContext *s) */ static void dca_exss_parse_header(DCAContext *s) { + int asset_size[8]; int ss_index; int blownup; int num_audiop = 1; @@ -1894,7 +1998,7 @@ static void dca_exss_parse_header(DCAContext *s) } for (i = 0; i < num_assets; i++) - skip_bits_long(&s->gb, 16 + 4 * blownup); // asset size + asset_size[i] = get_bits_long(&s->gb, 16 + 4 * blownup); for (i = 0; i < num_assets; i++) { if (dca_exss_parse_asset_header(s)) @@ -1904,18 +2008,31 @@ static void dca_exss_parse_header(DCAContext *s) /* not parsed further, we were only interested in the extensions mask * from the asset header */ - if(num_assets > 0) { + if (num_assets > 0) { j = get_bits_count(&s->gb); - if(start_posn + hdrsize * 8 > j) + if (start_posn + hdrsize * 8 > j) skip_bits_long(&s->gb, start_posn + hdrsize * 8 - j); - /* check first asset for XBR -- should also check extension mask! */ - mkr = get_bits_long(&s->gb, 32); + for (i = 0; i < num_assets; i++) { + start_posn = get_bits_count(&s->gb); + mkr = get_bits_long(&s->gb, 32); - if(mkr == 0x655e315e) - dca_xbr_parse_frame(s); - else - av_log(s->avctx, AV_LOG_DEBUG, "DTS-MA: unknown marker = 0x%08x\n", mkr); + /* parse extensions that we know about */ + if (mkr == 0x655e315e) { + dca_xbr_parse_frame(s); + } else if (mkr == 0x47004a03) { + dca_xxch_decode_frame(s); + s->core_ext_mask |= DCA_EXT_XXCH; /* xxx use for chan reordering */ + } else { + av_log(s->avctx, AV_LOG_DEBUG, + "DTS-ExSS: unknown marker = 0x%08x\n", mkr); + } + + /* skip to end of block */ + j = get_bits_count(&s->gb); + if (start_posn + asset_size[i] * 8 > j) + skip_bits_long(&s->gb, start_posn + asset_size[i] * 8 - j); + } } } @@ -1928,16 +2045,25 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, { const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - + int channel_mask; + int channel_layout; int lfe_samples; int num_core_channels = 0; int i, ret; - float *samples_flt; + float *samples_flt; + float *src_chan; + float *dst_chan; int16_t *samples_s16; DCAContext *s = avctx->priv_data; - int channels; int core_ss_end; - + int channels; + float scale; + int achan; + int chset; + int mask; + int lavc; + int posn; + int j, k; s->xch_present = 0; @@ -2072,44 +2198,117 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, channels = s->prim_channels + !!s->lfe; - if (s->amode < 16) { - avctx->channel_layout = dca_core_channel_layout[s->amode]; - - if (s->xch_present && (!avctx->request_channels || - avctx->request_channels > num_core_channels + !!s->lfe)) { - avctx->channel_layout |= AV_CH_BACK_CENTER; - if (s->lfe) { - avctx->channel_layout |= AV_CH_LOW_FREQUENCY; - s->channel_order_tab = dca_channel_reorder_lfe_xch[s->amode]; + /* If we have XXCH then the channel layout is managed differently */ + /* note that XLL will also have another way to do things */ + if (!(s->core_ext_mask & DCA_EXT_XXCH) + || (s->core_ext_mask & DCA_EXT_XXCH && avctx->request_channels > 0 + && avctx->request_channels + < num_core_channels + !!s->lfe + s->xxch_chset_nch[0])) + { /* xxx should also do MA extensions */ + if (s->amode < 16) { + avctx->channel_layout = dca_core_channel_layout[s->amode]; + + if (s->xch_present && (!avctx->request_channels || + avctx->request_channels + > num_core_channels + !!s->lfe)) { + avctx->channel_layout |= AV_CH_BACK_CENTER; + if (s->lfe) { + avctx->channel_layout |= AV_CH_LOW_FREQUENCY; + s->channel_order_tab = dca_channel_reorder_lfe_xch[s->amode]; + } else { + s->channel_order_tab = dca_channel_reorder_nolfe_xch[s->amode]; + } } else { - s->channel_order_tab = dca_channel_reorder_nolfe_xch[s->amode]; + channels = num_core_channels + !!s->lfe; + s->xch_present = 0; /* disable further xch processing */ + if (s->lfe) { + avctx->channel_layout |= AV_CH_LOW_FREQUENCY; + s->channel_order_tab = dca_channel_reorder_lfe[s->amode]; + } else + s->channel_order_tab = dca_channel_reorder_nolfe[s->amode]; + } + + if (channels > !!s->lfe && + s->channel_order_tab[channels - 1 - !!s->lfe] < 0) + return AVERROR_INVALIDDATA; + + if (avctx->request_channels == 2 && s->prim_channels > 2) { + channels = 2; + s->output = DCA_STEREO; + avctx->channel_layout = AV_CH_LAYOUT_STEREO; } + else if (avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE) { + static const int8_t dca_channel_order_native[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + s->channel_order_tab = dca_channel_order_native; + } + s->lfe_index = dca_lfe_index[s->amode]; } else { + av_log(avctx, AV_LOG_ERROR, + "Non standard configuration %d !\n", s->amode); + return AVERROR_INVALIDDATA; + } + + s->xxch_downmix = 0; + } else { + /* we only get here if an XXCH channel set can be added to the mix */ + channel_mask = s->xxch_core_spkmask; + + if (avctx->request_channels > 0 + && avctx->request_channels < s->prim_channels) { channels = num_core_channels + !!s->lfe; - s->xch_present = 0; /* disable further xch processing */ - if (s->lfe) { - avctx->channel_layout |= AV_CH_LOW_FREQUENCY; - s->channel_order_tab = dca_channel_reorder_lfe[s->amode]; - } else - s->channel_order_tab = dca_channel_reorder_nolfe[s->amode]; + for (i = 0; i < s->xxch_chset && channels + s->xxch_chset_nch[i] + <= avctx->request_channels; i++) { + channels += s->xxch_chset_nch[i]; + channel_mask |= s->xxch_spk_masks[i]; + } + } else { + channels = s->prim_channels + !!s->lfe; + for (i = 0; i < s->xxch_chset; i++) { + channel_mask |= s->xxch_spk_masks[i]; + } } - if (channels > !!s->lfe && - s->channel_order_tab[channels - 1 - !!s->lfe] < 0) - return AVERROR_INVALIDDATA; + /* Given the DTS spec'ed channel mask, generate an avcodec version */ + channel_layout = 0; + for (i = 0; i < s->xxch_nbits_spk_mask; ++i) { + if (channel_mask & (1 << i)) { + channel_layout |= map_xxch_to_libav[i]; + } + } - if (avctx->request_channels == 2 && s->prim_channels > 2) { - channels = 2; - s->output = DCA_STEREO; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; + /* make sure that we have managed to get equivelant dts/avcodec channel + * masks in some sense -- unfortunately some channels could overlap */ + if (av_popcount(channel_mask) != av_popcount(channel_layout)) { + av_log(avctx, AV_LOG_DEBUG, + "DTS-XXCH: Inconsistant avcodec/dts channel layouts\n"); + return AVERROR_INVALIDDATA; } - else if (avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE) { - static const int8_t dca_channel_order_native[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; - s->channel_order_tab = dca_channel_order_native; + + avctx->channel_layout = channel_layout; + + if (!(avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE)) { + /* Estimate DTS --> avcodec ordering table */ + for (chset = -1, j = 0; chset < s->xxch_chset; ++chset) { + mask = chset >= 0 ? s->xxch_spk_masks[chset] + : s->xxch_core_spkmask; + for (i = 0; i < s->xxch_nbits_spk_mask; i++) { + if (mask & ~(DCA_XXCH_LFE1 | DCA_XXCH_LFE2) & (1 << i)) { + lavc = map_xxch_to_libav[i]; + posn = av_popcount(channel_layout & (lavc - 1)); + s->xxch_order_tab[j++] = posn; + } + } + } + + s->lfe_index = av_popcount(channel_layout & (AV_CH_LOW_FREQUENCY-1)); + } else { /* native ordering */ + for (i = 0; i < channels; i++) + s->xxch_order_tab[i] = i; + + s->lfe_index = channels - 1; } - } else { - av_log(avctx, AV_LOG_ERROR, "Non standard configuration %d !\n", s->amode); - return AVERROR_INVALIDDATA; + + s->channel_order_tab = s->xxch_order_tab; } if (avctx->channels != channels) { @@ -2141,6 +2340,25 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, s->fdsp.vector_fmac_scalar(rt_chan, back_chan, -M_SQRT1_2, 256); } + /* 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 (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) { s->fmt_conv.float_interleave(samples_flt, s->samples_chanptr, 256, channels); |