]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/dca_exss.c
diradec: split tables away to a separate diractab file
[ffmpeg] / libavcodec / dca_exss.c
index ed014906cec6d1ec2b7b125922d1db4c0997b487..4579f2350fedb27bde061946edd908321f0c9352 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DCA ExSS extension
+ * Copyright (C) 2016 foo86
  *
  * This file is part of FFmpeg.
  *
  * 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;
 }