X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdca_exss.c;h=4579f2350fedb27bde061946edd908321f0c9352;hb=916da13d6dac8b0d3e8f7b1cb87fa37801cee3f8;hp=ed014906cec6d1ec2b7b125922d1db4c0997b487;hpb=4f32ccb61800ef1a0acf02010784da4f15adde44;p=ffmpeg diff --git a/libavcodec/dca_exss.c b/libavcodec/dca_exss.c index ed014906cec..4579f2350fe 100644 --- a/libavcodec/dca_exss.c +++ b/libavcodec/dca_exss.c @@ -1,5 +1,5 @@ /* - * DCA ExSS extension + * Copyright (C) 2016 foo86 * * This file is part of FFmpeg. * @@ -18,356 +18,497 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/common.h" -#include "libavutil/log.h" - -#include "dca.h" -#include "dca_syncwords.h" -#include "get_bits.h" - -/* extensions that reside in core substream */ -#define DCA_CORE_EXTS (DCA_EXT_XCH | DCA_EXT_XXCH | DCA_EXT_X96) - -/* these are unconfirmed but should be mostly correct */ -enum DCAExSSSpeakerMask { - DCA_EXSS_FRONT_CENTER = 0x0001, - DCA_EXSS_FRONT_LEFT_RIGHT = 0x0002, - DCA_EXSS_SIDE_REAR_LEFT_RIGHT = 0x0004, - DCA_EXSS_LFE = 0x0008, - DCA_EXSS_REAR_CENTER = 0x0010, - DCA_EXSS_FRONT_HIGH_LEFT_RIGHT = 0x0020, - DCA_EXSS_REAR_LEFT_RIGHT = 0x0040, - DCA_EXSS_FRONT_HIGH_CENTER = 0x0080, - DCA_EXSS_OVERHEAD = 0x0100, - DCA_EXSS_CENTER_LEFT_RIGHT = 0x0200, - DCA_EXSS_WIDE_LEFT_RIGHT = 0x0400, - DCA_EXSS_SIDE_LEFT_RIGHT = 0x0800, - DCA_EXSS_LFE2 = 0x1000, - DCA_EXSS_SIDE_HIGH_LEFT_RIGHT = 0x2000, - DCA_EXSS_REAR_HIGH_CENTER = 0x4000, - DCA_EXSS_REAR_HIGH_LEFT_RIGHT = 0x8000, -}; - -/** - * Return the number of channels in an ExSS speaker mask (HD) - */ -static int dca_exss_mask2count(int mask) +#include "dcadec.h" +#include "dcadata.h" + +static int count_chs_for_mask(int mask) { - /* count bits that mean speaker pairs twice */ - return av_popcount(mask) + - av_popcount(mask & (DCA_EXSS_CENTER_LEFT_RIGHT | - DCA_EXSS_FRONT_LEFT_RIGHT | - DCA_EXSS_FRONT_HIGH_LEFT_RIGHT | - DCA_EXSS_WIDE_LEFT_RIGHT | - DCA_EXSS_SIDE_LEFT_RIGHT | - DCA_EXSS_SIDE_HIGH_LEFT_RIGHT | - DCA_EXSS_SIDE_REAR_LEFT_RIGHT | - DCA_EXSS_REAR_LEFT_RIGHT | - DCA_EXSS_REAR_HIGH_LEFT_RIGHT)); + return av_popcount(mask) + av_popcount(mask & 0xae66); } -/** - * Skip mixing coefficients of a single mix out configuration (HD) - */ -static void dca_exss_skip_mix_coeffs(GetBitContext *gb, int channels, int out_ch) +static void parse_xll_parameters(DCAExssParser *s, DCAExssAsset *asset) { - int i; + // Size of XLL data in extension substream + asset->xll_size = get_bits(&s->gb, s->exss_size_nbits) + 1; + + // XLL sync word present flag + if (asset->xll_sync_present = get_bits1(&s->gb)) { + int xll_delay_nbits; + + // Peak bit rate smoothing buffer size + skip_bits(&s->gb, 4); + + // Number of bits for XLL decoding delay + xll_delay_nbits = get_bits(&s->gb, 5) + 1; - for (i = 0; i < channels; i++) { - int mix_map_mask = get_bits(gb, out_ch); - int num_coeffs = av_popcount(mix_map_mask); - skip_bits_long(gb, num_coeffs * 6); + // Initial XLL decoding delay in frames + asset->xll_delay_nframes = get_bits_long(&s->gb, xll_delay_nbits); + + // Number of bytes offset to XLL sync + asset->xll_sync_offset = get_bits(&s->gb, s->exss_size_nbits); + } else { + asset->xll_delay_nframes = 0; + asset->xll_sync_offset = 0; } } -/** - * Parse extension substream asset header (HD) - */ -static int dca_exss_parse_asset_header(DCAContext *s) +static void parse_lbr_parameters(DCAExssParser *s, DCAExssAsset *asset) { - int header_pos = get_bits_count(&s->gb); - int header_size; - int channels = 0; - int embedded_stereo = 0; - int embedded_6ch = 0; - int drc_code_present; - int extensions_mask = 0; - int i, j; - - if (get_bits_left(&s->gb) < 16) - return AVERROR_INVALIDDATA; + // Size of LBR component in extension substream + asset->lbr_size = get_bits(&s->gb, 14) + 1; + + // LBR sync word present flag + if (get_bits1(&s->gb)) + // LBR sync distance + skip_bits(&s->gb, 2); +} - /* We will parse just enough to get to the extensions bitmask with which - * we can set the profile value. */ +static int parse_descriptor(DCAExssParser *s, DCAExssAsset *asset) +{ + int i, j, drc_present, descr_size, descr_pos = get_bits_count(&s->gb); + + // Size of audio asset descriptor in bytes + descr_size = get_bits(&s->gb, 9) + 1; + + // Audio asset identifier + asset->asset_index = get_bits(&s->gb, 3); - header_size = get_bits(&s->gb, 9) + 1; - skip_bits(&s->gb, 3); // asset index + // + // Per stream static metadata + // - if (s->static_fields) { + if (s->static_fields_present) { + // Asset type descriptor presence if (get_bits1(&s->gb)) - skip_bits(&s->gb, 4); // asset type descriptor + // Asset type descriptor + skip_bits(&s->gb, 4); + + // Language descriptor presence if (get_bits1(&s->gb)) - skip_bits_long(&s->gb, 24); // language descriptor + // Language descriptor + skip_bits(&s->gb, 24); + // Additional textual information presence if (get_bits1(&s->gb)) { - /* How can one fit 1024 bytes of text here if the maximum value - * for the asset header size field above was 512 bytes? */ - int text_length = get_bits(&s->gb, 10) + 1; - if (get_bits_left(&s->gb) < text_length * 8) + // Byte size of additional text info + int text_size = get_bits(&s->gb, 10) + 1; + + // Sanity check available size + if (get_bits_left(&s->gb) < text_size * 8) return AVERROR_INVALIDDATA; - skip_bits_long(&s->gb, text_length * 8); // info text + + // Additional textual information string + skip_bits_long(&s->gb, text_size * 8); } - skip_bits(&s->gb, 5); // bit resolution - 1 - skip_bits(&s->gb, 4); // max sample rate code - channels = get_bits(&s->gb, 8) + 1; + // PCM bit resolution + asset->pcm_bit_res = get_bits(&s->gb, 5) + 1; - s->one2one_map_chtospkr = get_bits1(&s->gb); - if (s->one2one_map_chtospkr) { - int spkr_remap_sets; - int spkr_mask_size = 16; - int num_spkrs[7]; + // Maximum sample rate + asset->max_sample_rate = ff_dca_sampling_freqs[get_bits(&s->gb, 4)]; - if (channels > 2) - embedded_stereo = get_bits1(&s->gb); - if (channels > 6) - embedded_6ch = get_bits1(&s->gb); + // Total number of channels + asset->nchannels_total = get_bits(&s->gb, 8) + 1; - if (get_bits1(&s->gb)) { - spkr_mask_size = (get_bits(&s->gb, 2) + 1) << 2; - skip_bits(&s->gb, spkr_mask_size); // spkr activity mask - } + // One to one map channel to speakers + if (asset->one_to_one_map_ch_to_spkr = get_bits1(&s->gb)) { + int spkr_mask_nbits = 0; + int spkr_remap_nsets; + int nspeakers[8]; + + // Embedded stereo flag + if (asset->nchannels_total > 2) + asset->embedded_stereo = get_bits1(&s->gb); + + // Embedded 6 channels flag + if (asset->nchannels_total > 6) + asset->embedded_6ch = get_bits1(&s->gb); - spkr_remap_sets = get_bits(&s->gb, 3); + // Speaker mask enabled flag + if (asset->spkr_mask_enabled = get_bits1(&s->gb)) { + // Number of bits for speaker activity mask + spkr_mask_nbits = (get_bits(&s->gb, 2) + 1) << 2; - for (i = 0; i < spkr_remap_sets; i++) { - /* std layout mask for each remap set */ - num_spkrs[i] = dca_exss_mask2count(get_bits(&s->gb, spkr_mask_size)); + // Loudspeaker activity mask + asset->spkr_mask = get_bits(&s->gb, spkr_mask_nbits); + } + + // Number of speaker remapping sets + if ((spkr_remap_nsets = get_bits(&s->gb, 3)) && !spkr_mask_nbits) { + av_log(s->avctx, AV_LOG_ERROR, "Speaker mask disabled yet there are remapping sets\n"); + return AVERROR_INVALIDDATA; } - for (i = 0; i < spkr_remap_sets; i++) { - int num_dec_ch_remaps = get_bits(&s->gb, 5) + 1; - if (get_bits_left(&s->gb) < 0) - return AVERROR_INVALIDDATA; + // Standard loudspeaker layout mask + for (i = 0; i < spkr_remap_nsets; i++) + nspeakers[i] = count_chs_for_mask(get_bits(&s->gb, spkr_mask_nbits)); - for (j = 0; j < num_spkrs[i]; j++) { - int remap_dec_ch_mask = get_bits_long(&s->gb, num_dec_ch_remaps); - int num_dec_ch = av_popcount(remap_dec_ch_mask); - skip_bits_long(&s->gb, num_dec_ch * 5); // remap codes + for (i = 0; i < spkr_remap_nsets; i++) { + // Number of channels to be decoded for speaker remapping + int nch_for_remaps = get_bits(&s->gb, 5) + 1; + + for (j = 0; j < nspeakers[i]; j++) { + // Decoded channels to output speaker mapping mask + int remap_ch_mask = get_bits_long(&s->gb, nch_for_remaps); + + // Loudspeaker remapping codes + skip_bits_long(&s->gb, av_popcount(remap_ch_mask) * 5); } } } else { - skip_bits(&s->gb, 3); // representation type + asset->embedded_stereo = 0; + asset->embedded_6ch = 0; + asset->spkr_mask_enabled = 0; + asset->spkr_mask = 0; + + // Representation type + asset->representation_type = get_bits(&s->gb, 3); } } - drc_code_present = get_bits1(&s->gb); - if (drc_code_present) - get_bits(&s->gb, 8); // drc code + // + // DRC, DNC and mixing metadata + // + // Dynamic range coefficient presence flag + drc_present = get_bits1(&s->gb); + + // Code for dynamic range coefficient + if (drc_present) + skip_bits(&s->gb, 8); + + // Dialog normalization presence flag if (get_bits1(&s->gb)) - skip_bits(&s->gb, 5); // dialog normalization code + // Dialog normalization code + skip_bits(&s->gb, 5); + + // DRC for stereo downmix + if (drc_present && asset->embedded_stereo) + skip_bits(&s->gb, 8); - if (drc_code_present && embedded_stereo) - get_bits(&s->gb, 8); // drc stereo code + // Mixing metadata presence flag + if (s->mix_metadata_enabled && get_bits1(&s->gb)) { + int nchannels_dmix; - if (s->mix_metadata && get_bits1(&s->gb)) { - skip_bits(&s->gb, 1); // external mix - skip_bits(&s->gb, 6); // post mix gain code + // External mixing flag + skip_bits1(&s->gb); - if (get_bits(&s->gb, 2) != 3) // mixer drc code - skip_bits(&s->gb, 3); // drc limit + // Post mixing / replacement gain adjustment + skip_bits(&s->gb, 6); + + // DRC prior to mixing + if (get_bits(&s->gb, 2) == 3) + // Custom code for mixing DRC + skip_bits(&s->gb, 8); else - skip_bits(&s->gb, 8); // custom drc code + // Limit for mixing DRC + skip_bits(&s->gb, 3); - if (get_bits1(&s->gb)) // channel specific scaling - for (i = 0; i < s->num_mix_configs; i++) - skip_bits_long(&s->gb, s->mix_config_num_ch[i] * 6); // scale codes + // Scaling type for channels of main audio + // Scaling parameters of main audio + if (get_bits1(&s->gb)) + for (i = 0; i < s->nmixoutconfigs; i++) + skip_bits_long(&s->gb, 6 * s->nmixoutchs[i]); else - skip_bits_long(&s->gb, s->num_mix_configs * 6); // scale codes + skip_bits_long(&s->gb, 6 * s->nmixoutconfigs); + + nchannels_dmix = asset->nchannels_total; + if (asset->embedded_6ch) + nchannels_dmix += 6; + if (asset->embedded_stereo) + nchannels_dmix += 2; - for (i = 0; i < s->num_mix_configs; i++) { - if (get_bits_left(&s->gb) < 0) + for (i = 0; i < s->nmixoutconfigs; i++) { + if (!s->nmixoutchs[i]) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid speaker layout mask for mixing configuration\n"); return AVERROR_INVALIDDATA; - dca_exss_skip_mix_coeffs(&s->gb, channels, s->mix_config_num_ch[i]); - if (embedded_6ch) - dca_exss_skip_mix_coeffs(&s->gb, 6, s->mix_config_num_ch[i]); - if (embedded_stereo) - dca_exss_skip_mix_coeffs(&s->gb, 2, s->mix_config_num_ch[i]); + } + for (j = 0; j < nchannels_dmix; j++) { + // Mix output mask + int mix_map_mask = get_bits(&s->gb, s->nmixoutchs[i]); + + // Mixing coefficients + skip_bits_long(&s->gb, av_popcount(mix_map_mask) * 6); + } } } - switch (get_bits(&s->gb, 2)) { - case 0: - extensions_mask = get_bits(&s->gb, 12); + // + // Decoder navigation data + // + + // Coding mode for the asset + asset->coding_mode = get_bits(&s->gb, 2); + + // Coding components used in asset + switch (asset->coding_mode) { + case 0: // Coding mode that may contain multiple coding components + asset->extension_mask = get_bits(&s->gb, 12); + + if (asset->extension_mask & DCA_EXSS_CORE) { + // Size of core component in extension substream + asset->core_size = get_bits(&s->gb, 14) + 1; + // Core sync word present flag + if (get_bits1(&s->gb)) + // Core sync distance + skip_bits(&s->gb, 2); + } + + if (asset->extension_mask & DCA_EXSS_XBR) + // Size of XBR extension in extension substream + asset->xbr_size = get_bits(&s->gb, 14) + 1; + + if (asset->extension_mask & DCA_EXSS_XXCH) + // Size of XXCH extension in extension substream + asset->xxch_size = get_bits(&s->gb, 14) + 1; + + if (asset->extension_mask & DCA_EXSS_X96) + // Size of X96 extension in extension substream + asset->x96_size = get_bits(&s->gb, 12) + 1; + + if (asset->extension_mask & DCA_EXSS_LBR) + parse_lbr_parameters(s, asset); + + if (asset->extension_mask & DCA_EXSS_XLL) + parse_xll_parameters(s, asset); + + if (asset->extension_mask & DCA_EXSS_RSV1) + skip_bits(&s->gb, 16); + + if (asset->extension_mask & DCA_EXSS_RSV2) + skip_bits(&s->gb, 16); break; - case 1: - extensions_mask = DCA_EXT_EXSS_XLL; + + case 1: // Loss-less coding mode without CBR component + asset->extension_mask = DCA_EXSS_XLL; + parse_xll_parameters(s, asset); break; - case 2: - extensions_mask = DCA_EXT_EXSS_LBR; + + case 2: // Low bit rate mode + asset->extension_mask = DCA_EXSS_LBR; + parse_lbr_parameters(s, asset); break; - case 3: - extensions_mask = 0; /* aux coding */ + + case 3: // Auxiliary coding mode + asset->extension_mask = 0; + + // Size of auxiliary coded data + skip_bits(&s->gb, 14); + + // Auxiliary codec identification + skip_bits(&s->gb, 8); + + // Aux sync word present flag + if (get_bits1(&s->gb)) + // Aux sync distance + skip_bits(&s->gb, 3); break; } - /* not parsed further, we were only interested in the extensions mask */ - - if (get_bits_left(&s->gb) < 0) + if (asset->extension_mask & DCA_EXSS_XLL) + // DTS-HD stream ID + asset->hd_stream_id = get_bits(&s->gb, 3); + + // One to one mixing flag + // Per channel main audio scaling flag + // Main audio scaling codes + // Decode asset in secondary decoder flag + // Revision 2 DRC metadata + // Reserved + // Zero pad + if (ff_dca_seek_bits(&s->gb, descr_pos + descr_size * 8)) { + av_log(s->avctx, AV_LOG_ERROR, "Read past end of EXSS asset descriptor\n"); return AVERROR_INVALIDDATA; + } - if (get_bits_count(&s->gb) - header_pos > header_size * 8) { - av_log(s->avctx, AV_LOG_WARNING, "Asset header size mismatch.\n"); - return AVERROR_INVALIDDATA; + return 0; +} + +static int set_exss_offsets(DCAExssAsset *asset) +{ + int offs = asset->asset_offset; + int size = asset->asset_size; + + if (asset->extension_mask & DCA_EXSS_CORE) { + asset->core_offset = offs; + if (asset->core_size > size) + return AVERROR_INVALIDDATA; + offs += asset->core_size; + size -= asset->core_size; + } + + if (asset->extension_mask & DCA_EXSS_XBR) { + asset->xbr_offset = offs; + if (asset->xbr_size > size) + return AVERROR_INVALIDDATA; + offs += asset->xbr_size; + size -= asset->xbr_size; } - skip_bits_long(&s->gb, header_pos + header_size * 8 - get_bits_count(&s->gb)); - if (extensions_mask & DCA_EXT_EXSS_XLL) - s->profile = FF_PROFILE_DTS_HD_MA; - else if (extensions_mask & (DCA_EXT_EXSS_XBR | DCA_EXT_EXSS_X96 | - DCA_EXT_EXSS_XXCH)) - s->profile = FF_PROFILE_DTS_HD_HRA; + if (asset->extension_mask & DCA_EXSS_XXCH) { + asset->xxch_offset = offs; + if (asset->xxch_size > size) + return AVERROR_INVALIDDATA; + offs += asset->xxch_size; + size -= asset->xxch_size; + } + + if (asset->extension_mask & DCA_EXSS_X96) { + asset->x96_offset = offs; + if (asset->x96_size > size) + return AVERROR_INVALIDDATA; + offs += asset->x96_size; + size -= asset->x96_size; + } - if (!(extensions_mask & DCA_EXT_CORE)) - av_log(s->avctx, AV_LOG_WARNING, "DTS core detection mismatch.\n"); - if ((extensions_mask & DCA_CORE_EXTS) != s->core_ext_mask) - av_log(s->avctx, AV_LOG_WARNING, - "DTS extensions detection mismatch (%d, %d)\n", - extensions_mask & DCA_CORE_EXTS, s->core_ext_mask); + if (asset->extension_mask & DCA_EXSS_LBR) { + asset->lbr_offset = offs; + if (asset->lbr_size > size) + return AVERROR_INVALIDDATA; + offs += asset->lbr_size; + size -= asset->lbr_size; + } + + if (asset->extension_mask & DCA_EXSS_XLL) { + asset->xll_offset = offs; + if (asset->xll_size > size) + return AVERROR_INVALIDDATA; + offs += asset->xll_size; + size -= asset->xll_size; + } return 0; } -/** - * Parse extension substream header (HD) - */ -void ff_dca_exss_parse_header(DCAContext *s) +int ff_dca_exss_parse(DCAExssParser *s, uint8_t *data, int size) { - int asset_size[8]; - int ss_index; - int blownup; - int num_audiop = 1; - int num_assets = 1; - int active_ss_mask[8]; - int i, j; - int start_pos; - int hdrsize; - uint32_t mkr; - - if (get_bits_left(&s->gb) < 52) - return; - - start_pos = get_bits_count(&s->gb) - 32; - - skip_bits(&s->gb, 8); // user data - ss_index = get_bits(&s->gb, 2); - - blownup = get_bits1(&s->gb); - hdrsize = get_bits(&s->gb, 8 + 4 * blownup) + 1; // header_size - skip_bits(&s->gb, 16 + 4 * blownup); // hd_size - - s->static_fields = get_bits1(&s->gb); - if (s->static_fields) { - skip_bits(&s->gb, 2); // reference clock code - skip_bits(&s->gb, 3); // frame duration code + int i, ret, offset, wide_hdr, header_size; - if (get_bits1(&s->gb)) - skip_bits_long(&s->gb, 36); // timestamp + if ((ret = init_get_bits8(&s->gb, data, size)) < 0) + return ret; + + // Extension substream sync word + skip_bits_long(&s->gb, 32); + + // User defined bits + skip_bits(&s->gb, 8); + + // Extension substream index + s->exss_index = get_bits(&s->gb, 2); + + // Flag indicating short or long header size + wide_hdr = get_bits1(&s->gb); - /* a single stream can contain multiple audio assets that can be - * combined to form multiple audio presentations */ + // Extension substream header length + header_size = get_bits(&s->gb, 8 + 4 * wide_hdr) + 1; - num_audiop = get_bits(&s->gb, 3) + 1; - if (num_audiop > 1) { - avpriv_request_sample(s->avctx, - "Multiple DTS-HD audio presentations"); - /* ignore such streams for now */ - return; + // Check CRC + if ((s->avctx->err_recognition & (AV_EF_CRCCHECK | AV_EF_CAREFUL)) + && ff_dca_check_crc(&s->gb, 32 + 8, header_size * 8)) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid EXSS header checksum\n"); + return AVERROR_INVALIDDATA; + } + + s->exss_size_nbits = 16 + 4 * wide_hdr; + + // Number of bytes of extension substream + s->exss_size = get_bits(&s->gb, s->exss_size_nbits) + 1; + if (s->exss_size > size) { + av_log(s->avctx, AV_LOG_ERROR, "Packet too short for EXSS frame\n"); + return AVERROR_INVALIDDATA; + } + + // Per stream static fields presence flag + if (s->static_fields_present = get_bits1(&s->gb)) { + int active_exss_mask[8]; + + // Reference clock code + skip_bits(&s->gb, 2); + + // Extension substream frame duration + skip_bits(&s->gb, 3); + + // Timecode presence flag + if (get_bits1(&s->gb)) + // Timecode data + skip_bits_long(&s->gb, 36); + + // Number of defined audio presentations + s->npresents = get_bits(&s->gb, 3) + 1; + if (s->npresents > 1) { + avpriv_request_sample(s->avctx, "%d audio presentations", s->npresents); + return AVERROR_PATCHWELCOME; } - num_assets = get_bits(&s->gb, 3) + 1; - if (num_assets > 1) { - avpriv_request_sample(s->avctx, "Multiple DTS-HD audio assets"); - /* ignore such streams for now */ - return; + // Number of audio assets in extension substream + s->nassets = get_bits(&s->gb, 3) + 1; + if (s->nassets > 1) { + avpriv_request_sample(s->avctx, "%d audio assets", s->nassets); + return AVERROR_PATCHWELCOME; } - for (i = 0; i < num_audiop; i++) - active_ss_mask[i] = get_bits(&s->gb, ss_index + 1); + // Active extension substream mask for audio presentation + for (i = 0; i < s->npresents; i++) + active_exss_mask[i] = get_bits(&s->gb, s->exss_index + 1); - for (i = 0; i < num_audiop; i++) - for (j = 0; j <= ss_index; j++) - if (active_ss_mask[i] & (1 << j)) - skip_bits(&s->gb, 8); // active asset mask + // Active audio asset mask + for (i = 0; i < s->npresents; i++) + skip_bits_long(&s->gb, av_popcount(active_exss_mask[i]) * 8); - s->mix_metadata = get_bits1(&s->gb); - if (s->mix_metadata) { - int mix_out_mask_size; + // Mixing metadata enable flag + if (s->mix_metadata_enabled = get_bits1(&s->gb)) { + int spkr_mask_nbits; - skip_bits(&s->gb, 2); // adjustment level - mix_out_mask_size = (get_bits(&s->gb, 2) + 1) << 2; - s->num_mix_configs = get_bits(&s->gb, 2) + 1; + // Mixing metadata adjustment level + skip_bits(&s->gb, 2); - for (i = 0; i < s->num_mix_configs; i++) { - int mix_out_mask = get_bits(&s->gb, mix_out_mask_size); - s->mix_config_num_ch[i] = dca_exss_mask2count(mix_out_mask); - } + // Number of bits for mixer output speaker activity mask + spkr_mask_nbits = (get_bits(&s->gb, 2) + 1) << 2; + + // Number of mixing configurations + s->nmixoutconfigs = get_bits(&s->gb, 2) + 1; + + // Speaker layout mask for mixer output channels + for (i = 0; i < s->nmixoutconfigs; i++) + s->nmixoutchs[i] = count_chs_for_mask(get_bits(&s->gb, spkr_mask_nbits)); } + } else { + s->npresents = 1; + s->nassets = 1; } - av_assert0(num_assets > 0); // silence a warning - - for (i = 0; i < num_assets; i++) - asset_size[i] = get_bits_long(&s->gb, 16 + 4 * blownup) + 1; + // Size of encoded asset data in bytes + offset = header_size; + for (i = 0; i < s->nassets; i++) { + s->assets[i].asset_offset = offset; + s->assets[i].asset_size = get_bits(&s->gb, s->exss_size_nbits) + 1; + offset += s->assets[i].asset_size; + if (offset > s->exss_size) { + av_log(s->avctx, AV_LOG_ERROR, "EXSS asset out of bounds\n"); + return AVERROR_INVALIDDATA; + } + } - for (i = 0; i < num_assets; i++) { - if (dca_exss_parse_asset_header(s)) - return; + // Audio asset descriptor + for (i = 0; i < s->nassets; i++) { + if ((ret = parse_descriptor(s, &s->assets[i])) < 0) + return ret; + if ((ret = set_exss_offsets(&s->assets[i])) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid extension size in EXSS asset descriptor\n"); + return ret; + } } - j = get_bits_count(&s->gb); - if (start_pos + hdrsize * 8 > j) - skip_bits_long(&s->gb, start_pos + hdrsize * 8 - j); - - for (i = 0; i < num_assets; i++) { - int end_pos; - start_pos = get_bits_count(&s->gb); - end_pos = start_pos + asset_size[i] * 8; - mkr = get_bits_long(&s->gb, 32); - - /* parse extensions that we know about */ - switch (mkr) { - case DCA_SYNCWORD_XBR: - ff_dca_xbr_parse_frame(s); - break; - case DCA_SYNCWORD_XXCH: - ff_dca_xxch_decode_frame(s); - s->core_ext_mask |= DCA_EXT_XXCH; /* xxx use for chan reordering */ - break; - case DCA_SYNCWORD_XLL: - if (s->xll_disable) { - av_log(s->avctx, AV_LOG_DEBUG, - "DTS-XLL: ignoring XLL extension\n"); - break; - } - av_log(s->avctx, AV_LOG_DEBUG, - "DTS-XLL: decoding XLL extension\n"); - if (ff_dca_xll_decode_header(s) == 0 && - ff_dca_xll_decode_navi(s, end_pos) == 0) - s->exss_ext_mask |= DCA_EXT_EXSS_XLL; - break; - default: - av_log(s->avctx, AV_LOG_DEBUG, - "DTS-ExSS: unknown marker = 0x%08x\n", mkr); - } + // Backward compatible core present + // Backward compatible core substream index + // Backward compatible core asset index + // Reserved + // Byte align + // CRC16 of extension substream header + if (ff_dca_seek_bits(&s->gb, header_size * 8)) { + av_log(s->avctx, AV_LOG_ERROR, "Read past end of EXSS header\n"); + return AVERROR_INVALIDDATA; + } - /* skip to end of block */ - j = get_bits_count(&s->gb); - if (j > end_pos) - av_log(s->avctx, AV_LOG_ERROR, - "DTS-ExSS: Processed asset too long.\n"); - if (j < end_pos) - skip_bits_long(&s->gb, end_pos - j); - } + return 0; }