[FFmpeg-devel] [RFC] avcodec: Add native DCA decoder based on libdcadec.

foo86 foobaz86 at gmail.com
Sun Jan 3 18:49:10 CET 2016


This is initial version of libdcadec DCA decoder port I hacked together over
the last week. This patch is of RFC/inquiry type and not meant for immediate
inclusion.

Any comments about the code are appreciated, as well as suggestions concerning
how should I proceed with this patch. Should I aim for including it as a
separate decoder or a replacement for existing DCA decoder? Or it might be that
you prefer to continue improving existing decoder instead and not merge this at
all.

Attached decoder is feature complete enough to fully decode any practically
available DTS stream configuration. It supports any possible combinations of
XCH, XXCH, XBR and X96 core extensions to deliver up to 7.1 ch, 96 kHz floating
point output. It also implements lossless decoding of XLL extension to deliver
up to 7.1 ch, 192 kHz fixed point output. Bit rate managed XLL streams are
supported. Downmixing to 5.1 and stereo using embedded coefficients is
supported.

Performance wise, this decoder used to be around 10% slower than pure floating
point version of existing native DCA decoder. However, after native DCA decoder
has been partially converted to fixed point, this decoder became 5% faster than
native one. Measurements were done looping over 5.1 core only stream in
floating point mode on a x86_64 system. Of course, decoding extensions like X96
and XLL makes the decoder much slower. These can be ignored with -core_only
option.

The libdcadec code this decoder is based on has been rather well tested and
stable, thus I don't expect any fundamental issues with this new decoder. I
might have introduced some bugs during porting; these should be hopefully found
by regression tests and fixed. Note that I've not run this decoder through any
serious regression testing yet, I just checked that it works on several select
samples.

This decoder depends on assembly versions of existing native dcadsp, however it
only uses assembly optimized version of synth_filter currently. Because
synth_filter implicitly depends on dcadsp this is required to allow decoder to
build when existing DCA decoder is disabled. I plan to overhaul this area
(interacting with existing dcadsp) later.

---
 configure                   |    1 +
 libavcodec/Makefile         |    4 +
 libavcodec/aarch64/Makefile |    3 +
 libavcodec/allcodecs.c      |    1 +
 libavcodec/arm/Makefile     |    5 +
 libavcodec/dca2.h           |  547 +++++++++
 libavcodec/dca2_core.c      | 2565 +++++++++++++++++++++++++++++++++++++++++++
 libavcodec/dca2_exss.c      |  500 +++++++++
 libavcodec/dca2_math.h      |  108 ++
 libavcodec/dca2_xll.c       | 1412 ++++++++++++++++++++++++
 libavcodec/dcadata2.c       |  637 +++++++++++
 libavcodec/dcadata2.h       |   36 +
 libavcodec/dcadec2.c        |  542 +++++++++
 libavcodec/dcadsp2_fixed.c  |  516 +++++++++
 libavcodec/dcadsp2_float.c  |  183 +++
 libavcodec/x86/Makefile     |    2 +
 16 files changed, 7062 insertions(+)
 create mode 100644 libavcodec/dca2.h
 create mode 100644 libavcodec/dca2_core.c
 create mode 100644 libavcodec/dca2_exss.c
 create mode 100644 libavcodec/dca2_math.h
 create mode 100644 libavcodec/dca2_xll.c
 create mode 100644 libavcodec/dcadata2.c
 create mode 100644 libavcodec/dcadata2.h
 create mode 100644 libavcodec/dcadec2.c
 create mode 100644 libavcodec/dcadsp2_fixed.c
 create mode 100644 libavcodec/dcadsp2_float.c

diff --git a/configure b/configure
index 6710f85..0d2aa4f 100755
--- a/configure
+++ b/configure
@@ -2277,6 +2277,7 @@ comfortnoise_encoder_select="lpc"
 cook_decoder_select="audiodsp mdct sinewin"
 cscd_decoder_select="lzo"
 cscd_decoder_suggest="zlib"
+dca2_decoder_select="mdct"
 dca_decoder_select="fmtconvert mdct"
 dds_decoder_select="texturedsp"
 dirac_decoder_select="dirac_parse dwt golomb videodsp mpegvideoenc"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index a18ca5b..d0290c1 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -221,6 +221,10 @@ OBJS-$(CONFIG_COMFORTNOISE_ENCODER)    += cngenc.o
 OBJS-$(CONFIG_CPIA_DECODER)            += cpia.o
 OBJS-$(CONFIG_CSCD_DECODER)            += cscd.o
 OBJS-$(CONFIG_CYUV_DECODER)            += cyuv.o
+OBJS-$(CONFIG_DCA2_DECODER)            += dcadec2.o dca.o dcadsp2_float.o       \
+                                          dcadsp2_fixed.o dcadata.o dcadata2.o  \
+                                          dca2_exss.o dca2_xll.o dca2_core.o    \
+                                          synth_filter.o
 OBJS-$(CONFIG_DCA_DECODER)             += dcadec.o dca.o dcadsp.o      \
                                           dcadata.o dca_exss.o         \
                                           dca_xll.o synth_filter.o
diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile
index 022ed84..6871aef 100644
--- a/libavcodec/aarch64/Makefile
+++ b/libavcodec/aarch64/Makefile
@@ -1,3 +1,4 @@
+OBJS-$(CONFIG_DCA2_DECODER)             += aarch64/dcadsp_init.o
 OBJS-$(CONFIG_DCA_DECODER)              += aarch64/dcadsp_init.o
 OBJS-$(CONFIG_FFT)                      += aarch64/fft_init_aarch64.o
 OBJS-$(CONFIG_FMTCONVERT)               += aarch64/fmtconvert_init.o
@@ -17,6 +18,8 @@ OBJS-$(CONFIG_VORBIS_DECODER)           += aarch64/vorbisdsp_init.o
 
 ARMV8-OBJS-$(CONFIG_VIDEODSP)           += aarch64/videodsp.o
 
+NEON-OBJS-$(CONFIG_DCA2_DECODER)        += aarch64/dcadsp_neon.o               \
+                                           aarch64/synth_filter_neon.o
 NEON-OBJS-$(CONFIG_DCA_DECODER)         += aarch64/dcadsp_neon.o               \
                                            aarch64/synth_filter_neon.o
 NEON-OBJS-$(CONFIG_FFT)                 += aarch64/fft_neon.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4eeb6f3..3225ca4 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -387,6 +387,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(BINKAUDIO_RDFT,    binkaudio_rdft);
     REGISTER_DECODER(BMV_AUDIO,         bmv_audio);
     REGISTER_DECODER(COOK,              cook);
+    REGISTER_DECODER(DCA2,              dca2);
     REGISTER_ENCDEC (DCA,               dca);
     REGISTER_DECODER(DSD_LSBF,          dsd_lsbf);
     REGISTER_DECODER(DSD_MSBF,          dsd_msbf);
diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
index cdd35b0..619f1d3 100644
--- a/libavcodec/arm/Makefile
+++ b/libavcodec/arm/Makefile
@@ -36,6 +36,7 @@ OBJS-$(CONFIG_VP8DSP)                  += arm/vp8dsp_init_arm.o
 # decoders/encoders
 OBJS-$(CONFIG_AAC_DECODER)             += arm/aacpsdsp_init_arm.o       \
                                           arm/sbrdsp_init_arm.o
+OBJS-$(CONFIG_DCA2_DECODER)            += arm/dcadsp_init_arm.o
 OBJS-$(CONFIG_DCA_DECODER)             += arm/dcadsp_init_arm.o
 OBJS-$(CONFIG_HEVC_DECODER)            += arm/hevcdsp_init_arm.o
 OBJS-$(CONFIG_MLP_DECODER)             += arm/mlpdsp_init_arm.o
@@ -87,6 +88,8 @@ VFP-OBJS-$(CONFIG_FMTCONVERT)          += arm/fmtconvert_vfp.o
 VFP-OBJS-$(CONFIG_MDCT)                += arm/mdct_vfp.o
 
 # decoders/encoders
+VFP-OBJS-$(CONFIG_DCA2_DECODER)        += arm/dcadsp_vfp.o              \
+                                          arm/synth_filter_vfp.o
 VFP-OBJS-$(CONFIG_DCA_DECODER)         += arm/dcadsp_vfp.o              \
                                           arm/synth_filter_vfp.o
 
@@ -127,6 +130,8 @@ NEON-OBJS-$(CONFIG_VP8DSP)             += arm/vp8dsp_init_neon.o        \
 NEON-OBJS-$(CONFIG_AAC_DECODER)        += arm/aacpsdsp_neon.o           \
                                           arm/sbrdsp_neon.o
 NEON-OBJS-$(CONFIG_LLAUDDSP)           += arm/lossless_audiodsp_neon.o
+NEON-OBJS-$(CONFIG_DCA2_DECODER)       += arm/dcadsp_neon.o             \
+                                          arm/synth_filter_neon.o
 NEON-OBJS-$(CONFIG_DCA_DECODER)        += arm/dcadsp_neon.o             \
                                           arm/synth_filter_neon.o
 NEON-OBJS-$(CONFIG_HEVC_DECODER)       += arm/hevcdsp_init_neon.o       \
diff --git a/libavcodec/dca2.h b/libavcodec/dca2.h
new file mode 100644
index 0000000..2f52450
--- /dev/null
+++ b/libavcodec/dca2.h
@@ -0,0 +1,547 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_DCA2_H
+#define AVCODEC_DCA2_H
+
+#include "libavutil/common.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/float_dsp.h"
+#include "libavutil/opt.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "dca_syncwords.h"
+#include "dcadata.h"
+#include "dcadata2.h"
+#include "get_bits.h"
+#include "unary.h"
+#include "fft.h"
+#include "synth_filter.h"
+
+#define DCA2_BUFFER_PADDING_SIZE    1024
+
+#define DCA2_PACKET_CORE        0x01
+#define DCA2_PACKET_EXSS        0x02
+#define DCA2_PACKET_XLL         0x04
+#define DCA2_PACKET_RECOVERY    0x08
+
+enum DCA2Speaker {
+    DCA2_SPEAKER_C,    DCA2_SPEAKER_L,    DCA2_SPEAKER_R,    DCA2_SPEAKER_Ls,
+    DCA2_SPEAKER_Rs,   DCA2_SPEAKER_LFE1, DCA2_SPEAKER_Cs,   DCA2_SPEAKER_Lsr,
+    DCA2_SPEAKER_Rsr,  DCA2_SPEAKER_Lss,  DCA2_SPEAKER_Rss,  DCA2_SPEAKER_Lc,
+    DCA2_SPEAKER_Rc,   DCA2_SPEAKER_Lh,   DCA2_SPEAKER_Ch,   DCA2_SPEAKER_Rh,
+    DCA2_SPEAKER_LFE2, DCA2_SPEAKER_Lw,   DCA2_SPEAKER_Rw,   DCA2_SPEAKER_Oh,
+    DCA2_SPEAKER_Lhs,  DCA2_SPEAKER_Rhs,  DCA2_SPEAKER_Chr,  DCA2_SPEAKER_Lhr,
+    DCA2_SPEAKER_Rhr,  DCA2_SPEAKER_Cl,   DCA2_SPEAKER_Ll,   DCA2_SPEAKER_Rl,
+    DCA2_SPEAKER_RSV1, DCA2_SPEAKER_RSV2, DCA2_SPEAKER_RSV3, DCA2_SPEAKER_RSV4,
+
+    DCA2_SPEAKER_COUNT
+};
+
+enum DCA2SpeakerMask {
+    DCA2_SPEAKER_MASK_C     = 0x00000001,
+    DCA2_SPEAKER_MASK_L     = 0x00000002,
+    DCA2_SPEAKER_MASK_R     = 0x00000004,
+    DCA2_SPEAKER_MASK_Ls    = 0x00000008,
+    DCA2_SPEAKER_MASK_Rs    = 0x00000010,
+    DCA2_SPEAKER_MASK_LFE1  = 0x00000020,
+    DCA2_SPEAKER_MASK_Cs    = 0x00000040,
+    DCA2_SPEAKER_MASK_Lsr   = 0x00000080,
+    DCA2_SPEAKER_MASK_Rsr   = 0x00000100,
+    DCA2_SPEAKER_MASK_Lss   = 0x00000200,
+    DCA2_SPEAKER_MASK_Rss   = 0x00000400,
+    DCA2_SPEAKER_MASK_Lc    = 0x00000800,
+    DCA2_SPEAKER_MASK_Rc    = 0x00001000,
+    DCA2_SPEAKER_MASK_Lh    = 0x00002000,
+    DCA2_SPEAKER_MASK_Ch    = 0x00004000,
+    DCA2_SPEAKER_MASK_Rh    = 0x00008000,
+    DCA2_SPEAKER_MASK_LFE2  = 0x00010000,
+    DCA2_SPEAKER_MASK_Lw    = 0x00020000,
+    DCA2_SPEAKER_MASK_Rw    = 0x00040000,
+    DCA2_SPEAKER_MASK_Oh    = 0x00080000,
+    DCA2_SPEAKER_MASK_Lhs   = 0x00100000,
+    DCA2_SPEAKER_MASK_Rhs   = 0x00200000,
+    DCA2_SPEAKER_MASK_Chr   = 0x00400000,
+    DCA2_SPEAKER_MASK_Lhr   = 0x00800000,
+    DCA2_SPEAKER_MASK_Rhr   = 0x01000000,
+    DCA2_SPEAKER_MASK_Cl    = 0x02000000,
+    DCA2_SPEAKER_MASK_Ll    = 0x04000000,
+    DCA2_SPEAKER_MASK_Rl    = 0x08000000,
+};
+
+#define DCA2_SPEAKER_LAYOUT_MONO         (DCA2_SPEAKER_MASK_C)
+#define DCA2_SPEAKER_LAYOUT_STEREO       (DCA2_SPEAKER_MASK_L | DCA2_SPEAKER_MASK_R)
+#define DCA2_SPEAKER_LAYOUT_2POINT1      (DCA2_SPEAKER_LAYOUT_STEREO | DCA2_SPEAKER_MASK_LFE1)
+#define DCA2_SPEAKER_LAYOUT_3_0          (DCA2_SPEAKER_LAYOUT_STEREO | DCA2_SPEAKER_MASK_C)
+#define DCA2_SPEAKER_LAYOUT_2_1          (DCA2_SPEAKER_LAYOUT_STEREO | DCA2_SPEAKER_MASK_Cs)
+#define DCA2_SPEAKER_LAYOUT_3_1          (DCA2_SPEAKER_LAYOUT_3_0 | DCA2_SPEAKER_MASK_Cs)
+#define DCA2_SPEAKER_LAYOUT_2_2          (DCA2_SPEAKER_LAYOUT_STEREO | DCA2_SPEAKER_MASK_Ls | DCA2_SPEAKER_MASK_Rs)
+#define DCA2_SPEAKER_LAYOUT_5POINT0      (DCA2_SPEAKER_LAYOUT_3_0 | DCA2_SPEAKER_MASK_Ls | DCA2_SPEAKER_MASK_Rs)
+#define DCA2_SPEAKER_LAYOUT_5POINT1      (DCA2_SPEAKER_LAYOUT_5POINT0 | DCA2_SPEAKER_MASK_LFE1)
+#define DCA2_SPEAKER_LAYOUT_7POINT0_WIDE (DCA2_SPEAKER_LAYOUT_5POINT0 | DCA2_SPEAKER_MASK_Lw | DCA2_SPEAKER_MASK_Rw)
+#define DCA2_SPEAKER_LAYOUT_7POINT1_WIDE (DCA2_SPEAKER_LAYOUT_7POINT0_WIDE | DCA2_SPEAKER_MASK_LFE1)
+
+enum DCA2RepresentationType {
+    DCA2_REPR_TYPE_LtRt = 2,
+    DCA2_REPR_TYPE_LhRh = 3
+};
+
+enum DCA2ExtensionMask {
+    DCA2_CSS_CORE   = 0x001,
+    DCA2_CSS_XXCH   = 0x002,
+    DCA2_CSS_X96    = 0x004,
+    DCA2_CSS_XCH    = 0x008,
+    DCA2_CSS_MASK   = 0x00f,
+    DCA2_EXSS_CORE  = 0x010,
+    DCA2_EXSS_XBR   = 0x020,
+    DCA2_EXSS_XXCH  = 0x040,
+    DCA2_EXSS_X96   = 0x080,
+    DCA2_EXSS_LBR   = 0x100,
+    DCA2_EXSS_XLL   = 0x200,
+    DCA2_EXSS_RSV1  = 0x400,
+    DCA2_EXSS_RSV2  = 0x800,
+    DCA2_EXSS_MASK  = 0xff0,
+};
+
+enum DCA2DownMixType {
+    DCA2_DMIX_TYPE_1_0,
+    DCA2_DMIX_TYPE_LoRo,
+    DCA2_DMIX_TYPE_LtRt,
+    DCA2_DMIX_TYPE_3_0,
+    DCA2_DMIX_TYPE_2_1,
+    DCA2_DMIX_TYPE_2_2,
+    DCA2_DMIX_TYPE_3_1,
+
+    DCA2_DMIX_TYPE_COUNT
+};
+
+// ============================================================================
+
+typedef struct DCA2ExssAsset {
+    int     asset_offset;   ///< Offset to asset data from start of substream
+    int     asset_size;     ///< Size of encoded asset data
+    int     asset_index;    ///< Audio asset identifier
+
+    int     pcm_bit_res;                ///< PCM bit resolution
+    int     max_sample_rate;            ///< Maximum sample rate
+    int     nchannels_total;            ///< Total number of channels
+    int     one_to_one_map_ch_to_spkr;  ///< One to one channel to speaker mapping flag
+    int     embedded_stereo;            ///< Embedded stereo flag
+    int     embedded_6ch;               ///< Embedded 6 channels flag
+    int     spkr_mask_enabled;          ///< Speaker mask enabled flag
+    int     spkr_mask;                  ///< Loudspeaker activity mask
+    int     representation_type;        ///< Representation type
+
+    int     coding_mode;        ///< Coding mode for the asset
+    int     extension_mask;     ///< Coding components used in asset
+
+    int     core_offset;    ///< Offset to core component from start of substream
+    int     core_size;      ///< Size of core component in extension substream
+
+    int     xbr_offset;     ///< Offset to XBR extension from start of substream
+    int     xbr_size;       ///< Size of XBR extension in extension substream
+
+    int     xxch_offset;    ///< Offset to XXCH extension from start of substream
+    int     xxch_size;      ///< Size of XXCH extension in extension substream
+
+    int     x96_offset;     ///< Offset to X96 extension from start of substream
+    int     x96_size;       ///< Size of X96 extension in extension substream
+
+    int     lbr_offset;     ///< Offset to LBR component from start of substream
+    int     lbr_size;       ///< Size of LBR component in extension substream
+
+    int     xll_offset;         ///< Offset to XLL data from start of substream
+    int     xll_size;           ///< Size of XLL data in extension substream
+    int     xll_sync_present;   ///< XLL sync word present flag
+    int     xll_delay_nframes;  ///< Initial XLL decoding delay in frames
+    int     xll_sync_offset;    ///< Number of bytes offset to XLL sync
+
+    int     hd_stream_id;   ///< DTS-HD stream ID
+} DCA2ExssAsset;
+
+typedef struct DCA2ExssParser {
+    AVCodecContext  *avctx;
+    GetBitContext   gb;
+
+    int     exss_index;         ///< Extension substream index
+    int     exss_size_nbits;    ///< Number of bits for extension substream size
+    int     exss_size;          ///< Number of bytes of extension substream
+
+    int     static_fields_present;  ///< Per stream static fields presence flag
+    int     npresents;  ///< Number of defined audio presentations
+    int     nassets;    ///< Number of audio assets in extension substream
+
+    int     mix_metadata_enabled;   ///< Mixing metadata enable flag
+    int     nmixoutconfigs;         ///< Number of mixing configurations
+    int     nmixoutchs[4];          ///< Speaker layout mask for mixer output channels
+
+    DCA2ExssAsset   assets[1];    ///< Audio asset descriptors
+} DCA2ExssParser;
+
+int ff_dca2_exss_parse(DCA2ExssParser *s, uint8_t *data, int size);
+
+// ============================================================================
+
+#define DCA2_CHANNELS           7
+#define DCA2_SUBBANDS           32
+#define DCA2_SUBBANDS_X96       64
+#define DCA2_SUBFRAMES          16
+#define DCA2_SUBBAND_SAMPLES    8
+#define DCA2_PCMBLOCK_SAMPLES   32
+#define DCA2_ADPCM_COEFFS       4
+#define DCA2_LFE_HISTORY        8
+#define DCA2_CODE_BOOKS         10
+
+#define DCA2_CORE_CHANNELS_MAX      6
+#define DCA2_DMIX_CHANNELS_MAX      4
+#define DCA2_XXCH_CHANNELS_MAX      2
+#define DCA2_EXSS_CHANNELS_MAX      8
+#define DCA2_EXSS_CHSETS_MAX        4
+
+typedef struct DCA2DspData {
+    union {
+        struct {
+            DECLARE_ALIGNED(32, float, hist1)[512];
+            DECLARE_ALIGNED(32, float, hist2)[32];
+        } flt32;
+        struct {
+            DECLARE_ALIGNED(32, int, hist1)[512];
+            DECLARE_ALIGNED(32, int, hist2)[32];
+        } fix32;
+        struct {
+            DECLARE_ALIGNED(32, float, hist1)[1024];
+            DECLARE_ALIGNED(32, float, hist2)[64];
+        } flt64;
+        struct {
+            DECLARE_ALIGNED(32, int, hist1)[1024];
+            DECLARE_ALIGNED(32, int, hist2)[64];
+        } fix64;
+    } u;
+    int offset;
+} DCA2DspData;
+
+typedef struct DCA2FloatDspContext {
+    void (*lfe_fir[2])(float *pcm_samples, int *lfe_samples, int npcmblocks);
+    void (*sub_qmf[2])(FFTContext *imdct,
+                       SynthFilterContext *synth,
+                       float *pcm_samples,
+                       int **subband_samples_lo,
+                       int **subband_samples_hi,
+                       DCA2DspData *dsp,
+                       int nsamples, int perfect);
+} DCA2FloatDspContext;
+
+typedef struct DCA2FixedDspContext {
+    void (*lfe_fir)(int *pcm_samples, int *lfe_samples, int npcmblocks);
+    void (*sub_qmf[2])(int *pcm_samples,
+                       int **subband_samples_lo,
+                       int **subband_samples_hi,
+                       DCA2DspData *dsp,
+                       int nsamples, int perfect);
+} DCA2FixedDspContext;
+
+typedef struct DCA2CoreDecoder {
+    AVCodecContext  *avctx;
+    GetBitContext   gb;
+
+    // Bit stream header
+    int     crc_present;        ///< CRC present flag
+    int     npcmblocks;         ///< Number of PCM sample blocks
+    int     frame_size;         ///< Primary frame byte size
+    int     audio_mode;         ///< Audio channel arrangement
+    int     sample_rate;        ///< Core audio sampling frequency
+    int     bit_rate;           ///< Transmission bit rate
+    int     drc_present;        ///< Embedded dynamic range flag
+    int     ts_present;         ///< Embedded time stamp flag
+    int     aux_present;        ///< Auxiliary data flag
+    int     ext_audio_type;     ///< Extension audio descriptor flag
+    int     ext_audio_present;  ///< Extended coding flag
+    int     sync_ssf;           ///< Audio sync word insertion flag
+    int     lfe_present;        ///< Low frequency effects flag
+    int     predictor_history;  ///< Predictor history flag switch
+    int     filter_perfect;     ///< Multirate interpolator switch
+    int     source_pcm_res;     ///< Source PCM resolution
+    int     es_format;          ///< Extended surround (ES) mastering flag
+    int     sumdiff_front;      ///< Front sum/difference flag
+    int     sumdiff_surround;   ///< Surround sum/difference flag
+
+    // Primary audio coding header
+    int         nsubframes;     ///< Number of subframes
+    int         nchannels;      ///< Number of primary audio channels (incl. extension channels)
+    int         ch_mask;        ///< Speaker layout mask (incl. LFE and extension channels)
+    int8_t      nsubbands[DCA2_CHANNELS];                ///< Subband activity count
+    int8_t      subband_vq_start[DCA2_CHANNELS];         ///< High frequency VQ start subband
+    int8_t      joint_intensity_index[DCA2_CHANNELS];    ///< Joint intensity coding index
+    int8_t      transition_mode_sel[DCA2_CHANNELS];      ///< Transient mode code book
+    int8_t      scale_factor_sel[DCA2_CHANNELS];         ///< Scale factor code book
+    int8_t      bit_allocation_sel[DCA2_CHANNELS];       ///< Bit allocation quantizer select
+    int8_t      quant_index_sel[DCA2_CHANNELS][DCA2_CODE_BOOKS];  ///< Quantization index codebook select
+    int32_t     scale_factor_adj[DCA2_CHANNELS][DCA2_CODE_BOOKS]; ///< Scale factor adjustment
+
+    // Primary audio coding side information
+    int8_t      nsubsubframes[DCA2_SUBFRAMES];   ///< Subsubframe count for each subframe
+    int8_t      prediction_mode[DCA2_CHANNELS][DCA2_SUBBANDS_X96];             ///< Prediction mode
+    int16_t     prediction_vq_index[DCA2_CHANNELS][DCA2_SUBBANDS_X96];         ///< Prediction coefficients VQ address
+    int8_t      bit_allocation[DCA2_CHANNELS][DCA2_SUBBANDS_X96];              ///< Bit allocation index
+    int8_t      transition_mode[DCA2_SUBFRAMES][DCA2_CHANNELS][DCA2_SUBBANDS];  ///< Transition mode
+    int32_t     scale_factors[DCA2_CHANNELS][DCA2_SUBBANDS][2];                ///< Scale factors (2x for transients and X96)
+    int8_t      joint_scale_sel[DCA2_CHANNELS];                                ///< Joint subband codebook select
+    int32_t     joint_scale_factors[DCA2_CHANNELS][DCA2_SUBBANDS_X96];         ///< Scale factors for joint subband coding
+
+    // Auxiliary data
+    int     prim_dmix_embedded; ///< Auxiliary dynamic downmix flag
+    int     prim_dmix_type;     ///< Auxiliary primary channel downmix type
+    int     prim_dmix_coeff[DCA2_DMIX_CHANNELS_MAX * DCA2_CORE_CHANNELS_MAX]; ///< Dynamic downmix code coefficients
+
+    // Core extensions
+    int     ext_audio_mask;     ///< Bit mask of fully decoded core extensions
+
+    // XCH extension data
+    int     xch_pos;    ///< Bit position of XCH frame in core substream
+
+    // XXCH extension data
+    int     xxch_crc_present;       ///< CRC presence flag for XXCH channel set header
+    int     xxch_mask_nbits;        ///< Number of bits for loudspeaker mask
+    int     xxch_core_mask;         ///< Core loudspeaker activity mask
+    int     xxch_spkr_mask;         ///< Loudspeaker layout mask
+    int     xxch_dmix_embedded;     ///< Downmix already performed by encoder
+    int     xxch_dmix_scale_inv;    ///< Downmix scale factor
+    int     xxch_dmix_mask[DCA2_XXCH_CHANNELS_MAX];  ///< Downmix channel mapping mask
+    int     xxch_dmix_coeff[DCA2_XXCH_CHANNELS_MAX * DCA2_CORE_CHANNELS_MAX];     ///< Downmix coefficients
+    int     xxch_pos;   ///< Bit position of XXCH frame in core substream
+
+    // X96 extension data
+    int     x96_rev_no;         ///< X96 revision number
+    int     x96_crc_present;    ///< CRC presence flag for X96 channel set header
+    int     x96_nchannels;      ///< Number of primary channels in X96 extension
+    int     x96_high_res;       ///< X96 high resolution flag
+    int     x96_subband_start;  ///< First encoded subband in X96 extension
+    int     x96_rand;           ///< Random seed for generating samples for unallocated X96 subbands
+    int     x96_pos;            ///< Bit position of X96 frame in core substream
+
+    // Sample buffers
+    unsigned int    x96_subband_size;
+    int             *x96_subband_buffer;    ///< X96 subband sample buffer base
+    int             *x96_subband_samples[DCA2_CHANNELS][DCA2_SUBBANDS_X96];   ///< X96 subband samples
+
+    unsigned int    subband_size;
+    int             *subband_buffer;    ///< Subband sample buffer base
+    int             *subband_samples[DCA2_CHANNELS][DCA2_SUBBANDS];   ///< Subband samples
+    int             *lfe_samples;    ///< Decimated LFE samples
+
+    // DSP contexts
+    DCA2DspData             dcadsp_data[DCA2_CHANNELS];    ///< FIR history buffers
+    DCA2FloatDspContext     dcadsp_float;
+    DCA2FixedDspContext     dcadsp_fixed;
+    FFTContext              imdct[2];
+    SynthFilterContext      synth;
+    AVFloatDSPContext       *fdsp;
+
+    // PCM output data
+    unsigned int    output_size;
+    void            *output_buffer;                         ///< PCM output buffer base
+    int             *output_samples[DCA2_SPEAKER_COUNT];    ///< PCM output speaker map
+    int             output_history_lfe_fixed;               ///< LFE PCM history for X96 filter
+    float           output_history_lfe_float;               ///< LFE PCM history for X96 filter
+
+    int     ch_remap[DCA2_SPEAKER_COUNT];
+    int     request_mask;
+
+    int     npcmsamples;    ///< Number of PCM samples per channel
+    int     output_rate;    ///< Output sample rate (1x or 2x header rate)
+
+    int     filter_mode;   ///< Previous filtering mode for detecting changes
+} DCA2CoreDecoder;
+
+static inline int ff_dca2_core_map_spkr(DCA2CoreDecoder *core, int spkr)
+{
+    if (core->ch_mask & (1U << spkr))
+        return spkr;
+    if (spkr == DCA2_SPEAKER_Lss && (core->ch_mask & DCA2_SPEAKER_MASK_Ls))
+        return DCA2_SPEAKER_Ls;
+    if (spkr == DCA2_SPEAKER_Rss && (core->ch_mask & DCA2_SPEAKER_MASK_Rs))
+        return DCA2_SPEAKER_Rs;
+    return -1;
+}
+
+int ff_dca2_core_parse(DCA2CoreDecoder *s, uint8_t *data, int size);
+int ff_dca2_core_parse_exss(DCA2CoreDecoder *s, uint8_t *data, DCA2ExssAsset *asset);
+int ff_dca2_core_filter_fixed(DCA2CoreDecoder *s, int x96_synth);
+int ff_dca2_core_filter_frame(DCA2CoreDecoder *s, AVFrame *frame);
+av_cold void ff_dca2_core_flush(DCA2CoreDecoder *s);
+av_cold int ff_dca2_core_init(DCA2CoreDecoder *s);
+av_cold void ff_dca2_core_close(DCA2CoreDecoder *s);
+
+av_cold void ff_dcadsp2_float_init(DCA2FloatDspContext *s);
+av_cold void ff_dcadsp2_fixed_init(DCA2FixedDspContext *s);
+
+// ============================================================================
+
+#define DCA2_XLL_CHSETS_MAX             3
+#define DCA2_XLL_CHANNELS_MAX           8
+#define DCA2_XLL_BANDS_MAX              2
+#define DCA2_XLL_ADAPT_PRED_ORDER_MAX   16
+#define DCA2_XLL_DECI_HISTORY_MAX       8
+#define DCA2_XLL_DMIX_SCALES_MAX        ((DCA2_XLL_CHSETS_MAX - 1) * DCA2_XLL_CHANNELS_MAX)
+#define DCA2_XLL_DMIX_COEFFS_MAX        (DCA2_XLL_DMIX_SCALES_MAX * DCA2_XLL_CHANNELS_MAX)
+#define DCA2_XLL_PBR_BUFFER_MAX         (240 << 10)
+#define DCA2_XLL_SAMPLE_BUFFERS_MAX     3
+
+typedef struct DCA2XllBand {
+    int     decor_enabled;                      ///< Pairwise channel decorrelation flag
+    int     orig_order[DCA2_XLL_CHANNELS_MAX];       ///< Original channel order
+    int     decor_coeff[DCA2_XLL_CHANNELS_MAX / 2];  ///< Pairwise channel coefficients
+
+    int     adapt_pred_order[DCA2_XLL_CHANNELS_MAX]; ///< Adaptive predictor order
+    int     highest_pred_order;                 ///< Highest adaptive predictor order
+    int     fixed_pred_order[DCA2_XLL_CHANNELS_MAX]; ///< Fixed predictor order
+    int     adapt_refl_coeff[DCA2_XLL_CHANNELS_MAX][DCA2_XLL_ADAPT_PRED_ORDER_MAX];   ///< Adaptive predictor reflection coefficients
+
+    int     dmix_embedded;  ///< Downmix performed by encoder in frequency band
+
+    int     lsb_section_size;                   ///< Size of LSB section in any segment
+    int     nscalablelsbs[DCA2_XLL_CHANNELS_MAX];    ///< Number of bits to represent the samples in LSB part
+    int     bit_width_adjust[DCA2_XLL_CHANNELS_MAX]; ///< Number of bits discarded by authoring
+
+    int     *msb_sample_buffer[DCA2_XLL_CHANNELS_MAX];   ///< MSB sample buffer pointers
+    int     *lsb_sample_buffer[DCA2_XLL_CHANNELS_MAX];   ///< LSB sample buffer pointers or NULL
+} DCA2XllBand;
+
+typedef struct DCA2XllChSet {
+    // Channel set header
+    int     nchannels;          ///< Number of channels in the channel set (N)
+    int     residual_encode;    ///< Residual encoding mask (0 - residual, 1 - full channel)
+    int     pcm_bit_res;        ///< PCM bit resolution (variable)
+    int     storage_bit_res;    ///< Storage bit resolution (16 or 24)
+    int     freq;               ///< Original sampling frequency (max. 96000 Hz)
+
+    int     primary_chset;          ///< Primary channel set flag
+    int     dmix_coeffs_present;    ///< Downmix coefficients present in stream
+    int     dmix_embedded;          ///< Downmix already performed by encoder
+    int     dmix_type;              ///< Primary channel set downmix type
+    int     hier_chset;             ///< Whether the channel set is part of a hierarchy
+    int     hier_ofs;               ///< Number of preceding channels in a hierarchy (M)
+    int     dmix_coeff[DCA2_XLL_DMIX_COEFFS_MAX];       ///< Downmixing coefficients
+    int     dmix_scale[DCA2_XLL_DMIX_SCALES_MAX];       ///< Downmixing scales
+    int     dmix_scale_inv[DCA2_XLL_DMIX_SCALES_MAX];   ///< Inverse downmixing scales
+    int     ch_mask;                ///< Channel mask for set
+    int     ch_remap[DCA2_XLL_CHANNELS_MAX];
+
+    int     nfreqbands; ///< Number of frequency bands (1 or 2)
+    int     nabits;     ///< Number of bits to read bit allocation coding parameter
+
+    DCA2XllBand     bands[DCA2_XLL_BANDS_MAX];   ///< Frequency bands
+
+    // Frequency band coding parameters
+    int     seg_common;                                     ///< Segment type
+    int     rice_code_flag[DCA2_XLL_CHANNELS_MAX];          ///< Rice coding flag
+    int     bitalloc_hybrid_linear[DCA2_XLL_CHANNELS_MAX];  ///< Binary code length for isolated samples
+    int     bitalloc_part_a[DCA2_XLL_CHANNELS_MAX];         ///< Coding parameter for part A of segment
+    int     bitalloc_part_b[DCA2_XLL_CHANNELS_MAX];         ///< Coding parameter for part B of segment
+    int     nsamples_part_a[DCA2_XLL_CHANNELS_MAX];         ///< Number of samples in part A of segment
+
+    // Decimator history
+    int     deci_history[DCA2_XLL_CHANNELS_MAX][DCA2_XLL_DECI_HISTORY_MAX];   ///< Decimator history for frequency band 1
+
+    // Sample buffers
+    unsigned int    sample_size[DCA2_XLL_SAMPLE_BUFFERS_MAX];
+    int             *sample_buffer[DCA2_XLL_SAMPLE_BUFFERS_MAX];
+} DCA2XllChSet;
+
+typedef struct DCA2XllDecoder {
+    AVCodecContext  *avctx;
+    GetBitContext   gb;
+
+    int     frame_size;             ///< Number of bytes in a lossless frame
+    int     nchsets;                ///< Number of channels sets per frame
+    int     nframesegs;             ///< Number of segments per frame
+    int     nsegsamples_log2;       ///< log2(nsegsamples)
+    int     nsegsamples;            ///< Samples in segment per one frequency band
+    int     nframesamples_log2;     ///< log2(nframesamples)
+    int     nframesamples;          ///< Samples in frame per one frequency band
+    int     seg_size_nbits;         ///< Number of bits used to read segment size
+    int     band_crc_present;       ///< Presence of CRC16 within each frequency band
+    int     scalable_lsbs;          ///< MSB/LSB split flag
+    int     ch_mask_nbits;          ///< Number of bits used to read channel mask
+    int     fixed_lsb_width;        ///< Fixed LSB width
+
+    DCA2XllChSet    chset[DCA2_XLL_CHSETS_MAX]; ///< Channel sets
+
+    int             *navi;          ///< NAVI table
+    unsigned int    navi_size;
+
+    int     nfreqbands;     ///< Highest number of frequency bands
+    int     nchannels;      ///< Total number of channels in a hierarchy
+    int     nactivechsets;  ///< Number of active channel sets to decode
+
+    int     hd_stream_id;   ///< Previous DTS-HD stream ID for detecting changes
+
+    uint8_t     *pbr_buffer;        ///< Peak bit rate (PBR) smoothing buffer
+    int         pbr_length;         ///< Length in bytes of data currently buffered
+    int         pbr_delay;          ///< Delay in frames before decoding buffered data
+
+    int     output_mask;
+    int     *output_samples[DCA2_SPEAKER_COUNT];
+} DCA2XllDecoder;
+
+int ff_dca2_xll_parse(DCA2XllDecoder *s, uint8_t *data, DCA2ExssAsset *asset);
+int ff_dca2_xll_filter(DCA2XllDecoder *s);
+av_cold void ff_dca2_xll_flush(DCA2XllDecoder *s);
+av_cold void ff_dca2_xll_close(DCA2XllDecoder *s);
+
+// ============================================================================
+
+typedef struct DCA2Context {
+    const AVClass   *class;       ///< class for AVOptions
+    AVCodecContext  *avctx;
+
+    DCA2CoreDecoder core;  ///< Core decoder context
+    DCA2ExssParser  exss;  ///< EXSS parser context
+    DCA2XllDecoder  xll;   ///< XLL decoder context
+
+    uint8_t         *buffer;
+    unsigned int    buffer_size;
+
+    int     packet; ///< Packet flags
+
+    int     has_residual_encoded;   ///< XLL residual encoded channels present
+    int     core_residual_valid;    ///< Core valid for residual decoding
+
+    int     request_channel_layout;
+    int     core_only;
+} DCA2Context;
+
+int ff_dca2_set_channel_layout(AVCodecContext *avctx, int *ch_remap, int dca_mask);
+
+int ff_dca2_check_crc(GetBitContext *s, int p1, int p2);
+
+void ff_dca2_downmix_to_stereo_fixed(int **samples, int *coeff_l, int nsamples, int ch_mask);
+void ff_dca2_downmix_to_stereo_float(AVFloatDSPContext *fdsp, float **samples,
+                                     int *coeff_l, int nsamples, int ch_mask);
+
+static inline int ff_dca2_seek_bits(GetBitContext *s, int p)
+{
+    if (p < s->index || p > s->size_in_bits)
+        return -1;
+    s->index = p;
+    return 0;
+}
+
+#endif
diff --git a/libavcodec/dca2_core.c b/libavcodec/dca2_core.c
new file mode 100644
index 0000000..4a90bf6
--- /dev/null
+++ b/libavcodec/dca2_core.c
@@ -0,0 +1,2565 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca.h"    // for avpriv_dca_sample_rates[]
+#include "dca2.h"
+#include "dca2_math.h"
+
+#define  DCA_SYNCWORD_REV1AUX   0x9A1105A0u
+
+enum HeaderType {
+    HEADER_CORE,
+    HEADER_XCH,
+    HEADER_XXCH
+};
+
+enum AudioMode {
+    AMODE_MONO,             // Mode 0: A (mono)
+    AMODE_MONO_DUAL,        // Mode 1: A + B (dual mono)
+    AMODE_STEREO,           // Mode 2: L + R (stereo)
+    AMODE_STEREO_SUMDIFF,   // Mode 3: (L+R) + (L-R) (sum-diff)
+    AMODE_STEREO_TOTAL,     // Mode 4: LT + RT (left and right total)
+    AMODE_3F,               // Mode 5: C + L + R
+    AMODE_2F1R,             // Mode 6: L + R + S
+    AMODE_3F1R,             // Mode 7: C + L + R + S
+    AMODE_2F2R,             // Mode 8: L + R + SL + SR
+    AMODE_3F2R,             // Mode 9: C + L + R + SL + SR
+
+    AMODE_COUNT
+};
+
+enum ExtAudioType {
+    EXT_AUDIO_XCH   = 0,
+    EXT_AUDIO_X96   = 2,
+    EXT_AUDIO_XXCH  = 6
+};
+
+enum LFEFlag {
+    LFE_FLAG_NONE,
+    LFE_FLAG_128,
+    LFE_FLAG_64,
+    LFE_FLAG_INVALID
+};
+
+static const int8_t prm_ch_to_spkr_map[AMODE_COUNT][5] = {
+    { DCA2_SPEAKER_C,             -1,              -1,              -1,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R,              -1,              -1,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R,              -1,              -1,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R,              -1,              -1,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R,              -1,              -1,              -1 },
+    { DCA2_SPEAKER_C, DCA2_SPEAKER_L, DCA2_SPEAKER_R ,              -1,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R, DCA2_SPEAKER_Cs,              -1,              -1 },
+    { DCA2_SPEAKER_C, DCA2_SPEAKER_L, DCA2_SPEAKER_R , DCA2_SPEAKER_Cs,              -1 },
+    { DCA2_SPEAKER_L, DCA2_SPEAKER_R, DCA2_SPEAKER_Ls, DCA2_SPEAKER_Rs,              -1 },
+    { DCA2_SPEAKER_C, DCA2_SPEAKER_L, DCA2_SPEAKER_R,  DCA2_SPEAKER_Ls, DCA2_SPEAKER_Rs }
+};
+
+static const uint8_t audio_mode_ch_mask[AMODE_COUNT] = {
+    DCA2_SPEAKER_LAYOUT_MONO,
+    DCA2_SPEAKER_LAYOUT_STEREO,
+    DCA2_SPEAKER_LAYOUT_STEREO,
+    DCA2_SPEAKER_LAYOUT_STEREO,
+    DCA2_SPEAKER_LAYOUT_STEREO,
+    DCA2_SPEAKER_LAYOUT_3_0,
+    DCA2_SPEAKER_LAYOUT_2_1,
+    DCA2_SPEAKER_LAYOUT_3_1,
+    DCA2_SPEAKER_LAYOUT_2_2,
+    DCA2_SPEAKER_LAYOUT_5POINT0
+};
+
+// ============================================================================
+
+#include "dcahuff.h"
+
+static const uint8_t quant_index_group_size[DCA2_CODE_BOOKS] = {
+    1, 3, 3, 3, 3, 7, 7, 7, 7, 7
+};
+
+typedef struct DCA2VLC {
+    int offset;         ///< Code values offset
+    int max_depth;      ///< Parameter for get_vlc2()
+    VLC vlc[7];         ///< Actual codes
+} DCA2VLC;
+
+static DCA2VLC  vlc_bit_allocation;
+static DCA2VLC  vlc_transition_mode;
+static DCA2VLC  vlc_scale_factor;
+static DCA2VLC  vlc_quant_index[DCA2_CODE_BOOKS];
+
+static av_cold void dca2_init_vlcs(void)
+{
+    static VLC_TYPE dca_table[23622][2];
+    static int vlcs_initialized = 0;
+    int i, j, k;
+
+    if (vlcs_initialized)
+        return;
+
+#define DCA2_INIT_VLC(vlc, a, b, c, d)                                     \
+    do {                                                                   \
+        vlc.table           = &dca_table[ff_dca_vlc_offs[k]];              \
+        vlc.table_allocated = ff_dca_vlc_offs[k + 1] - ff_dca_vlc_offs[k]; \
+        init_vlc(&vlc, a, b, c, 1, 1, d, 2, 2, INIT_VLC_USE_NEW_STATIC);   \
+    } while (0)
+
+    vlc_bit_allocation.offset    = 1;
+    vlc_bit_allocation.max_depth = 2;
+    for (i = 0, k = 0; i < 5; i++, k++)
+        DCA2_INIT_VLC(vlc_bit_allocation.vlc[i], bitalloc_12_vlc_bits[i], 12,
+                      bitalloc_12_bits[i], bitalloc_12_codes[i]);
+
+    vlc_scale_factor.offset    = -64;
+    vlc_scale_factor.max_depth = 2;
+    for (i = 0; i < 5; i++, k++)
+        DCA2_INIT_VLC(vlc_scale_factor.vlc[i], SCALES_VLC_BITS, 129,
+                      scales_bits[i], scales_codes[i]);
+
+    vlc_transition_mode.offset    = 0;
+    vlc_transition_mode.max_depth = 1;
+    for (i = 0; i < 4; i++, k++)
+        DCA2_INIT_VLC(vlc_transition_mode.vlc[i], tmode_vlc_bits[i], 4,
+                      tmode_bits[i], tmode_codes[i]);
+
+    for (i = 0; i < DCA2_CODE_BOOKS; i++) {
+        vlc_quant_index[i].offset    = bitalloc_offsets[i];
+        vlc_quant_index[i].max_depth = 1 + (i > 5);
+        for (j = 0; j < quant_index_group_size[i]; j++, k++)
+            DCA2_INIT_VLC(vlc_quant_index[i].vlc[j], bitalloc_maxbits[i][j],
+                          bitalloc_sizes[i], bitalloc_bits[i][j], bitalloc_codes[i][j]);
+    }
+
+    vlcs_initialized = 1;
+}
+
+static int get_vlc(GetBitContext *s, DCA2VLC *v, int i)
+{
+    return get_vlc2(s, v->vlc[i].table, v->vlc[i].bits, v->max_depth) + v->offset;
+}
+
+static void get_array(GetBitContext *s, int *array, int size, int n)
+{
+    int i;
+
+    for (i = 0; i < size; i++)
+        array[i] = get_sbits(s, n);
+}
+
+// ============================================================================
+
+// 5.3.1 - Bit stream header
+static int parse_frame_header(DCA2CoreDecoder *s)
+{
+    int normal_frame, pcmr_index;
+
+    // Frame type
+    normal_frame = get_bits1(&s->gb);
+
+    // Deficit sample count
+    if (get_bits(&s->gb, 5) != DCA2_PCMBLOCK_SAMPLES - 1) {
+        av_log(s->avctx, AV_LOG_ERROR, "Deficit samples are not supported\n");
+        return normal_frame ? AVERROR_INVALIDDATA : AVERROR_PATCHWELCOME;
+    }
+
+    // CRC present flag
+    s->crc_present = get_bits1(&s->gb);
+
+    // Number of PCM sample blocks
+    s->npcmblocks = get_bits(&s->gb, 7) + 1;
+    if (s->npcmblocks & (DCA2_SUBBAND_SAMPLES - 1)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unsupported number of PCM sample blocks (%d)\n", s->npcmblocks);
+        return (s->npcmblocks < 6 || normal_frame) ? AVERROR_INVALIDDATA : AVERROR_PATCHWELCOME;
+    }
+
+    // Primary frame byte size
+    s->frame_size = get_bits(&s->gb, 14) + 1;
+    if (s->frame_size < 96) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid core frame size (%d bytes)\n", s->frame_size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Audio channel arrangement
+    s->audio_mode = get_bits(&s->gb, 6);
+    if (s->audio_mode >= AMODE_COUNT) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unsupported audio channel arrangement (%d)\n", s->audio_mode);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Core audio sampling frequency
+    s->sample_rate = avpriv_dca_sample_rates[get_bits(&s->gb, 4)];
+    if (!s->sample_rate) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid core audio sampling frequency\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Transmission bit rate
+    s->bit_rate = ff_dca_bit_rates[get_bits(&s->gb, 5)];
+
+    // Reserved field
+    skip_bits1(&s->gb);
+
+    // Embedded dynamic range flag
+    s->drc_present = get_bits1(&s->gb);
+
+    // Embedded time stamp flag
+    s->ts_present = get_bits1(&s->gb);
+
+    // Auxiliary data flag
+    s->aux_present = get_bits1(&s->gb);
+
+    // HDCD mastering flag
+    skip_bits1(&s->gb);
+
+    // Extension audio descriptor flag
+    s->ext_audio_type = get_bits(&s->gb, 3);
+
+    // Extended coding flag
+    s->ext_audio_present = get_bits1(&s->gb);
+
+    // Audio sync word insertion flag
+    s->sync_ssf = get_bits1(&s->gb);
+
+    // Low frequency effects flag
+    s->lfe_present = get_bits(&s->gb, 2);
+    if (s->lfe_present == LFE_FLAG_INVALID) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid low frequency effects flag\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Predictor history flag switch
+    s->predictor_history = get_bits1(&s->gb);
+
+    // Header CRC check bytes
+    if (s->crc_present)
+        skip_bits(&s->gb, 16);
+
+    // Multirate interpolator switch
+    s->filter_perfect = get_bits1(&s->gb);
+
+    // Encoder software revision
+    skip_bits(&s->gb, 4);
+
+    // Copy history
+    skip_bits(&s->gb, 2);
+
+    // Source PCM resolution
+    s->source_pcm_res = ff_dca_bits_per_sample[pcmr_index = get_bits(&s->gb, 3)];
+    if (!s->source_pcm_res) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid source PCM resolution\n");
+        return AVERROR_INVALIDDATA;
+    }
+    s->es_format = pcmr_index & 1;
+
+    // Front sum/difference flag
+    s->sumdiff_front = get_bits1(&s->gb);
+
+    // Surround sum/difference flag
+    s->sumdiff_surround = get_bits1(&s->gb);
+
+    // Dialog normalization / unspecified
+    skip_bits(&s->gb, 4);
+
+    return 0;
+}
+
+// 5.3.2 - Primary audio coding header
+static int parse_coding_header(DCA2CoreDecoder *s, enum HeaderType header, int xch_base)
+{
+    int n, ch, nchannels, header_size = 0, header_pos = get_bits_count(&s->gb);
+    unsigned int mask, index;
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    switch (header) {
+    case HEADER_CORE:
+        // Number of subframes
+        s->nsubframes = get_bits(&s->gb, 4) + 1;
+
+        // Number of primary audio channels
+        s->nchannels = get_bits(&s->gb, 3) + 1;
+        if (s->nchannels != ff_dca_channels[s->audio_mode]) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid number of primary audio channels (%d) for audio channel arrangement (%d)\n", s->nchannels, s->audio_mode);
+            return AVERROR_INVALIDDATA;
+        }
+        av_assert0(s->nchannels <= DCA2_CHANNELS - 2);
+
+        s->ch_mask = audio_mode_ch_mask[s->audio_mode];
+
+        // Add LFE channel if present
+        if (s->lfe_present)
+            s->ch_mask |= DCA2_SPEAKER_MASK_LFE1;
+        break;
+
+    case HEADER_XCH:
+        s->nchannels = ff_dca_channels[s->audio_mode] + 1;
+        av_assert0(s->nchannels <= DCA2_CHANNELS - 1);
+        s->ch_mask |= DCA2_SPEAKER_MASK_Cs;
+        break;
+
+    case HEADER_XXCH:
+        // Channel set header length
+        header_size = get_bits(&s->gb, 7) + 1;
+
+        // Check CRC
+        if (s->xxch_crc_present && ff_dca2_check_crc(&s->gb, header_pos, header_pos + header_size * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH channel set header checksum\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Number of channels in a channel set
+        nchannels = get_bits(&s->gb, 3) + 1;
+        if (nchannels > DCA2_XXCH_CHANNELS_MAX) {
+            av_log(s->avctx, AV_LOG_WARNING, "Unsupported number of XXCH channels (%d)\n", nchannels);
+            return AVERROR_PATCHWELCOME;
+        }
+        s->nchannels = ff_dca_channels[s->audio_mode] + nchannels;
+        av_assert0(s->nchannels <= DCA2_CHANNELS);
+
+        // Loudspeaker layout mask
+        mask = get_bits_long(&s->gb, s->xxch_mask_nbits - DCA2_SPEAKER_Cs);
+        s->xxch_spkr_mask = mask << DCA2_SPEAKER_Cs;
+
+        if (av_popcount(s->xxch_spkr_mask) != nchannels) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH speaker layout mask (%#x)\n", s->xxch_spkr_mask);
+            return AVERROR_INVALIDDATA;
+        }
+
+        if (s->xxch_core_mask & s->xxch_spkr_mask) {
+            av_log(s->avctx, AV_LOG_ERROR, "XXCH speaker layout mask (%#x) overlaps with core (%#x)\n", s->xxch_spkr_mask, s->xxch_core_mask);
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Combine core and XXCH masks together
+        s->ch_mask = s->xxch_core_mask | s->xxch_spkr_mask;
+
+        // Downmix coefficients present in stream
+        if (get_bits1(&s->gb)) {
+            int *coeff_ptr;
+
+            // Downmix already performed by encoder
+            s->xxch_dmix_embedded = get_bits1(&s->gb);
+
+            // Downmix scale factor
+            index = get_bits(&s->gb, 6) * 4 - 44;
+            if (index >= FF_DCA_INV_DMIXTABLE_SIZE) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH downmix scale index (%d)\n", index);
+                return AVERROR_INVALIDDATA;
+            }
+            s->xxch_dmix_scale_inv = ff_dca_inv_dmixtable[index];
+
+            // Downmix channel mapping mask
+            for (ch = 0; ch < nchannels; ch++) {
+                mask = get_bits_long(&s->gb, s->xxch_mask_nbits);
+                if ((mask & s->xxch_core_mask) != mask) {
+                    av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH downmix channel mapping mask (%#x)\n", mask);
+                    return AVERROR_INVALIDDATA;
+                }
+                s->xxch_dmix_mask[ch] = mask;
+            }
+
+            // Downmix coefficients
+            coeff_ptr = s->xxch_dmix_coeff;
+            for (ch = 0; ch < nchannels; ch++) {
+                for (n = 0; n < s->xxch_mask_nbits; n++) {
+                    if (s->xxch_dmix_mask[ch] & (1U << n)) {
+                        int code = get_bits(&s->gb, 7);
+                        int sign = (code >> 6) - 1;
+                        if (code &= 63) {
+                            index = code * 4 - 3;
+                            if (index >= FF_DCA_DMIXTABLE_SIZE) {
+                                av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH downmix coefficient index (%d)\n", index);
+                                return AVERROR_INVALIDDATA;
+                            }
+                            *coeff_ptr++ = (ff_dca_dmixtable[index] ^ sign) - sign;
+                        } else {
+                            *coeff_ptr = 0;
+                        }
+                    }
+                }
+            }
+        } else {
+            s->xxch_dmix_embedded = 0;
+        }
+
+        break;
+    }
+
+    // Subband activity count
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        s->nsubbands[ch] = get_bits(&s->gb, 5) + 2;
+        if (s->nsubbands[ch] > DCA2_SUBBANDS) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid subband activity count\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // High frequency VQ start subband
+    for (ch = xch_base; ch < s->nchannels; ch++)
+        s->subband_vq_start[ch] = get_bits(&s->gb, 5) + 1;
+
+    // Joint intensity coding index
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        if ((n = get_bits(&s->gb, 3)) && header == HEADER_XXCH)
+            n += xch_base - 1;
+        if (n > s->nchannels) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid joint intensity coding index\n");
+            return AVERROR_INVALIDDATA;
+        }
+        s->joint_intensity_index[ch] = n;
+    }
+
+    // Transient mode code book
+    for (ch = xch_base; ch < s->nchannels; ch++)
+        s->transition_mode_sel[ch] = get_bits(&s->gb, 2);
+
+    // Scale factor code book
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        s->scale_factor_sel[ch] = get_bits(&s->gb, 3);
+        if (s->scale_factor_sel[ch] == 7) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid scale factor code book\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // Bit allocation quantizer select
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        s->bit_allocation_sel[ch] = get_bits(&s->gb, 3);
+        if (s->bit_allocation_sel[ch] == 7) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid bit allocation quantizer select\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // Quantization index codebook select
+    for (n = 0; n < DCA2_CODE_BOOKS; n++)
+        for (ch = xch_base; ch < s->nchannels; ch++)
+            s->quant_index_sel[ch][n] = get_bits(&s->gb, ff_dca2_quant_index_sel_nbits[n]);
+
+    // Scale factor adjustment index
+    for (n = 0; n < DCA2_CODE_BOOKS; n++)
+        for (ch = xch_base; ch < s->nchannels; ch++)
+            if (s->quant_index_sel[ch][n] < quant_index_group_size[n])
+                s->scale_factor_adj[ch][n] = ff_dca2_scale_factor_adj[get_bits(&s->gb, 2)];
+
+    if (header == HEADER_XXCH) {
+        // Reserved
+        // Byte align
+        // CRC16 of channel set header
+        if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Read past end of XXCH channel set header\n");
+            return AVERROR_INVALIDDATA;
+        }
+    } else {
+        // Audio header CRC check word
+        if (s->crc_present)
+            skip_bits(&s->gb, 16);
+    }
+
+    return 0;
+}
+
+static inline int parse_scale(DCA2CoreDecoder *s, int *scale_index, int sel)
+{
+    const uint32_t *scale_table;
+    unsigned int scale_size;
+
+    // Select the root square table
+    if (sel > 5) {
+        scale_table = ff_dca_scale_factor_quant7;
+        scale_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant7);
+    } else {
+        scale_table = ff_dca_scale_factor_quant6;
+        scale_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant6);
+    }
+
+    // If Huffman code was used, the difference of scales was encoded
+    if (sel < 5)
+        *scale_index += get_vlc(&s->gb, &vlc_scale_factor, sel);
+    else
+        *scale_index = get_bits(&s->gb, sel + 1);
+
+    // Look up scale factor from the root square table
+    if ((unsigned int)*scale_index >= scale_size) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid scale factor index\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return scale_table[*scale_index];
+}
+
+static inline int parse_joint_scale(DCA2CoreDecoder *s, int sel)
+{
+    int scale_index;
+
+    if (sel < 5)
+        scale_index = get_vlc(&s->gb, &vlc_scale_factor, sel);
+    else
+        scale_index = get_bits(&s->gb, sel + 1);
+
+    // Bias by 64
+    scale_index += 64;
+
+    // Look up joint scale factor
+    if ((unsigned int)scale_index >= FF_ARRAY_ELEMS(ff_dca2_joint_scale_factors)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid joint scale factor index\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return ff_dca2_joint_scale_factors[scale_index];
+}
+
+// 5.4.1 - Primary audio coding side information
+static int parse_subframe_header(DCA2CoreDecoder *s, int sf,
+                                 enum HeaderType header, int xch_base)
+{
+    int ch, band, ret;
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    if (header == HEADER_CORE) {
+        // Subsubframe count
+        s->nsubsubframes[sf] = get_bits(&s->gb, 2) + 1;
+
+        // Partial subsubframe sample count
+        skip_bits(&s->gb, 3);
+    }
+
+    // Prediction mode
+    for (ch = xch_base; ch < s->nchannels; ch++)
+        for (band = 0; band < s->nsubbands[ch]; band++)
+            s->prediction_mode[ch][band] = get_bits1(&s->gb);
+
+    // Prediction coefficients VQ address
+    for (ch = xch_base; ch < s->nchannels; ch++)
+        for (band = 0; band < s->nsubbands[ch]; band++)
+            if (s->prediction_mode[ch][band])
+                s->prediction_vq_index[ch][band] = get_bits(&s->gb, 12);
+
+    // Bit allocation index
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Select codebook
+        int sel = s->bit_allocation_sel[ch];
+        // Not high frequency VQ subbands
+        for (band = 0; band < s->subband_vq_start[ch]; band++) {
+            int abits;
+
+            if (sel < 5)
+                abits = get_vlc(&s->gb, &vlc_bit_allocation, sel);
+            else
+                abits = get_bits(&s->gb, sel - 1);
+
+            if (abits >= 27) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid bit allocation index\n");
+                return AVERROR_INVALIDDATA;
+            }
+
+            s->bit_allocation[ch][band] = abits;
+        }
+    }
+
+    // Transition mode
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Clear transition mode for all subbands
+        memset(s->transition_mode[sf][ch], 0, sizeof(s->transition_mode[0][0]));
+
+        // Transient possible only if more than one subsubframe
+        if (s->nsubsubframes[sf] > 1) {
+            // Select codebook
+            int sel = s->transition_mode_sel[ch];
+            // Not high frequency VQ subbands
+            for (band = 0; band < s->subband_vq_start[ch]; band++) {
+                // Present only if bits allocated
+                if (s->bit_allocation[ch][band]) {
+                    int trans_ssf = get_vlc(&s->gb, &vlc_transition_mode, sel);
+                    if (trans_ssf >= 4) {
+                        av_log(s->avctx, AV_LOG_ERROR, "Invalid transition mode index\n");
+                        return AVERROR_INVALIDDATA;
+                    }
+                    s->transition_mode[sf][ch][band] = trans_ssf;
+                }
+            }
+        }
+    }
+
+    // Scale factors
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Select codebook
+        int sel = s->scale_factor_sel[ch];
+
+        // Clear accumulation
+        int scale_index = 0;
+
+        // Extract scales for subbands up to VQ
+        for (band = 0; band < s->subband_vq_start[ch]; band++) {
+            if (s->bit_allocation[ch][band]) {
+                if ((ret = parse_scale(s, &scale_index, sel)) < 0)
+                    return ret;
+                s->scale_factors[ch][band][0] = ret;
+                if (s->transition_mode[sf][ch][band]) {
+                    if ((ret = parse_scale(s, &scale_index, sel)) < 0)
+                        return ret;
+                    s->scale_factors[ch][band][1] = ret;
+                }
+            } else {
+                s->scale_factors[ch][band][0] = 0;
+            }
+        }
+
+        // High frequency VQ subbands
+        for (band = s->subband_vq_start[ch]; band < s->nsubbands[ch]; band++) {
+            if ((ret = parse_scale(s, &scale_index, sel)) < 0)
+                return ret;
+            s->scale_factors[ch][band][0] = ret;
+        }
+    }
+
+    // Joint subband codebook select
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            s->joint_scale_sel[ch] = get_bits(&s->gb, 3);
+            if (s->joint_scale_sel[ch] == 7) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid joint scale factor code book\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    // Scale factors for joint subband coding
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            // Select codebook
+            int sel = s->joint_scale_sel[ch];
+            // Get source channel
+            int src_ch = s->joint_intensity_index[ch] - 1;
+            for (band = s->nsubbands[ch]; band < s->nsubbands[src_ch]; band++) {
+                if ((ret = parse_joint_scale(s, sel)) < 0)
+                    return ret;
+                s->joint_scale_factors[ch][band] = ret;
+            }
+        }
+    }
+
+    // Dynamic range coefficient
+    if (s->drc_present && header == HEADER_CORE)
+        skip_bits(&s->gb, 8);
+
+    // Side information CRC check word
+    if (s->crc_present)
+        skip_bits(&s->gb, 16);
+
+    return 0;
+}
+
+// Extract block code indices from the bit stream
+static inline int parse_block_codes(DCA2CoreDecoder *s, int *audio, int abits)
+{
+    int code1 = get_bits(&s->gb, ff_dca2_block_code_nbits[abits - 1]);
+    int code2 = get_bits(&s->gb, ff_dca2_block_code_nbits[abits - 1]);
+    int levels = ff_dca2_quant_levels[abits];
+    int offset = (levels - 1) / 2;
+    int n, div;
+
+    // Look up samples from the block code book
+    for (n = 0; n < DCA2_SUBBAND_SAMPLES / 2; n++) {
+        div = FASTDIV(code1, levels);
+        audio[n] = code1 - div * levels - offset;
+        code1 = div;
+    }
+    for (; n < DCA2_SUBBAND_SAMPLES; n++) {
+        div = FASTDIV(code2, levels);
+        audio[n] = code2 - div * levels - offset;
+        code2 = div;
+    }
+
+    if (code1 || code2) {
+        av_log(s->avctx, AV_LOG_ERROR, "Failed to decode block code(s)\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+// Extract Huffman codes from the bit stream
+static inline int parse_huffman_codes(DCA2CoreDecoder *s, int *audio, int abits, int sel)
+{
+    int i;
+
+    for (i = 0; i < DCA2_SUBBAND_SAMPLES; i++)
+        audio[i] = get_vlc(&s->gb, &vlc_quant_index[abits - 1], sel);
+
+    return 1;
+}
+
+static inline int extract_audio(DCA2CoreDecoder *s, int *audio, int abits, int ch)
+{
+    av_assert0(abits >= 0 && abits < 27);
+
+    if (abits == 0) {
+        // No bits allocated
+        memset(audio, 0, DCA2_SUBBAND_SAMPLES * sizeof(*audio));
+        return 0;
+    }
+
+    if (abits <= DCA2_CODE_BOOKS) {
+        int sel = s->quant_index_sel[ch][abits - 1];
+        if (sel < quant_index_group_size[abits - 1]) {
+            // Huffman codes
+            return parse_huffman_codes(s, audio, abits, sel);
+        }
+        if (abits <= 7) {
+            // Block codes
+            return parse_block_codes(s, audio, abits);
+        }
+    }
+
+    // No further encoding
+    get_array(&s->gb, audio, DCA2_SUBBAND_SAMPLES, abits - 3);
+    return 0;
+}
+
+static inline void dequantize(int *output, const int *input, int step_size,
+                              int scale, int residual)
+{
+    // Account for quantizer step size
+    int64_t step_scale = (int64_t)step_size * scale;
+    int n, shift = 0;
+
+    // Limit scale factor resolution to 22 bits
+    if (step_scale > (1 << 23)) {
+        shift = av_log2(step_scale >> 23) + 1;
+        step_scale >>= shift;
+    }
+
+    // Scale the samples
+    if (residual) {
+        for (n = 0; n < DCA2_SUBBAND_SAMPLES; n++)
+            output[n] += clip23(norm__(input[n] * step_scale, 22 - shift));
+    } else {
+        for (n = 0; n < DCA2_SUBBAND_SAMPLES; n++)
+            output[n]  = clip23(norm__(input[n] * step_scale, 22 - shift));
+    }
+}
+
+// 5.5 - Primary audio data arrays
+static int parse_subframe_audio(DCA2CoreDecoder *s, int sf, enum HeaderType header,
+                                int xch_base, int *sub_pos, int *lfe_pos)
+{
+    int audio[16], *samples;
+    int m, n, ssf, ofs, ch, band, scale;
+
+    // Number of subband samples in this subframe
+    int nsamples = s->nsubsubframes[sf] * DCA2_SUBBAND_SAMPLES;
+    if (*sub_pos + nsamples > s->npcmblocks) {
+        av_log(s->avctx, AV_LOG_ERROR, "Subband sample buffer overflow\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    // VQ encoded subbands
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        for (band = s->subband_vq_start[ch]; band < s->nsubbands[ch]; band++) {
+            // Extract the VQ address from the bit stream
+            int vq_index = get_bits(&s->gb, 10);
+
+            // Look up the VQ code book for 32 subband samples
+            const int8_t *vq_samples = ff_dca_high_freq_vq[vq_index];
+
+            // Get the scale factor
+            scale = s->scale_factors[ch][band][0];
+
+            // Scale and take the samples
+            samples = s->subband_samples[ch][band] + *sub_pos;
+            for (n = 0; n < nsamples; n++)
+                samples[n] = clip23(mul4(scale, vq_samples[n]));
+        }
+    }
+
+    // Low frequency effect data
+    if (s->lfe_present && header == HEADER_CORE) {
+        unsigned int index;
+
+        // Number of LFE samples in this subframe
+        int nlfesamples = 2 * s->lfe_present * s->nsubsubframes[sf];
+
+        // Extract LFE samples from the bit stream
+        get_array(&s->gb, audio, nlfesamples, 8);
+
+        // Extract scale factor index from the bit stream
+        index = get_bits(&s->gb, 8);
+        if (index >= FF_ARRAY_ELEMS(ff_dca_scale_factor_quant7)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid LFE scale factor index\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Look up the 7-bit root square quantization table
+        scale = ff_dca_scale_factor_quant7[index];
+
+        // Account for quantizer step size which is 0.035
+        scale = mul23(4697620 /* 0.035 * (1 << 27) */, scale);
+
+        // Scale the LFE samples
+        for (n = 0; n < nlfesamples; n++)
+            s->lfe_samples[*lfe_pos + n] = clip23((audio[n] * scale) >> 4);
+
+        // Advance LFE sample pointer for the next subframe
+        *lfe_pos += nlfesamples;
+    }
+
+    // Audio data
+    for (ssf = 0, ofs = *sub_pos; ssf < s->nsubsubframes[sf]; ssf++) {
+        for (ch = xch_base; ch < s->nchannels; ch++) {
+            if (get_bits_left(&s->gb) < 0)
+                return AVERROR_INVALIDDATA;
+
+            // Not high frequency VQ subbands
+            for (band = 0; band < s->subband_vq_start[ch]; band++) {
+                int abits = s->bit_allocation[ch][band];
+                int ret, step_size, trans_ssf;
+
+                // Extract bits from the bit stream
+                if ((ret = extract_audio(s, audio, abits, ch)) < 0)
+                    return ret;
+
+                // Select quantization step size table
+                // Look up quantization step size
+                if (s->bit_rate == 3)
+                    step_size = ff_dca_lossless_quant[abits];
+                else
+                    step_size = ff_dca_lossy_quant[abits];
+
+                // Identify transient location
+                trans_ssf = s->transition_mode[sf][ch][band];
+
+                // Determine proper scale factor
+                if (trans_ssf == 0 || ssf < trans_ssf)
+                    scale = s->scale_factors[ch][band][0];
+                else
+                    scale = s->scale_factors[ch][band][1];
+
+                // Adjustment of scale factor
+                // Only when SEL indicates Huffman code
+                if (ret > 0) {
+                    int64_t adj = s->scale_factor_adj[ch][abits - 1];
+                    scale = clip23((adj * scale) >> 22);
+                }
+
+                dequantize(s->subband_samples[ch][band] + ofs,
+                           audio, step_size, scale, 0);
+            }
+        }
+
+        // DSYNC
+        if ((ssf == s->nsubsubframes[sf] - 1 || s->sync_ssf) && get_bits(&s->gb, 16) != 0xffff) {
+            av_log(s->avctx, AV_LOG_ERROR, "DSYNC check failed\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ofs += DCA2_SUBBAND_SAMPLES;
+    }
+
+    // Inverse ADPCM
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        for (band = 0; band < s->nsubbands[ch]; band++) {
+            // Only if prediction mode is on
+            if (s->prediction_mode[ch][band]) {
+                // Extract the VQ index
+                int vq_index = s->prediction_vq_index[ch][band];
+
+                // Look up the VQ table for prediction coefficients
+                const int16_t *vq_coeffs = ff_dca_adpcm_vb[vq_index];
+
+                samples = s->subband_samples[ch][band] + *sub_pos;
+                for (m = 0; m < nsamples; m++) {
+                    int64_t err = INT64_C(0);
+                    for (n = 0; n < DCA2_ADPCM_COEFFS; n++)
+                        err += (int64_t)samples[m - n - 1] * vq_coeffs[n];
+                    samples[m] = clip23(samples[m] + clip23(norm13(err)));
+                }
+            }
+        }
+    }
+
+    // Joint subband coding
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            // Get source channel
+            int src_ch = s->joint_intensity_index[ch] - 1;
+            for (band = s->nsubbands[ch]; band < s->nsubbands[src_ch]; band++) {
+                int *src = s->subband_samples[src_ch][band] + *sub_pos;
+                int *dst = s->subband_samples[    ch][band] + *sub_pos;
+                int scale = s->joint_scale_factors[ch][band];
+                for (n = 0; n < nsamples; n++)
+                    dst[n] = clip23(mul17(src[n], scale));
+            }
+        }
+    }
+
+    // Advance subband sample pointer for the next subframe
+    *sub_pos += nsamples;
+    return 0;
+}
+
+static void erase_adpcm_history(DCA2CoreDecoder *s)
+{
+    int ch, band;
+
+    // Erase ADPCM history from previous frame if
+    // predictor history switch was disabled
+    for (ch = 0; ch < DCA2_CHANNELS; ch++)
+        for (band = 0; band < DCA2_SUBBANDS; band++)
+            AV_ZERO128(s->subband_samples[ch][band] - DCA2_ADPCM_COEFFS);
+}
+
+static int alloc_sample_buffer(DCA2CoreDecoder *s)
+{
+    int nchsamples = DCA2_ADPCM_COEFFS + s->npcmblocks;
+    int nframesamples = nchsamples * DCA2_CHANNELS * DCA2_SUBBANDS;
+    int nlfesamples = DCA2_LFE_HISTORY + s->npcmblocks / 2;
+    unsigned int size = s->subband_size;
+    int ch, band;
+
+    // Reallocate subband sample buffer
+    av_fast_mallocz(&s->subband_buffer, &s->subband_size,
+                    (nframesamples + nlfesamples) * sizeof(int));
+    if (!s->subband_buffer)
+        return AVERROR(ENOMEM);
+
+    if (size != s->subband_size) {
+        for (ch = 0; ch < DCA2_CHANNELS; ch++)
+            for (band = 0; band < DCA2_SUBBANDS; band++)
+                s->subband_samples[ch][band] = s->subband_buffer +
+                    (ch * DCA2_SUBBANDS + band) * nchsamples + DCA2_ADPCM_COEFFS;
+        s->lfe_samples = s->subband_buffer + nframesamples;
+    }
+
+    if (!s->predictor_history)
+        erase_adpcm_history(s);
+
+    return 0;
+}
+
+static int parse_frame_data(DCA2CoreDecoder *s, enum HeaderType header, int xch_base)
+{
+    int sf, ch, ret, band, sub_pos, lfe_pos;
+
+    if ((ret = parse_coding_header(s, header, xch_base)) < 0)
+        return ret;
+
+    for (sf = 0, sub_pos = 0, lfe_pos = DCA2_LFE_HISTORY; sf < s->nsubframes; sf++) {
+        if ((ret = parse_subframe_header(s, sf, header, xch_base)) < 0)
+            return ret;
+        if ((ret = parse_subframe_audio(s, sf, header, xch_base, &sub_pos, &lfe_pos)) < 0)
+            return ret;
+    }
+
+    for (ch = xch_base; ch < s->nchannels; ch++) {
+        // Number of active subbands for this channel
+        int nsubbands = s->nsubbands[ch];
+        if (s->joint_intensity_index[ch])
+            nsubbands = FFMAX(nsubbands, s->nsubbands[s->joint_intensity_index[ch] - 1]);
+
+        // Update history for ADPCM
+        for (band = 0; band < nsubbands; band++) {
+            int *samples = s->subband_samples[ch][band] - DCA2_ADPCM_COEFFS;
+            AV_COPY128(samples, samples + s->npcmblocks);
+        }
+
+        // Clear inactive subbands
+        for (; band < DCA2_SUBBANDS; band++) {
+            int *samples = s->subband_samples[ch][band] - DCA2_ADPCM_COEFFS;
+            memset(samples, 0, (DCA2_ADPCM_COEFFS + s->npcmblocks) * sizeof(int));
+        }
+    }
+
+    return 0;
+}
+
+static int parse_xch_frame(DCA2CoreDecoder *s)
+{
+    int ret;
+
+    if (s->ch_mask & DCA2_SPEAKER_MASK_Cs) {
+        av_log(s->avctx, AV_LOG_ERROR, "XCH with Cs speaker already present\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if ((ret = parse_frame_data(s, HEADER_XCH, s->nchannels)) < 0)
+        return ret;
+
+    // Seek to the end of core frame, don't trust XCH frame size
+    if (ff_dca2_seek_bits(&s->gb, s->frame_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XCH frame\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int parse_xxch_frame(DCA2CoreDecoder *s)
+{
+    int xxch_nchsets, xxch_frame_size;
+    int ret, mask, header_size, header_pos = get_bits_count(&s->gb);
+
+    // XXCH sync word
+    if (get_bits_long(&s->gb, 32) != DCA_SYNCWORD_XXCH) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH sync word\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // XXCH frame header length
+    header_size = get_bits(&s->gb, 6) + 1;
+
+    // Check XXCH frame header CRC
+    if (ff_dca2_check_crc(&s->gb, header_pos + 32, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XXCH frame header checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // CRC presence flag for channel set header
+    s->xxch_crc_present = get_bits1(&s->gb);
+
+    // Number of bits for loudspeaker mask
+    s->xxch_mask_nbits = get_bits(&s->gb, 5) + 1;
+    if (s->xxch_mask_nbits <= DCA2_SPEAKER_Cs) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid number of bits for XXCH speaker mask (%d)\n", s->xxch_mask_nbits);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Number of channel sets
+    xxch_nchsets = get_bits(&s->gb, 2) + 1;
+    if (xxch_nchsets > 1) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported number of XXCH channel sets (%d)\n", xxch_nchsets);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Channel set 0 data byte size
+    xxch_frame_size = get_bits(&s->gb, 14) + 1;
+
+    // Core loudspeaker activity mask
+    s->xxch_core_mask = get_bits_long(&s->gb, s->xxch_mask_nbits);
+
+    // Validate the core mask
+    mask = s->ch_mask;
+
+    if ((mask & DCA2_SPEAKER_MASK_Ls) && (s->xxch_core_mask & DCA2_SPEAKER_MASK_Lss))
+        mask = (mask & ~DCA2_SPEAKER_MASK_Ls) | DCA2_SPEAKER_MASK_Lss;
+
+    if ((mask & DCA2_SPEAKER_MASK_Rs) && (s->xxch_core_mask & DCA2_SPEAKER_MASK_Rss))
+        mask = (mask & ~DCA2_SPEAKER_MASK_Rs) | DCA2_SPEAKER_MASK_Rss;
+
+    if (mask != s->xxch_core_mask) {
+        av_log(s->avctx, AV_LOG_ERROR, "XXCH core speaker activity mask (%#x) disagrees with core (%#x)\n", s->xxch_core_mask, mask);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Reserved
+    // Byte align
+    // CRC16 of XXCH frame header
+    if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XXCH frame header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Parse XXCH channel set 0
+    if ((ret = parse_frame_data(s, HEADER_XXCH, s->nchannels)) < 0)
+        return ret;
+
+    if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8 + xxch_frame_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XXCH channel set\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int parse_xbr_subframe(DCA2CoreDecoder *s, int xbr_base_ch, int xbr_nchannels,
+                              int *xbr_nsubbands, int xbr_transition_mode, int sf, int *sub_pos)
+{
+    int     xbr_nabits[DCA2_CHANNELS];
+    int     xbr_bit_allocation[DCA2_CHANNELS][DCA2_SUBBANDS];
+    int     xbr_scale_nbits[DCA2_CHANNELS];
+    int     xbr_scale_factors[DCA2_CHANNELS][DCA2_SUBBANDS][2];
+    int     ssf, ch, band, ofs;
+
+    // Number of subband samples in this subframe
+    int nsamples = s->nsubsubframes[sf] * DCA2_SUBBAND_SAMPLES;
+    if (*sub_pos + nsamples > s->npcmblocks) {
+        av_log(s->avctx, AV_LOG_ERROR, "Subband sample buffer overflow\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    // Number of bits for XBR bit allocation index
+    for (ch = xbr_base_ch; ch < xbr_nchannels; ch++)
+        xbr_nabits[ch] = get_bits(&s->gb, 2) + 2;
+
+    // XBR bit allocation index
+    for (ch = xbr_base_ch; ch < xbr_nchannels; ch++)
+        for (band = 0; band < xbr_nsubbands[ch]; band++)
+            xbr_bit_allocation[ch][band] = get_bits(&s->gb, xbr_nabits[ch]);
+
+    // Number of bits for scale indices
+    for (ch = xbr_base_ch; ch < xbr_nchannels; ch++) {
+        xbr_scale_nbits[ch] = get_bits(&s->gb, 3);
+        if (!xbr_scale_nbits[ch]) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid number of bits for XBR scale factor index\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // XBR scale factors
+    for (ch = xbr_base_ch; ch < xbr_nchannels; ch++) {
+        const uint32_t *scale_table;
+        int scale_size;
+
+        // Select the root square table
+        if (s->scale_factor_sel[ch] > 5) {
+            scale_table = ff_dca_scale_factor_quant7;
+            scale_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant7);
+        } else {
+            scale_table = ff_dca_scale_factor_quant6;
+            scale_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant6);
+        }
+
+        // Parse scale factor indices
+        // Look up scale factors from the root square table
+        for (band = 0; band < xbr_nsubbands[ch]; band++) {
+            if (xbr_bit_allocation[ch][band] > 0) {
+                int scale_index = get_bits(&s->gb, xbr_scale_nbits[ch]);
+                if (scale_index >= scale_size) {
+                    av_log(s->avctx, AV_LOG_ERROR, "Invalid XBR scale factor index\n");
+                    return AVERROR_INVALIDDATA;
+                }
+                xbr_scale_factors[ch][band][0] = scale_table[scale_index];
+                if (xbr_transition_mode && s->transition_mode[sf][ch][band]) {
+                    scale_index = get_bits(&s->gb, xbr_scale_nbits[ch]);
+                    if (scale_index >= scale_size) {
+                        av_log(s->avctx, AV_LOG_ERROR, "Invalid XBR scale factor index\n");
+                        return AVERROR_INVALIDDATA;
+                    }
+                    xbr_scale_factors[ch][band][1] = scale_table[scale_index];
+                }
+            }
+        }
+    }
+
+    // Audio data
+    for (ssf = 0, ofs = *sub_pos; ssf < s->nsubsubframes[sf]; ssf++) {
+        for (ch = xbr_base_ch; ch < xbr_nchannels; ch++) {
+            if (get_bits_left(&s->gb) < 0)
+                return AVERROR_INVALIDDATA;
+
+            for (band = 0; band < xbr_nsubbands[ch]; band++) {
+                int abits = xbr_bit_allocation[ch][band];
+                int audio[DCA2_SUBBAND_SAMPLES];
+                int ret, step_size, trans_ssf, scale;
+
+                // Extract bits from the bit stream
+                if (abits > 7) {
+                    // No further encoding
+                    get_array(&s->gb, audio, DCA2_SUBBAND_SAMPLES, abits - 3);
+                } else if (abits > 0) {
+                    // Block codes
+                    if ((ret = parse_block_codes(s, audio, abits)) < 0)
+                        return ret;
+                } else {
+                    // No bits allocated
+                    continue;
+                }
+
+                // Look up quantization step size
+                step_size = ff_dca_lossless_quant[abits];
+
+                // Identify transient location
+                if (xbr_transition_mode)
+                    trans_ssf = s->transition_mode[sf][ch][band];
+                else
+                    trans_ssf = 0;
+
+                // Determine proper scale factor
+                if (trans_ssf == 0 || ssf < trans_ssf)
+                    scale = xbr_scale_factors[ch][band][0];
+                else
+                    scale = xbr_scale_factors[ch][band][1];
+
+                dequantize(s->subband_samples[ch][band] + ofs,
+                           audio, step_size, scale, 1);
+            }
+        }
+
+        // DSYNC
+        if ((ssf == s->nsubsubframes[sf] - 1 || s->sync_ssf) && get_bits(&s->gb, 16) != 0xffff) {
+            av_log(s->avctx, AV_LOG_ERROR, "XBR-DSYNC check failed\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ofs += DCA2_SUBBAND_SAMPLES;
+    }
+
+    // Advance subband sample pointer for the next subframe
+    *sub_pos += nsamples;
+    return 0;
+}
+
+static int parse_xbr_frame(DCA2CoreDecoder *s)
+{
+    int     xbr_frame_size[DCA2_EXSS_CHSETS_MAX];
+    int     xbr_nchannels[DCA2_EXSS_CHSETS_MAX];
+    int     xbr_nsubbands[DCA2_EXSS_CHSETS_MAX * DCA2_EXSS_CHANNELS_MAX];
+    int     xbr_nchsets, xbr_transition_mode, xbr_band_nbits, xbr_base_ch;
+    int     i, ch1, ch2, ret, header_size, header_pos = get_bits_count(&s->gb);
+
+    // XBR sync word
+    if (get_bits_long(&s->gb, 32) != DCA_SYNCWORD_XBR) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XBR sync word\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // XBR frame header length
+    header_size = get_bits(&s->gb, 6) + 1;
+
+    // Check XBR frame header CRC
+    if (ff_dca2_check_crc(&s->gb, header_pos + 32, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XBR frame header checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Number of channel sets
+    xbr_nchsets = get_bits(&s->gb, 2) + 1;
+
+    // Channel set data byte size
+    for (i = 0; i < xbr_nchsets; i++)
+        xbr_frame_size[i] = get_bits(&s->gb, 14) + 1;
+
+    // Transition mode flag
+    xbr_transition_mode = get_bits1(&s->gb);
+
+    // Channel set headers
+    for (i = 0, ch2 = 0; i < xbr_nchsets; i++) {
+        xbr_nchannels[i] = get_bits(&s->gb, 3) + 1;
+        xbr_band_nbits = get_bits(&s->gb, 2) + 5;
+        for (ch1 = 0; ch1 < xbr_nchannels[i]; ch1++, ch2++) {
+            xbr_nsubbands[ch2] = get_bits(&s->gb, xbr_band_nbits) + 1;
+            if (xbr_nsubbands[ch2] > DCA2_SUBBANDS) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid number of active XBR subbands (%d)\n", xbr_nsubbands[ch2]);
+                return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    // Reserved
+    // Byte align
+    // CRC16 of XBR frame header
+    if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XBR frame header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Channel set data
+    for (i = 0, xbr_base_ch = 0; i < xbr_nchsets; i++) {
+        header_pos = get_bits_count(&s->gb);
+
+        if (xbr_base_ch + xbr_nchannels[i] <= s->nchannels) {
+            int sf, sub_pos;
+
+            for (sf = 0, sub_pos = 0; sf < s->nsubframes; sf++) {
+                if ((ret = parse_xbr_subframe(s, xbr_base_ch,
+                                              xbr_base_ch + xbr_nchannels[i],
+                                              xbr_nsubbands, xbr_transition_mode,
+                                              sf, &sub_pos)) < 0)
+                    return ret;
+            }
+        }
+
+        xbr_base_ch += xbr_nchannels[i];
+
+        if (ff_dca2_seek_bits(&s->gb, header_pos + xbr_frame_size[i] * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Read past end of XBR channel set\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+// Modified ISO/IEC 9899 linear congruential generator
+// Returns pseudorandom integer in range [-2^30, 2^30 - 1]
+static int rand_x96(DCA2CoreDecoder *s)
+{
+    s->x96_rand = 1103515245U * s->x96_rand + 12345U;
+    return (s->x96_rand & 0x7fffffff) - 0x40000000;
+}
+
+static int parse_x96_subframe_audio(DCA2CoreDecoder *s, int sf, int xch_base, int *sub_pos)
+{
+    int m, n, ssf, ch, band, ofs;
+
+    // Number of subband samples in this subframe
+    int nsamples = s->nsubsubframes[sf] * DCA2_SUBBAND_SAMPLES;
+    if (*sub_pos + nsamples > s->npcmblocks) {
+        av_log(s->avctx, AV_LOG_ERROR, "Subband sample buffer overflow\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    // VQ encoded or unallocated subbands
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++) {
+            // Get the sample pointer
+            int *samples = s->x96_subband_samples[ch][band] + *sub_pos;
+
+            // Get the scale factor
+            int scale = s->scale_factors[ch][band >> 1][band & 1];
+
+            int abits = s->bit_allocation[ch][band];
+            if (abits == 0) {   // No bits allocated for subband
+                if (scale <= 1) {
+                    memset(samples, 0, nsamples * sizeof(int));
+                } else {
+                    // Generate scaled random samples as required by specification
+                    for (n = 0; n < nsamples; n++)
+                        samples[n] = mul31(rand_x96(s), scale);
+                }
+            } else if (abits == 1) {    // VQ encoded subband
+                for (ssf = 0; ssf < (s->nsubsubframes[sf] + 1) / 2; ssf++) {
+                    // Extract the VQ address from the bit stream
+                    int vq_index = get_bits(&s->gb, 10);
+
+                    // Look up the VQ code book for up to 16 subband samples
+                    const int8_t *vq_samples = ff_dca_high_freq_vq[vq_index];
+
+                    // Number of VQ samples to look up
+                    int vq_nsamples = FFMIN(nsamples - ssf * 16, 16);
+
+                    // Scale and take the samples
+                    for (n = 0; n < vq_nsamples; n++)
+                        *samples++ = clip23(mul4(scale, vq_samples[n]));
+                }
+            }
+        }
+    }
+
+    // Audio data
+    for (ssf = 0, ofs = *sub_pos; ssf < s->nsubsubframes[sf]; ssf++) {
+        for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+            if (get_bits_left(&s->gb) < 0)
+                return AVERROR_INVALIDDATA;
+
+            for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++) {
+                int abits = s->bit_allocation[ch][band] - 1;
+                int audio[DCA2_SUBBAND_SAMPLES];
+                int ret, step_size, scale;
+
+                // Not VQ encoded or unallocated subbands
+                if (abits < 1)
+                    continue;
+
+                // Extract bits from the bit stream
+                if ((ret = extract_audio(s, audio, abits, ch)) < 0)
+                    return ret;
+
+                // Select quantization step size table
+                // Look up quantization step size
+                if (s->bit_rate == 3)
+                    step_size = ff_dca_lossless_quant[abits];
+                else
+                    step_size = ff_dca_lossy_quant[abits];
+
+                // Determine proper scale factor
+                scale = s->scale_factors[ch][band >> 1][band & 1];
+
+                dequantize(s->x96_subband_samples[ch][band] + ofs,
+                           audio, step_size, scale, 0);
+            }
+        }
+
+        // DSYNC
+        if ((ssf == s->nsubsubframes[sf] - 1 || s->sync_ssf) && get_bits(&s->gb, 16) != 0xffff) {
+            av_log(s->avctx, AV_LOG_ERROR, "X96-DSYNC check failed\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        ofs += DCA2_SUBBAND_SAMPLES;
+    }
+
+    // Inverse ADPCM
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++) {
+            // Only if prediction mode is on
+            if (s->prediction_mode[ch][band]) {
+                int *samples = s->x96_subband_samples[ch][band] + *sub_pos;
+
+                // Extract the VQ index
+                int vq_index = s->prediction_vq_index[ch][band];
+
+                // Look up the VQ table for prediction coefficients
+                const int16_t *vq_coeffs = ff_dca_adpcm_vb[vq_index];
+                for (m = 0; m < nsamples; m++) {
+                    int64_t err = INT64_C(0);
+                    for (n = 0; n < DCA2_ADPCM_COEFFS; n++)
+                        err += (int64_t)samples[m - n - 1] * vq_coeffs[n];
+                    samples[m] = clip23(samples[m] + clip23(norm13(err)));
+                }
+            }
+        }
+    }
+
+    // Joint subband coding
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            // Get source channel
+            int src_ch = s->joint_intensity_index[ch] - 1;
+            for (band = s->nsubbands[ch]; band < s->nsubbands[src_ch]; band++) {
+                int *src = s->x96_subband_samples[src_ch][band] + *sub_pos;
+                int *dst = s->x96_subband_samples[    ch][band] + *sub_pos;
+                int scale = s->joint_scale_factors[ch][band];
+                for (n = 0; n < nsamples; n++)
+                    dst[n] = clip23(mul17(src[n], scale));
+            }
+        }
+    }
+
+    // Advance subband sample pointer for the next subframe
+    *sub_pos += nsamples;
+    return 0;
+}
+
+static void erase_x96_adpcm_history(DCA2CoreDecoder *s)
+{
+    int ch, band;
+
+    // Erase ADPCM history from previous frame if
+    // predictor history switch was disabled
+    for (ch = 0; ch < DCA2_CHANNELS; ch++)
+        for (band = 0; band < DCA2_SUBBANDS_X96; band++)
+            AV_ZERO128(s->x96_subband_samples[ch][band] - DCA2_ADPCM_COEFFS);
+}
+
+static int alloc_x96_sample_buffer(DCA2CoreDecoder *s)
+{
+    int nchsamples = DCA2_ADPCM_COEFFS + s->npcmblocks;
+    int nframesamples = nchsamples * DCA2_CHANNELS * DCA2_SUBBANDS_X96;
+    unsigned int size = s->x96_subband_size;
+    int ch, band;
+
+    // Reallocate subband sample buffer
+    av_fast_mallocz(&s->x96_subband_buffer, &s->x96_subband_size,
+                    nframesamples * sizeof(int));
+    if (!s->x96_subband_buffer)
+        return AVERROR(ENOMEM);
+
+    if (size != s->x96_subband_size) {
+        for (ch = 0; ch < DCA2_CHANNELS; ch++)
+            for (band = 0; band < DCA2_SUBBANDS_X96; band++)
+                s->x96_subband_samples[ch][band] = s->x96_subband_buffer +
+                    (ch * DCA2_SUBBANDS_X96 + band) * nchsamples + DCA2_ADPCM_COEFFS;
+    }
+
+    if (!s->predictor_history)
+        erase_x96_adpcm_history(s);
+
+    return 0;
+}
+
+static int parse_x96_subframe_header(DCA2CoreDecoder *s, int xch_base)
+{
+    int ch, band, ret;
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    // Prediction mode
+    for (ch = xch_base; ch < s->x96_nchannels; ch++)
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++)
+            s->prediction_mode[ch][band] = get_bits1(&s->gb);
+
+    // Prediction coefficients VQ address
+    for (ch = xch_base; ch < s->x96_nchannels; ch++)
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++)
+            if (s->prediction_mode[ch][band])
+                s->prediction_vq_index[ch][band] = get_bits(&s->gb, 12);
+
+    // Bit allocation index
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Select codebook
+        int sel = s->bit_allocation_sel[ch];
+
+        // Clear accumulation
+        int abits = 0;
+
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++) {
+            // If Huffman code was used, the difference of abits was encoded
+            if (sel < 7)
+                abits += get_vlc(&s->gb, &vlc_quant_index[5 + 2 * s->x96_high_res], sel);
+            else
+                abits = get_bits(&s->gb, 3 + s->x96_high_res);
+
+            if (abits < 0 || abits > 7 + 8 * s->x96_high_res) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 bit allocation index\n");
+                return AVERROR_INVALIDDATA;
+            }
+
+            s->bit_allocation[ch][band] = abits;
+        }
+    }
+
+    // Scale factors
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Select codebook
+        int sel = s->scale_factor_sel[ch];
+
+        // Clear accumulation
+        int scale_index = 0;
+
+        // Extract scales for subbands
+        // Transmitted even for unallocated subbands
+        for (band = s->x96_subband_start; band < s->nsubbands[ch]; band++) {
+            if ((ret = parse_scale(s, &scale_index, sel)) < 0)
+                return ret;
+            s->scale_factors[ch][band >> 1][band & 1] = ret;
+        }
+    }
+
+    // Joint subband codebook select
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            s->joint_scale_sel[ch] = get_bits(&s->gb, 3);
+            if (s->joint_scale_sel[ch] == 7) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 joint scale factor code book\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
+    }
+
+    // Scale factors for joint subband coding
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Only if joint subband coding is enabled
+        if (s->joint_intensity_index[ch]) {
+            // Select codebook
+            int sel = s->joint_scale_sel[ch];
+            // Get source channel
+            int src_ch = s->joint_intensity_index[ch] - 1;
+            for (band = s->nsubbands[ch]; band < s->nsubbands[src_ch]; band++) {
+                if ((ret = parse_joint_scale(s, sel)) < 0)
+                    return ret;
+                s->joint_scale_factors[ch][band] = ret;
+            }
+        }
+    }
+
+    // Side information CRC check word
+    if (s->crc_present)
+        skip_bits(&s->gb, 16);
+
+    return 0;
+}
+
+static int parse_x96_coding_header(DCA2CoreDecoder *s, int exss, int xch_base)
+{
+    int n, ch, header_size = 0, header_pos = get_bits_count(&s->gb);
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    if (exss) {
+        // Channel set header length
+        header_size = get_bits(&s->gb, 7) + 1;
+
+        // Check CRC
+        if (s->x96_crc_present && ff_dca2_check_crc(&s->gb, header_pos, header_pos + header_size * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 channel set header checksum\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // High resolution flag
+    s->x96_high_res = get_bits1(&s->gb);
+
+    // First encoded subband
+    if (s->x96_rev_no < 8) {
+        s->x96_subband_start = get_bits(&s->gb, 5);
+        if (s->x96_subband_start > 27) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 subband start index (%d)\n", s->x96_subband_start);
+            return AVERROR_INVALIDDATA;
+        }
+    } else {
+        s->x96_subband_start = DCA2_SUBBANDS;
+    }
+
+    // Subband activity count
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        s->nsubbands[ch] = get_bits(&s->gb, 6) + 1;
+        if (s->nsubbands[ch] < DCA2_SUBBANDS) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 subband activity count (%d)\n", s->nsubbands[ch]);
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // Joint intensity coding index
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        if ((n = get_bits(&s->gb, 3)) && xch_base)
+            n += xch_base - 1;
+        if (n > s->x96_nchannels) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 joint intensity coding index\n");
+            return AVERROR_INVALIDDATA;
+        }
+        s->joint_intensity_index[ch] = n;
+    }
+
+    // Scale factor code book
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        s->scale_factor_sel[ch] = get_bits(&s->gb, 3);
+        if (s->scale_factor_sel[ch] >= 6) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 scale factor code book\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // Bit allocation quantizer select
+    for (ch = xch_base; ch < s->x96_nchannels; ch++)
+        s->bit_allocation_sel[ch] = get_bits(&s->gb, 3);
+
+    // Quantization index codebook select
+    for (n = 0; n < 6 + 4 * s->x96_high_res; n++)
+        for (ch = xch_base; ch < s->x96_nchannels; ch++)
+            s->quant_index_sel[ch][n] = get_bits(&s->gb, ff_dca2_quant_index_sel_nbits[n]);
+
+    if (exss) {
+        // Reserved
+        // Byte align
+        // CRC16 of channel set header
+        if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Read past end of X96 channel set header\n");
+            return AVERROR_INVALIDDATA;
+        }
+    } else {
+        if (s->crc_present)
+            skip_bits(&s->gb, 16);
+    }
+
+    return 0;
+}
+
+static int parse_x96_frame_data(DCA2CoreDecoder *s, int exss, int xch_base)
+{
+    int sf, ch, ret, band, sub_pos;
+
+    if ((ret = parse_x96_coding_header(s, exss, xch_base)) < 0)
+        return ret;
+
+    for (sf = 0, sub_pos = 0; sf < s->nsubframes; sf++) {
+        if ((ret = parse_x96_subframe_header(s, xch_base)) < 0)
+            return ret;
+        if ((ret = parse_x96_subframe_audio(s, sf, xch_base, &sub_pos)) < 0)
+            return ret;
+    }
+
+    for (ch = xch_base; ch < s->x96_nchannels; ch++) {
+        // Number of active subbands for this channel
+        int nsubbands = s->nsubbands[ch];
+        if (s->joint_intensity_index[ch])
+            nsubbands = FFMAX(nsubbands, s->nsubbands[s->joint_intensity_index[ch] - 1]);
+
+        // Update history for ADPCM
+        // Clear inactive subbands
+        for (band = 0; band < DCA2_SUBBANDS_X96; band++) {
+            int *samples = s->x96_subband_samples[ch][band] - DCA2_ADPCM_COEFFS;
+            if (band >= s->x96_subband_start && band < nsubbands)
+                AV_COPY128(samples, samples + s->npcmblocks);
+            else
+                memset(samples, 0, (DCA2_ADPCM_COEFFS + s->npcmblocks) * sizeof(int));
+        }
+    }
+
+    return 0;
+}
+
+static int parse_x96_frame(DCA2CoreDecoder *s)
+{
+    int ret;
+
+    // Revision number
+    s->x96_rev_no = get_bits(&s->gb, 4);
+    if (s->x96_rev_no < 1 || s->x96_rev_no > 8) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unsupported X96 revision (%d)\n", s->x96_rev_no);
+        return AVERROR_INVALIDDATA;
+    }
+
+    s->x96_crc_present = 0;
+    s->x96_nchannels = s->nchannels;
+
+    if ((ret = alloc_x96_sample_buffer(s)) < 0)
+        return ret;
+
+    if ((ret = parse_x96_frame_data(s, 0, 0)) < 0)
+        return ret;
+
+    // Seek to the end of core frame
+    if (ff_dca2_seek_bits(&s->gb, s->frame_size * 8))
+        return AVERROR_INVALIDDATA;
+
+    return 0;
+}
+
+static int parse_x96_frame_exss(DCA2CoreDecoder *s)
+{
+    int     x96_frame_size[DCA2_EXSS_CHSETS_MAX];
+    int     x96_nchannels[DCA2_EXSS_CHSETS_MAX];
+    int     x96_nchsets, x96_base_ch;
+    int     i, ret, header_size, header_pos = get_bits_count(&s->gb);
+
+    // X96 sync word
+    if (get_bits_long(&s->gb, 32) != DCA_SYNCWORD_X96) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 sync word\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // X96 frame header length
+    header_size = get_bits(&s->gb, 6) + 1;
+
+    // Check X96 frame header CRC
+    if (ff_dca2_check_crc(&s->gb, header_pos + 32, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid X96 frame header checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Revision number
+    s->x96_rev_no = get_bits(&s->gb, 4);
+    if (s->x96_rev_no < 1 || s->x96_rev_no > 8) {
+        av_log(s->avctx, AV_LOG_ERROR, "Unsupported X96 revision (%d)\n", s->x96_rev_no);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // CRC presence flag for channel set header
+    s->x96_crc_present = get_bits1(&s->gb);
+
+    // Number of channel sets
+    x96_nchsets = get_bits(&s->gb, 2) + 1;
+
+    // Channel set data byte size
+    for (i = 0; i < x96_nchsets; i++)
+        x96_frame_size[i] = get_bits(&s->gb, 12) + 1;
+
+    // Number of channels in channel set
+    for (i = 0; i < x96_nchsets; i++)
+        x96_nchannels[i] = get_bits(&s->gb, 3) + 1;
+
+    // Reserved
+    // Byte align
+    // CRC16 of X96 frame header
+    if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of X96 frame header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if ((ret = alloc_x96_sample_buffer(s)) < 0)
+        return ret;
+
+    // Channel set data
+    for (i = 0, x96_base_ch = 0; i < x96_nchsets; i++) {
+        header_pos = get_bits_count(&s->gb);
+
+        if (x96_base_ch + x96_nchannels[i] <= s->nchannels) {
+            s->x96_nchannels = x96_base_ch + x96_nchannels[i];
+            if ((ret = parse_x96_frame_data(s, 1, x96_base_ch)) < 0)
+                return ret;
+        }
+
+        x96_base_ch += x96_nchannels[i];
+
+        if (ff_dca2_seek_bits(&s->gb, header_pos + x96_frame_size[i] * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Read past end of X96 channel set\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+static int parse_aux_data(DCA2CoreDecoder *s)
+{
+    int aux_pos;
+
+    if (get_bits_left(&s->gb) < 0)
+        return AVERROR_INVALIDDATA;
+
+    // Auxiliary data byte count (can't be trusted)
+    skip_bits(&s->gb, 6);
+
+    // 4-byte align
+    skip_bits_long(&s->gb, -get_bits_count(&s->gb) & 31);
+
+    // Auxiliary data sync word
+    if (get_bits_long(&s->gb, 32) != DCA_SYNCWORD_REV1AUX) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid auxiliary data sync word\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    aux_pos = get_bits_count(&s->gb);
+
+    // Auxiliary decode time stamp flag
+    if (get_bits1(&s->gb))
+        skip_bits_long(&s->gb, 47);
+
+    // Auxiliary dynamic downmix flag
+    if (s->prim_dmix_embedded = get_bits1(&s->gb)) {
+        int i, m, n;
+
+        // Auxiliary primary channel downmix type
+        s->prim_dmix_type = get_bits(&s->gb, 3);
+        if (s->prim_dmix_type >= DCA2_DMIX_TYPE_COUNT) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid primary channel set downmix type\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Size of downmix coefficients matrix
+        m = ff_dca2_dmix_primary_nch[s->prim_dmix_type];
+        n = ff_dca_channels[s->audio_mode] + !!s->lfe_present;
+
+        // Dynamic downmix code coefficients
+        for (i = 0; i < m * n; i++) {
+            int code = get_bits(&s->gb, 9);
+            int sign = (code >> 8) - 1;
+            unsigned int index = code & 0xff;
+            if (index >= FF_DCA_DMIXTABLE_SIZE) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid downmix coefficient index\n");
+                return AVERROR_INVALIDDATA;
+            }
+            s->prim_dmix_coeff[i] = (ff_dca_dmixtable[index] ^ sign) - sign;
+        }
+    }
+
+    // Byte align
+    skip_bits(&s->gb, -get_bits_count(&s->gb) & 7);
+
+    // CRC16 of auxiliary data
+    skip_bits(&s->gb, 16);
+
+    // Check CRC
+    if (ff_dca2_check_crc(&s->gb, aux_pos, get_bits_count(&s->gb))) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid auxiliary data checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int parse_optional_info(DCA2CoreDecoder *s)
+{
+    DCA2Context *dca = s->avctx->priv_data;
+    int ret = -1;
+
+    // Time code stamp
+    if (s->ts_present)
+        skip_bits_long(&s->gb, 32);
+
+    // Auxiliary data
+    if (s->aux_present && (ret = parse_aux_data(s)) < 0
+        && (s->avctx->err_recognition & AV_EF_EXPLODE))
+        return ret;
+
+    if (ret < 0)
+        s->prim_dmix_embedded = 0;
+
+    // Core extensions
+    if (s->ext_audio_present && !dca->core_only) {
+        int sync_pos = FFMIN(s->frame_size / 4, s->gb.size_in_bits / 32) - 1;
+        int last_pos = get_bits_count(&s->gb) / 32;
+        int size, dist;
+
+        // Search for extension sync words aligned on 4-byte boundary. Search
+        // must be done backwards from the end of core frame to work around
+        // sync word aliasing issues.
+        switch (s->ext_audio_type) {
+        case EXT_AUDIO_XCH:
+            if (dca->request_channel_layout)
+                break;
+
+            // The distance between XCH sync word and end of the core frame
+            // must be equal to XCH frame size. Off by one error is allowed for
+            // compatibility with legacy bitstreams. Minimum XCH frame size is
+            // 96 bytes. AMODE and PCHS are further checked to reduce
+            // probability of alias sync detection.
+            for (; sync_pos >= last_pos; sync_pos--) {
+                if (AV_RB32(s->gb.buffer + sync_pos * 4) == DCA_SYNCWORD_XCH) {
+                    s->gb.index = (sync_pos + 1) * 32;
+                    size = get_bits(&s->gb, 10) + 1;
+                    dist = s->frame_size - sync_pos * 4;
+                    if (size >= 96
+                        && (size == dist || size - 1 == dist)
+                        && get_bits(&s->gb, 7) == 0x08) {
+                        s->xch_pos = get_bits_count(&s->gb);
+                        break;
+                    }
+                }
+            }
+
+            if (s->avctx->err_recognition & AV_EF_EXPLODE) {
+                av_log(s->avctx, AV_LOG_ERROR, "XCH sync word not found\n");
+                return AVERROR_INVALIDDATA;
+            }
+            break;
+
+        case EXT_AUDIO_X96:
+            // The distance between X96 sync word and end of the core frame
+            // must be equal to X96 frame size. Minimum X96 frame size is 96
+            // bytes.
+            for (; sync_pos >= last_pos; sync_pos--) {
+                if (AV_RB32(s->gb.buffer + sync_pos * 4) == DCA_SYNCWORD_X96) {
+                    s->gb.index = (sync_pos + 1) * 32;
+                    size = get_bits(&s->gb, 12) + 1;
+                    dist = s->frame_size - sync_pos * 4;
+                    if (size >= 96 && size == dist) {
+                        s->x96_pos = get_bits_count(&s->gb);
+                        break;
+                    }
+                }
+            }
+
+            if (s->avctx->err_recognition & AV_EF_EXPLODE) {
+                av_log(s->avctx, AV_LOG_ERROR, "X96 sync word not found\n");
+                return AVERROR_INVALIDDATA;
+            }
+            break;
+
+        case EXT_AUDIO_XXCH:
+            if (dca->request_channel_layout)
+                break;
+
+            // XXCH frame header CRC must be valid. Minimum XXCH frame header
+            // size is 11 bytes.
+            for (; sync_pos >= last_pos; sync_pos--) {
+                if (AV_RB32(s->gb.buffer + sync_pos * 4) == DCA_SYNCWORD_XXCH) {
+                    s->gb.index = (sync_pos + 1) * 32;
+                    size = get_bits(&s->gb, 6) + 1;
+                    if (size >= 11 &&
+                        !ff_dca2_check_crc(&s->gb, (sync_pos + 1) * 32,
+                                           sync_pos * 32 + size * 8)) {
+                        s->xxch_pos = sync_pos * 32;
+                        break;
+                    }
+                }
+            }
+
+            if (s->avctx->err_recognition & AV_EF_EXPLODE) {
+                av_log(s->avctx, AV_LOG_ERROR, "XXCH sync word not found\n");
+                return AVERROR_INVALIDDATA;
+            }
+            break;
+        }
+    }
+
+    return 0;
+}
+
+int ff_dca2_core_parse(DCA2CoreDecoder *s, uint8_t *data, int size)
+{
+    int ret;
+
+    s->ext_audio_mask = 0;
+    s->xch_pos = s->xxch_pos = s->x96_pos = 0;
+
+    if ((ret = init_get_bits8(&s->gb, data, size)) < 0)
+        return ret;
+
+    skip_bits_long(&s->gb, 32);
+    if ((ret = parse_frame_header(s)) < 0)
+        return ret;
+    if ((ret = alloc_sample_buffer(s)) < 0)
+        return ret;
+    if ((ret = parse_frame_data(s, HEADER_CORE, 0)) < 0)
+        return ret;
+    if ((ret = parse_optional_info(s)) < 0)
+        return ret;
+
+    // Workaround for DTS in WAV
+    if (s->frame_size > size && s->frame_size < size + 4) {
+        av_log(s->avctx, AV_LOG_DEBUG, "Working around excessive core frame size (%d > %d)\n", s->frame_size, size);
+        s->frame_size = size;
+    }
+
+    if (ff_dca2_seek_bits(&s->gb, s->frame_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of core frame\n");
+        return ret;
+    }
+
+    return 0;
+}
+
+int ff_dca2_core_parse_exss(DCA2CoreDecoder *s, uint8_t *data, DCA2ExssAsset *asset)
+{
+    DCA2Context *dca = s->avctx->priv_data;
+    GetBitContext temp = s->gb;
+    int exss_mask = asset ? asset->extension_mask : 0;
+    int ret = 0, ext = 0;
+
+    // Parse (X)XCH unless downmixing
+    if (!dca->request_channel_layout) {
+        if (exss_mask & DCA2_EXSS_XXCH) {
+            if ((ret = init_get_bits8(&s->gb, data + asset->xxch_offset, asset->xxch_size)) < 0)
+                return ret;
+            ret = parse_xxch_frame(s);
+            ext = DCA2_EXSS_XXCH;
+        } else if (s->xxch_pos) {
+            s->gb.index = s->xxch_pos;
+            ret = parse_xxch_frame(s);
+            ext = DCA2_CSS_XXCH;
+        } else if (s->xch_pos) {
+            s->gb.index = s->xch_pos;
+            ret = parse_xch_frame(s);
+            ext = DCA2_CSS_XCH;
+        }
+
+        // Revert to primary channel set in case (X)XCH parsing fails
+        if (ret < 0) {
+            if (s->avctx->err_recognition & AV_EF_EXPLODE)
+                return ret;
+            s->nchannels = ff_dca_channels[s->audio_mode];
+            s->ch_mask = audio_mode_ch_mask[s->audio_mode];
+            if (s->lfe_present)
+                s->ch_mask |= DCA2_SPEAKER_MASK_LFE1;
+        } else {
+            s->ext_audio_mask |= ext;
+        }
+    }
+
+    // Parse XBR
+    if (exss_mask & DCA2_EXSS_XBR) {
+        if ((ret = init_get_bits8(&s->gb, data + asset->xbr_offset, asset->xbr_size)) < 0)
+            return ret;
+        if ((ret = parse_xbr_frame(s)) < 0) {
+            if (s->avctx->err_recognition & AV_EF_EXPLODE)
+                return ret;
+        } else {
+            s->ext_audio_mask |= DCA2_EXSS_XBR;
+        }
+    }
+
+    // Parse X96
+    if (exss_mask & DCA2_EXSS_X96) {
+        if ((ret = init_get_bits8(&s->gb, data + asset->x96_offset, asset->x96_size)) < 0)
+            return ret;
+        if ((ret = parse_x96_frame_exss(s)) < 0) {
+            if (s->avctx->err_recognition & AV_EF_EXPLODE)
+                return ret;
+        } else {
+            s->ext_audio_mask |= DCA2_EXSS_X96;
+        }
+    } else if (s->x96_pos) {
+        s->gb = temp;
+        s->gb.index = s->x96_pos;
+        if ((ret = parse_x96_frame(s)) < 0) {
+            if (s->avctx->err_recognition & AV_EF_EXPLODE)
+                return ret;
+        } else {
+            s->ext_audio_mask |= DCA2_CSS_X96;
+        }
+    }
+
+    return 0;
+}
+
+static int map_prm_ch_to_spkr(DCA2CoreDecoder *s, int ch)
+{
+    int pos, spkr;
+
+    // Try to map this channel to core first
+    pos = ff_dca_channels[s->audio_mode];
+    if (ch < pos) {
+        spkr = prm_ch_to_spkr_map[s->audio_mode][ch];
+        if (s->ext_audio_mask & (DCA2_CSS_XXCH | DCA2_EXSS_XXCH)) {
+            if (s->xxch_core_mask & (1U << spkr))
+                return spkr;
+            if (spkr == DCA2_SPEAKER_Ls && (s->xxch_core_mask & DCA2_SPEAKER_MASK_Lss))
+                return DCA2_SPEAKER_Lss;
+            if (spkr == DCA2_SPEAKER_Rs && (s->xxch_core_mask & DCA2_SPEAKER_MASK_Rss))
+                return DCA2_SPEAKER_Rss;
+            return -1;
+        }
+        return spkr;
+    }
+
+    // Then XCH
+    if ((s->ext_audio_mask & DCA2_CSS_XCH) && ch == pos)
+        return DCA2_SPEAKER_Cs;
+
+    // Then XXCH
+    if (s->ext_audio_mask & (DCA2_CSS_XXCH | DCA2_EXSS_XXCH)) {
+        for (spkr = DCA2_SPEAKER_Cs; spkr < s->xxch_mask_nbits; spkr++)
+            if (s->xxch_spkr_mask & (1U << spkr))
+                if (pos++ == ch)
+                    return spkr;
+    }
+
+    // No mapping
+    return -1;
+}
+
+static void erase_dsp_history(DCA2CoreDecoder *s)
+{
+    memset(s->dcadsp_data, 0, sizeof(s->dcadsp_data));
+    s->output_history_lfe_fixed = 0;
+    s->output_history_lfe_float = 0.0f;
+}
+
+int ff_dca2_core_filter_fixed(DCA2CoreDecoder *s, int x96_synth)
+{
+    int n, ch, spkr, nsamples, *ptr, x96_nchannels = 0;
+
+    // Externally set x96_synth flag implies that X96 synthesis should be
+    // enabled, yet actual X96 subband data should be discarded. This is a
+    // special case for lossless residual decoder that ignores X96 data if
+    // present.
+    if (!x96_synth && (s->ext_audio_mask & (DCA2_CSS_X96 | DCA2_EXSS_X96))) {
+        x96_nchannels = s->x96_nchannels;
+        x96_synth = 1;
+    }
+
+    s->output_rate = s->sample_rate << x96_synth;
+    s->npcmsamples = nsamples = (s->npcmblocks * DCA2_PCMBLOCK_SAMPLES) << x96_synth;
+
+    // Reallocate PCM output buffer
+    av_fast_malloc(&s->output_buffer, &s->output_size,
+                   nsamples * av_popcount(s->ch_mask) * sizeof(int));
+    if (!s->output_buffer)
+        return AVERROR(ENOMEM);
+
+    ptr = (int *)s->output_buffer;
+    for (spkr = 0; spkr < DCA2_SPEAKER_COUNT; spkr++) {
+        if (s->ch_mask & (1U << spkr)) {
+            s->output_samples[spkr] = ptr;
+            ptr += nsamples;
+        } else {
+            s->output_samples[spkr] = NULL;
+        }
+    }
+
+    // Handle change of filtering mode
+    if (s->filter_mode != (x96_synth | 2)) {
+        erase_dsp_history(s);
+        s->filter_mode = x96_synth | 2;
+    }
+
+    // Filter primary channels
+    for (ch = 0; ch < s->nchannels; ch++) {
+        // Map this primary channel to speaker
+        spkr = map_prm_ch_to_spkr(s, ch);
+        if (spkr < 0)
+            return AVERROR(EINVAL);
+
+        // Filter bank reconstruction
+        s->dcadsp_fixed.sub_qmf[x96_synth](
+            s->output_samples[spkr],
+            s->subband_samples[ch],
+            ch < x96_nchannels ? s->x96_subband_samples[ch] : NULL,
+            &s->dcadsp_data[ch],
+            s->npcmblocks,
+            s->filter_perfect);
+    }
+
+    // Filter LFE channel
+    if (s->lfe_present) {
+        int *samples = s->output_samples[DCA2_SPEAKER_LFE1];
+        int nlfesamples = s->npcmblocks >> 1;
+
+        // Check LFF
+        if (s->lfe_present == LFE_FLAG_128) {
+            av_log(s->avctx, AV_LOG_ERROR, "Fixed point mode doesn't support LFF=1\n");
+            return AVERROR(EINVAL);
+        }
+
+        // Offset intermediate buffer for X96
+        if (x96_synth)
+            samples += nsamples / 2;
+
+        // Interpolate LFE channel
+        s->dcadsp_fixed.lfe_fir(
+            samples, s->lfe_samples + DCA2_LFE_HISTORY, s->npcmblocks);
+
+        if (x96_synth) {
+            // Filter 96 kHz oversampled LFE PCM to attenuate high frequency
+            // (47.6 - 48.0 kHz) components of interpolation image
+            int history = s->output_history_lfe_fixed;
+            int *samples_out = s->output_samples[DCA2_SPEAKER_LFE1];
+            for (n = 0; n < nsamples / 2; n++) {
+                int64_t a = INT64_C(2097471) * samples[n] + INT64_C(6291137) * history;
+                int64_t b = INT64_C(6291137) * samples[n] + INT64_C(2097471) * history;
+                history = samples[n];
+                samples_out[2 * n    ] = clip23(norm23(a));
+                samples_out[2 * n + 1] = clip23(norm23(b));
+            }
+
+            // Update LFE PCM history
+            s->output_history_lfe_fixed = history;
+        }
+
+        // Update LFE history
+        for (n = DCA2_LFE_HISTORY - 1; n >= 0; n--)
+            s->lfe_samples[n] = s->lfe_samples[nlfesamples + n];
+    }
+
+    return 0;
+}
+
+static int filter_frame_fixed(DCA2CoreDecoder *s, AVFrame *frame)
+{
+    AVCodecContext *avctx = s->avctx;
+    int i, n, ch, ret, spkr, nsamples;
+
+    if ((ret = ff_dca2_core_filter_fixed(s, 0)) < 0)
+        return ret;
+
+    avctx->sample_rate = s->output_rate;
+    avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
+    avctx->bits_per_raw_sample = 24;
+
+    frame->nb_samples = nsamples = s->npcmsamples;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    // Undo embedded XCH downmix
+    if (s->es_format && (s->ext_audio_mask & DCA2_CSS_XCH)
+        && s->audio_mode >= AMODE_2F2R) {
+        int *samples_ls = s->output_samples[DCA2_SPEAKER_Ls];
+        int *samples_rs = s->output_samples[DCA2_SPEAKER_Rs];
+        int *samples_cs = s->output_samples[DCA2_SPEAKER_Cs];
+        for (n = 0; n < nsamples; n++) {
+            int cs = mul23(samples_cs[n], 5931520);
+            samples_ls[n] = clip23(samples_ls[n] - cs);
+            samples_rs[n] = clip23(samples_rs[n] - cs);
+        }
+    }
+
+    // Undo embedded XXCH downmix
+    if ((s->ext_audio_mask & (DCA2_CSS_XXCH | DCA2_EXSS_XXCH))
+        && s->xxch_dmix_embedded) {
+        int scale_inv   = s->xxch_dmix_scale_inv;
+        int *coeff_ptr  = s->xxch_dmix_coeff;
+        int xch_base    = ff_dca_channels[s->audio_mode];
+        av_assert0(s->nchannels - xch_base <= DCA2_XXCH_CHANNELS_MAX);
+
+        // Undo embedded core downmix pre-scaling
+        for (spkr = 0; spkr < s->xxch_mask_nbits; spkr++)
+            if (s->xxch_core_mask & (1U << spkr))
+                vmul16(s->output_samples[spkr], scale_inv, nsamples);
+
+        // Undo downmix
+        for (ch = xch_base; ch < s->nchannels; ch++) {
+            int src_spkr = map_prm_ch_to_spkr(s, ch);
+            if (src_spkr < 0)
+                return AVERROR(EINVAL);
+            for (spkr = 0; spkr < s->xxch_mask_nbits; spkr++) {
+                if (s->xxch_dmix_mask[ch - xch_base] & (1U << spkr)) {
+                    int coeff = mul16(*coeff_ptr++, scale_inv);
+                    if (coeff)
+                        vmul15_sub(s->output_samples[spkr    ],
+                                   s->output_samples[src_spkr],
+                                   coeff, nsamples);
+                }
+            }
+        }
+    }
+
+    // Downmix primary channel set to stereo
+    if (s->request_mask != s->ch_mask) {
+        ff_dca2_downmix_to_stereo_fixed(s->output_samples,
+                                        s->prim_dmix_coeff,
+                                        nsamples, s->ch_mask);
+    }
+
+    for (i = 0; i < avctx->channels; i++) {
+        int32_t *samples = s->output_samples[s->ch_remap[i]];
+        int32_t *plane = (int32_t *)frame->extended_data[i];
+        for (n = 0; n < nsamples; n++)
+            plane[n] = clip23(samples[n]) * (1 << 8);
+    }
+
+    return 0;
+}
+
+static int filter_frame_float(DCA2CoreDecoder *s, AVFrame *frame)
+{
+    AVCodecContext *avctx = s->avctx;
+    int x96_nchannels = 0, x96_synth = 0;
+    int i, n, ch, ret, spkr, nsamples, nchannels;
+    float *output_samples[DCA2_SPEAKER_COUNT] = { NULL }, *ptr;
+
+    if (s->ext_audio_mask & (DCA2_CSS_X96 | DCA2_EXSS_X96)) {
+        x96_nchannels = s->x96_nchannels;
+        x96_synth = 1;
+    }
+
+    avctx->sample_rate = s->sample_rate << x96_synth;
+    avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+    avctx->bits_per_raw_sample = 0;
+
+    frame->nb_samples = nsamples = (s->npcmblocks * DCA2_PCMBLOCK_SAMPLES) << x96_synth;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    // Build reverse speaker to channel mapping
+    for (i = 0; i < avctx->channels; i++)
+        output_samples[s->ch_remap[i]] = (float *)frame->extended_data[i];
+
+    // Allocate space for extra channels
+    nchannels = av_popcount(s->ch_mask) - avctx->channels;
+    if (nchannels > 0) {
+        av_fast_malloc(&s->output_buffer, &s->output_size,
+                       nsamples * nchannels * sizeof(float));
+        if (!s->output_buffer)
+            return AVERROR(ENOMEM);
+
+        ptr = (float *)s->output_buffer;
+        for (spkr = 0; spkr < DCA2_SPEAKER_COUNT; spkr++) {
+            if (!(s->ch_mask & (1U << spkr)))
+                continue;
+            if (output_samples[spkr])
+                continue;
+            output_samples[spkr] = ptr;
+            ptr += nsamples;
+        }
+    }
+
+    // Handle change of filtering mode
+    if (s->filter_mode != x96_synth) {
+        erase_dsp_history(s);
+        s->filter_mode = x96_synth;
+    }
+
+    // Filter primary channels
+    for (ch = 0; ch < s->nchannels; ch++) {
+        // Map this primary channel to speaker
+        spkr = map_prm_ch_to_spkr(s, ch);
+        if (spkr < 0)
+            return AVERROR(EINVAL);
+
+        // Filter bank reconstruction
+        s->dcadsp_float.sub_qmf[x96_synth](
+            &s->imdct[x96_synth],
+            &s->synth,
+            output_samples[spkr],
+            s->subband_samples[ch],
+            ch < x96_nchannels ? s->x96_subband_samples[ch] : NULL,
+            &s->dcadsp_data[ch],
+            s->npcmblocks,
+            s->filter_perfect);
+    }
+
+    // Filter LFE channel
+    if (s->lfe_present) {
+        int dec_select = (s->lfe_present == LFE_FLAG_128);
+        float *samples = output_samples[DCA2_SPEAKER_LFE1];
+        int nlfesamples = s->npcmblocks >> (dec_select + 1);
+
+        // Offset intermediate buffer for X96
+        if (x96_synth)
+            samples += nsamples / 2;
+
+        // Interpolate LFE channel
+        s->dcadsp_float.lfe_fir[dec_select](
+            samples, s->lfe_samples + DCA2_LFE_HISTORY, s->npcmblocks);
+
+        if (x96_synth) {
+            // Filter 96 kHz oversampled LFE PCM to attenuate high frequency
+            // (47.6 - 48.0 kHz) components of interpolation image
+            float history = s->output_history_lfe_float;
+            float *samples_out = output_samples[DCA2_SPEAKER_LFE1];
+            for (n = 0; n < nsamples / 2; n++) {
+                float a = 0.25f * samples[n] + 0.75f * history;
+                float b = 0.75f * samples[n] + 0.25f * history;
+                history = samples[n];
+                samples_out[2 * n    ] = a;
+                samples_out[2 * n + 1] = b;
+            }
+
+            // Update LFE PCM history
+            s->output_history_lfe_float = history;
+        }
+
+        // Update LFE history
+        for (n = DCA2_LFE_HISTORY - 1; n >= 0; n--)
+            s->lfe_samples[n] = s->lfe_samples[nlfesamples + n];
+    }
+
+    // Undo embedded XCH downmix
+    if (s->es_format && (s->ext_audio_mask & DCA2_CSS_XCH)
+        && s->audio_mode >= AMODE_2F2R) {
+        s->fdsp->vector_fmac_scalar(output_samples[DCA2_SPEAKER_Ls],
+                                    output_samples[DCA2_SPEAKER_Cs],
+                                    -M_SQRT1_2, nsamples);
+        s->fdsp->vector_fmac_scalar(output_samples[DCA2_SPEAKER_Rs],
+                                    output_samples[DCA2_SPEAKER_Cs],
+                                    -M_SQRT1_2, nsamples);
+    }
+
+    // Undo embedded XXCH downmix
+    if ((s->ext_audio_mask & (DCA2_CSS_XXCH | DCA2_EXSS_XXCH))
+        && s->xxch_dmix_embedded) {
+        float scale_inv = s->xxch_dmix_scale_inv * (1.0f / (1 << 16));
+        int *coeff_ptr  = s->xxch_dmix_coeff;
+        int xch_base    = ff_dca_channels[s->audio_mode];
+        av_assert0(s->nchannels - xch_base <= DCA2_XXCH_CHANNELS_MAX);
+
+        // Undo downmix
+        for (ch = xch_base; ch < s->nchannels; ch++) {
+            int src_spkr = map_prm_ch_to_spkr(s, ch);
+            if (src_spkr < 0)
+                return AVERROR(EINVAL);
+            for (spkr = 0; spkr < s->xxch_mask_nbits; spkr++) {
+                if (s->xxch_dmix_mask[ch - xch_base] & (1U << spkr)) {
+                    int coeff = *coeff_ptr++;
+                    if (coeff) {
+                        s->fdsp->vector_fmac_scalar(output_samples[    spkr],
+                                                    output_samples[src_spkr],
+                                                    coeff * (-1.0f / (1 << 15)),
+                                                    nsamples);
+                    }
+                }
+            }
+        }
+
+        // Undo embedded core downmix pre-scaling
+        for (spkr = 0; spkr < s->xxch_mask_nbits; spkr++) {
+            if (s->xxch_core_mask & (1U << spkr)) {
+                s->fdsp->vector_fmul_scalar(output_samples[spkr],
+                                            output_samples[spkr],
+                                            scale_inv, nsamples);
+            }
+        }
+    }
+
+    // Downmix primary channel set to stereo
+    if (s->request_mask != s->ch_mask) {
+        ff_dca2_downmix_to_stereo_float(s->fdsp, output_samples,
+                                        s->prim_dmix_coeff,
+                                        nsamples, s->ch_mask);
+    }
+
+    return 0;
+}
+
+int ff_dca2_core_filter_frame(DCA2CoreDecoder *s, AVFrame *frame)
+{
+    AVCodecContext *avctx = s->avctx;
+    DCA2Context *dca = avctx->priv_data;
+    enum AVMatrixEncoding matrix_encoding;
+    int ret;
+
+    // Handle downmixing to stereo request
+    if (dca->request_channel_layout == DCA2_SPEAKER_LAYOUT_STEREO
+        && s->audio_mode > AMODE_MONO && s->prim_dmix_embedded
+        && (s->prim_dmix_type == DCA2_DMIX_TYPE_LoRo ||
+            s->prim_dmix_type == DCA2_DMIX_TYPE_LtRt))
+        s->request_mask = DCA2_SPEAKER_LAYOUT_STEREO;
+    else
+        s->request_mask = s->ch_mask;
+    if (!ff_dca2_set_channel_layout(avctx, s->ch_remap, s->request_mask))
+        return AVERROR(EINVAL);
+
+    // Filter the frame
+    if (avctx->flags & AV_CODEC_FLAG_BITEXACT)
+        ret = filter_frame_fixed(s, frame);
+    else
+        ret = filter_frame_float(s, frame);
+    if (ret < 0)
+        return ret;
+
+    // Set profile, bit rate, etc
+    if (s->ext_audio_mask & DCA2_EXSS_MASK)
+        avctx->profile = FF_PROFILE_DTS_HD_HRA;
+    else if (s->ext_audio_mask & (DCA2_CSS_XXCH | DCA2_CSS_XCH))
+        avctx->profile = FF_PROFILE_DTS_ES;
+    else if (s->ext_audio_mask & DCA2_CSS_X96)
+        avctx->profile = FF_PROFILE_DTS_96_24;
+    else
+        avctx->profile = FF_PROFILE_DTS;
+
+    if (s->bit_rate > 3 && !(s->ext_audio_mask & DCA2_EXSS_MASK))
+        avctx->bit_rate = s->bit_rate;
+    else
+        avctx->bit_rate = 0;
+
+    if (s->audio_mode == AMODE_STEREO_TOTAL || (s->request_mask != s->ch_mask &&
+                                                s->prim_dmix_type == DCA2_DMIX_TYPE_LtRt))
+        matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
+    else
+        matrix_encoding = AV_MATRIX_ENCODING_NONE;
+    if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0)
+        return ret;
+
+    return 0;
+}
+
+av_cold void ff_dca2_core_flush(DCA2CoreDecoder *s)
+{
+    if (s->subband_buffer) {
+        erase_adpcm_history(s);
+        memset(s->lfe_samples, 0, DCA2_LFE_HISTORY * sizeof(int));
+    }
+
+    if (s->x96_subband_buffer)
+        erase_x96_adpcm_history(s);
+
+    erase_dsp_history(s);
+}
+
+av_cold int ff_dca2_core_init(DCA2CoreDecoder *s)
+{
+    dca2_init_vlcs();
+
+    if (!(s->fdsp = avpriv_float_dsp_alloc(0)))
+        return AVERROR(ENOMEM);
+
+    ff_synth_filter_init(&s->synth);
+    ff_mdct_init(&s->imdct[0], 6, 1, 1.0);
+    ff_mdct_init(&s->imdct[1], 7, 1, 1.0);
+    ff_dcadsp2_float_init(&s->dcadsp_float);
+    ff_dcadsp2_fixed_init(&s->dcadsp_fixed);
+
+    s->x96_rand = 1;
+    return 0;
+}
+
+av_cold void ff_dca2_core_close(DCA2CoreDecoder *s)
+{
+    av_freep(&s->fdsp);
+
+    ff_mdct_end(&s->imdct[0]);
+    ff_mdct_end(&s->imdct[1]);
+
+    av_freep(&s->subband_buffer);
+    s->subband_size = 0;
+
+    av_freep(&s->x96_subband_buffer);
+    s->x96_subband_size = 0;
+
+    av_freep(&s->output_buffer);
+    s->output_size = 0;
+}
diff --git a/libavcodec/dca2_exss.c b/libavcodec/dca2_exss.c
new file mode 100644
index 0000000..9f5aaf8
--- /dev/null
+++ b/libavcodec/dca2_exss.c
@@ -0,0 +1,500 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca2.h"
+
+static int count_chs_for_mask(int mask)
+{
+    return av_popcount(mask) + av_popcount(mask & 0xae66);
+}
+
+static void parse_xll_parameters(DCA2ExssParser *s, DCA2ExssAsset *asset)
+{
+    // 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;
+
+        // 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;
+    }
+}
+
+static void parse_lbr_parameters(DCA2ExssParser *s, DCA2ExssAsset *asset)
+{
+    // 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);
+}
+
+static int parse_descriptor(DCA2ExssParser *s, DCA2ExssAsset *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);
+
+    //
+    // Per stream static metadata
+    //
+
+    if (s->static_fields_present) {
+        // Asset type descriptor presence
+        if (get_bits1(&s->gb))
+            // Asset type descriptor
+            skip_bits(&s->gb, 4);
+
+        // Language descriptor presence
+        if (get_bits1(&s->gb))
+            // Language descriptor
+            skip_bits(&s->gb, 24);
+
+        // Additional textual information presence
+        if (get_bits1(&s->gb)) {
+            // Byte size of additional text info
+            int text_size = get_bits(&s->gb, 10) + 1;
+
+            // Additional textual information string
+            skip_bits_long(&s->gb, text_size * 8);
+        }
+
+        // PCM bit resolution
+        asset->pcm_bit_res = get_bits(&s->gb, 5) + 1;
+
+        // Maximum sample rate
+        asset->max_sample_rate = ff_dca_sampling_freqs[get_bits(&s->gb, 4)];
+
+        // Total number of channels
+        asset->nchannels_total = get_bits(&s->gb, 8) + 1;
+
+        // 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);
+
+            // 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;
+
+                // 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;
+            }
+
+            // 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 (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(&s->gb, nch_for_remaps);
+
+                    // Loudspeaker remapping codes
+                    skip_bits_long(&s->gb, av_popcount(remap_ch_mask) * 5);
+                }
+            }
+        } else {
+            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, 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))
+        // Dialog normalization code
+        skip_bits(&s->gb, 5);
+
+    // DRC for stereo downmix
+    if (drc_present && asset->embedded_stereo)
+        skip_bits(&s->gb, 8);
+
+    // Mixing metadata presence flag
+    if (s->mix_metadata_enabled && get_bits1(&s->gb)) {
+        int nchannels_dmix;
+
+        // External mixing flag
+        skip_bits1(&s->gb);
+
+        // 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
+            // Limit for mixing DRC
+            skip_bits(&s->gb, 3);
+
+        // 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, 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->nmixoutconfigs; 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);
+            }
+        }
+    }
+
+    //
+    // 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 & DCA2_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 & DCA2_EXSS_XBR)
+            // Size of XBR extension in extension substream
+            asset->xbr_size = get_bits(&s->gb, 14) + 1;
+
+        if (asset->extension_mask & DCA2_EXSS_XXCH)
+            // Size of XXCH extension in extension substream
+            asset->xxch_size = get_bits(&s->gb, 14) + 1;
+
+        if (asset->extension_mask & DCA2_EXSS_X96)
+            // Size of X96 extension in extension substream
+            asset->x96_size = get_bits(&s->gb, 12) + 1;
+
+        if (asset->extension_mask & DCA2_EXSS_LBR)
+            parse_lbr_parameters(s, asset);
+
+        if (asset->extension_mask & DCA2_EXSS_XLL)
+            parse_xll_parameters(s, asset);
+
+        if (asset->extension_mask & DCA2_EXSS_RSV1)
+            skip_bits(&s->gb, 16);
+
+        if (asset->extension_mask & DCA2_EXSS_RSV2)
+            skip_bits(&s->gb, 16);
+        break;
+
+    case 1: // Loss-less coding mode without CBR component
+        asset->extension_mask = DCA2_EXSS_XLL;
+        parse_xll_parameters(s, asset);
+        break;
+
+    case 2: // Low bit rate mode
+        asset->extension_mask = DCA2_EXSS_LBR;
+        parse_lbr_parameters(s, asset);
+        break;
+
+    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;
+    }
+
+    if (asset->extension_mask & DCA2_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_dca2_seek_bits(&s->gb, descr_pos + descr_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of asset descriptor\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int set_exss_offsets(DCA2ExssAsset *asset)
+{
+    int offs = asset->asset_offset;
+    int size = asset->asset_size;
+
+    if (asset->extension_mask & DCA2_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 & DCA2_EXSS_XBR) {
+        asset->xbr_offset = offs;
+        if (asset->xbr_size > size)
+            return AVERROR_INVALIDDATA;
+        offs += asset->xbr_size;
+        size -= asset->xbr_size;
+    }
+
+    if (asset->extension_mask & DCA2_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 & DCA2_EXSS_X96) {
+        asset->x96_offset = offs;
+        if (asset->x96_size > size)
+            return AVERROR_INVALIDDATA;
+        offs += asset->x96_size;
+        size -= asset->x96_size;
+    }
+
+    if (asset->extension_mask & DCA2_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 & DCA2_EXSS_XLL) {
+        asset->xll_offset = offs;
+        if (asset->xll_size > size)
+            return AVERROR_INVALIDDATA;
+        offs += asset->xll_size;
+        size -= asset->xll_size;
+    }
+
+    return 0;
+}
+
+int ff_dca2_exss_parse(DCA2ExssParser *s, uint8_t *data, int size)
+{
+    int i, ret, offset, wide_hdr, header_size;
+
+    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);
+
+    // Extension substream header length
+    header_size = get_bits(&s->gb, 8 + 4 * wide_hdr) + 1;
+
+    // Check CRC
+    if (ff_dca2_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;
+
+        // Number of audio assets in extension substream
+        s->nassets = get_bits(&s->gb, 3) + 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);
+
+        // Active audio asset mask
+        for (i = 0; i < s->npresents; i++)
+            skip_bits_long(&s->gb, av_popcount(active_exss_mask[i]) * 8);
+
+        // Mixing metadata enable flag
+        if (s->mix_metadata_enabled = get_bits1(&s->gb)) {
+            int spkr_mask_nbits;
+
+            // Mixing metadata adjustment level
+            skip_bits(&s->gb, 2);
+
+            // 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;
+    }
+
+    // Reject unsupported features for now
+    if (s->exss_index > 0 || s->npresents != 1 || s->nassets != 1) {
+        av_log(s->avctx, AV_LOG_WARNING, "Multiple sub-streams, audio presentations and/or assets are not supported\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // 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, "Asset out of bounds\n");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    // 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 asset descriptor\n");
+            return ret;
+        }
+    }
+
+    // Backward compatible core present
+    // Backward compatible core substream index
+    // Backward compatible core asset index
+    // Reserved
+    // Byte align
+    // CRC16 of extension substream header
+    if (ff_dca2_seek_bits(&s->gb, header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of EXSS header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
diff --git a/libavcodec/dca2_math.h b/libavcodec/dca2_math.h
new file mode 100644
index 0000000..a13d64d
--- /dev/null
+++ b/libavcodec/dca2_math.h
@@ -0,0 +1,108 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_DCA2_MATH_H
+#define AVCODEC_DCA2_MATH_H
+
+static inline int32_t norm__(int64_t a, int bits)
+{
+    if (bits > 0)
+        return (int32_t)((a + (INT64_C(1) << (bits - 1))) >> bits);
+    else
+        return (int32_t)a;
+}
+
+static inline int32_t mul__(int32_t a, int32_t b, int bits)
+{
+    return norm__((int64_t)a * b, bits);
+}
+
+static inline int32_t norm13(int64_t a) { return norm__(a, 13); }
+static inline int32_t norm16(int64_t a) { return norm__(a, 16); }
+static inline int32_t norm20(int64_t a) { return norm__(a, 20); }
+static inline int32_t norm21(int64_t a) { return norm__(a, 21); }
+static inline int32_t norm23(int64_t a) { return norm__(a, 23); }
+
+static inline int32_t mul3(int32_t a, int32_t b)
+{
+    return (a * b + (1 << 2)) >> 3;
+}
+
+static inline int32_t mul4(int32_t a, int32_t b)
+{
+    return (a * b + (1 << 3)) >> 4;
+}
+
+static inline int32_t mul15(int32_t a, int32_t b) { return mul__(a, b, 15); }
+static inline int32_t mul16(int32_t a, int32_t b) { return mul__(a, b, 16); }
+static inline int32_t mul17(int32_t a, int32_t b) { return mul__(a, b, 17); }
+static inline int32_t mul22(int32_t a, int32_t b) { return mul__(a, b, 22); }
+static inline int32_t mul23(int32_t a, int32_t b) { return mul__(a, b, 23); }
+static inline int32_t mul31(int32_t a, int32_t b) { return mul__(a, b, 31); }
+
+static inline int32_t clip23(int32_t a) { return av_clip_intp2(a, 23); }
+
+static inline void vmul15_sub(int32_t *dst, const int32_t *src, int32_t coeff, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] -= mul15(src[i], coeff);
+}
+
+static inline void vmul15_add(int32_t *dst, const int32_t *src, int32_t coeff, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] += mul15(src[i], coeff);
+}
+
+static inline void vmul22_sub(int32_t *dst, const int32_t *src, int32_t coeff, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] -= mul22(src[i], coeff);
+}
+
+static inline void vmul23_sub(int32_t *dst, const int32_t *src, int32_t coeff, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] -= mul23(src[i], coeff);
+}
+
+static inline void vmul15(int32_t *dst, int32_t scale, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] = mul15(dst[i], scale);
+}
+
+static inline void vmul16(int32_t *dst, int32_t scale, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        dst[i] = mul16(dst[i], scale);
+}
+
+#endif
diff --git a/libavcodec/dca2_xll.c b/libavcodec/dca2_xll.c
new file mode 100644
index 0000000..713f73a
--- /dev/null
+++ b/libavcodec/dca2_xll.c
@@ -0,0 +1,1412 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca2.h"
+#include "dca2_math.h"
+
+static int get_linear(GetBitContext *gb, int n)
+{
+    unsigned int v;
+
+    if (n == 0)
+        return 0;
+
+    v = get_bits(gb, n);
+    return (v >> 1) ^ -(v & 1);
+}
+
+static int get_rice_un(GetBitContext *gb, int k)
+{
+    unsigned int v = get_unary(gb, 1, 128);
+    return k ? (v << k) | get_bits(gb, k) : v;
+}
+
+static int get_rice(GetBitContext *gb, int k)
+{
+    unsigned int v = get_rice_un(gb, k);
+    return (v >> 1) ^ -(v & 1);
+}
+
+static void get_array(GetBitContext *gb, int *array, int size, int n)
+{
+    int i;
+
+    for (i = 0; i < size; i++)
+        array[i] = get_bits(gb, n);
+}
+
+static void get_linear_array(GetBitContext *gb, int *array, int size, int n)
+{
+    int i;
+
+    if (n == 0)
+        memset(array, 0, sizeof(*array) * size);
+    else for (i = 0; i < size; i++)
+        array[i] = get_linear(gb, n);
+}
+
+static void get_rice_array(GetBitContext *gb, int *array, int size, int k)
+{
+    int i;
+
+    for (i = 0; i < size; i++)
+        array[i] = get_rice(gb, k);
+}
+
+static int parse_dmix_coeffs(DCA2XllDecoder *s, DCA2XllChSet *c)
+{
+    int i, j, m, n, *coeff_ptr;
+
+    // Size of downmix coefficient matrix
+    m = c->primary_chset ? ff_dca2_dmix_primary_nch[c->dmix_type] : c->hier_ofs;
+    n = c->nchannels;
+
+    coeff_ptr = c->dmix_coeff;
+    for (i = 0; i < m; i++) {
+        int code, sign, coeff, scale, scale_inv = 0;
+        unsigned int index;
+
+        // Downmix scale (only for non-primary channel sets)
+        if (!c->primary_chset) {
+            code = get_bits(&s->gb, 9);
+            sign = (code >> 8) - 1;
+            index = (code & 0xff) - 41;
+            if (index >= FF_DCA_INV_DMIXTABLE_SIZE) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL downmix scale index\n");
+                return AVERROR_INVALIDDATA;
+            }
+            scale = ff_dca_dmixtable[index + 41];
+            scale_inv = ff_dca_inv_dmixtable[index];
+            c->dmix_scale[i] = (scale ^ sign) - sign;
+            c->dmix_scale_inv[i] = (scale_inv ^ sign) - sign;
+        }
+
+        // Downmix coefficients
+        for (j = 0; j < n; j++) {
+            code = get_bits(&s->gb, 9);
+            sign = (code >> 8) - 1;
+            index = code & 0xff;
+            if (index >= FF_DCA_DMIXTABLE_SIZE) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL downmix coefficient index\n");
+                return AVERROR_INVALIDDATA;
+            }
+            coeff = ff_dca_dmixtable[index];
+            if (!c->primary_chset)
+                // Multiply by |InvDmixScale| to get |UndoDmixScale|
+                coeff = mul16(scale_inv, coeff);
+            *coeff_ptr++ = (coeff ^ sign) - sign;
+        }
+    }
+
+    return 0;
+}
+
+static int chs_parse_header(DCA2XllDecoder *s, DCA2XllChSet *c, DCA2ExssAsset *asset)
+{
+    int i, j, k, ret, band, header_size, header_pos = get_bits_count(&s->gb);
+    DCA2XllChSet *p = &s->chset[0];
+    DCA2XllBand *b;
+
+    // Size of channel set sub-header
+    header_size = get_bits(&s->gb, 10) + 1;
+
+    // Check CRC
+    if (ff_dca2_check_crc(&s->gb, header_pos, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL sub-header checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Number of channels in the channel set
+    c->nchannels = get_bits(&s->gb, 4) + 1;
+    if (c->nchannels > DCA2_XLL_CHANNELS_MAX) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported number of XLL channels (%d)\n", c->nchannels);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Residual type
+    c->residual_encode = get_bits(&s->gb, c->nchannels);
+
+    // PCM bit resolution
+    c->pcm_bit_res = get_bits(&s->gb, 5) + 1;
+
+    // Storage unit width
+    c->storage_bit_res = get_bits(&s->gb, 5) + 1;
+    if (c->storage_bit_res != 16 && c->storage_bit_res != 24) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported storage bit resolution for XLL channel set (%d)", c->storage_bit_res);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    if (c->pcm_bit_res > c->storage_bit_res) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid PCM bit resolution for XLL channel set (%d > %d)", c->pcm_bit_res, c->storage_bit_res);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Original sampling frequency
+    c->freq = ff_dca_sampling_freqs[get_bits(&s->gb, 4)];
+    if (c->freq > 192000) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported XLL sampling frequency (%d)\n", c->freq);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Sampling frequency modifier
+    if (get_bits(&s->gb, 2)) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported XLL sampling frequency modifier\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Which replacement set this channel set is member of
+    if (get_bits(&s->gb, 2)) {
+        av_log(s->avctx, AV_LOG_WARNING, "XLL replacement sets are not supported\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    if (asset->one_to_one_map_ch_to_spkr) {
+        // Primary channel set flag
+        c->primary_chset = get_bits1(&s->gb);
+        if (c->primary_chset != (c == p)) {
+            av_log(s->avctx, AV_LOG_ERROR, "The first (and only) XLL channel set must be primary\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Downmix coefficients present in stream
+        c->dmix_coeffs_present = get_bits1(&s->gb);
+
+        // Downmix already performed by encoder
+        c->dmix_embedded = c->dmix_coeffs_present && get_bits1(&s->gb);
+
+        // Downmix type
+        if (c->dmix_coeffs_present && c->primary_chset) {
+            c->dmix_type = get_bits(&s->gb, 3);
+            if (c->dmix_type >= DCA2_DMIX_TYPE_COUNT) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL primary channel set downmix type\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        // Whether the channel set is part of a hierarchy
+        c->hier_chset = get_bits1(&s->gb);
+        if (!c->hier_chset && s->nchsets != 1) {
+            av_log(s->avctx, AV_LOG_WARNING, "XLL channel sets outside of hierarchy are not supported\n");
+            return AVERROR_PATCHWELCOME;
+        }
+
+        // Downmix coefficients
+        if (c->dmix_coeffs_present && (ret = parse_dmix_coeffs(s, c)) < 0)
+            return ret;
+
+        // Channel mask enabled
+        if (!get_bits1(&s->gb)) {
+            av_log(s->avctx, AV_LOG_WARNING, "XLL channel sets with disabled channel mask are not supported\n");
+            return AVERROR_PATCHWELCOME;
+        }
+
+        // Channel mask for set
+        c->ch_mask = get_bits_long(&s->gb, s->ch_mask_nbits);
+        if (av_popcount(c->ch_mask) != c->nchannels) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL channel mask\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Build the channel to speaker map
+        for (i = 0, j = 0; i < s->ch_mask_nbits; i++)
+            if (c->ch_mask & (1U << i))
+                c->ch_remap[j++] = i;
+    } else {
+        // Mapping coeffs present flag
+        if (c->nchannels != 2 || s->nchsets != 1 || get_bits1(&s->gb)) {
+            av_log(s->avctx, AV_LOG_WARNING, "XLL channel sets with custom channel to speaker mapping are not supported\n");
+            return AVERROR_PATCHWELCOME;
+        }
+
+        // Setup for LtRt decoding
+        c->primary_chset = 1;
+        c->dmix_coeffs_present = 0;
+        c->dmix_embedded = 0;
+        c->hier_chset = 0;
+        c->ch_mask = DCA2_SPEAKER_LAYOUT_STEREO;
+        c->ch_remap[0] = DCA2_SPEAKER_L;
+        c->ch_remap[1] = DCA2_SPEAKER_R;
+    }
+
+    if (c->freq > 96000) {
+        // Extra frequency bands flag
+        if (get_bits1(&s->gb)) {
+            av_log(s->avctx, AV_LOG_WARNING, "Extra XLL frequency bands are not supported\n");
+            return AVERROR_PATCHWELCOME;
+        }
+        c->nfreqbands = 2;
+    } else {
+        c->nfreqbands = 1;
+    }
+
+    // Set the sampling frequency to that of the first frequency band.
+    // Frequency will be doubled again after bands assembly.
+    c->freq >>= c->nfreqbands - 1;
+
+    // Verify that all channel sets have the same audio characteristics
+    if (c != p && (c->freq != p->freq || c->pcm_bit_res != p->pcm_bit_res
+        || c->storage_bit_res != p->storage_bit_res)) {
+        av_log(s->avctx, AV_LOG_WARNING, "XLL channel sets with different audio characteristics are not supported\n");
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Determine number of bits to read bit allocation coding parameter
+    if (c->storage_bit_res > 16)
+        c->nabits = 5;
+    else if (c->storage_bit_res > 8)
+        c->nabits = 4;
+    else
+        c->nabits = 3;
+
+    // Account for embedded downmix and decimator saturation
+    if ((s->nchsets > 1 || c->nfreqbands > 1) && c->nabits < 5)
+        c->nabits++;
+
+    for (band = 0, b = c->bands; band < c->nfreqbands; band++, b++) {
+        // Pairwise channel decorrelation
+        if ((b->decor_enabled = get_bits1(&s->gb)) && c->nchannels > 1) {
+            int ch_nbits = av_ceil_log2(c->nchannels);
+
+            // Original channel order
+            for (i = 0; i < c->nchannels; i++) {
+                b->orig_order[i] = get_bits(&s->gb, ch_nbits);
+                if (b->orig_order[i] >= c->nchannels) {
+                    av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL original channel order\n");
+                    return AVERROR_INVALIDDATA;
+                }
+            }
+
+            // Pairwise channel coefficients
+            for (i = 0; i < c->nchannels / 2; i++)
+                b->decor_coeff[i] = get_bits1(&s->gb) ? get_linear(&s->gb, 7) : 0;
+        } else {
+            for (i = 0; i < c->nchannels; i++)
+                b->orig_order[i] = i;
+            for (i = 0; i < c->nchannels / 2; i++)
+                b->decor_coeff[i] = 0;
+        }
+
+        // Adaptive predictor order
+        b->highest_pred_order = 0;
+        for (i = 0; i < c->nchannels; i++) {
+            b->adapt_pred_order[i] = get_bits(&s->gb, 4);
+            if (b->adapt_pred_order[i] > b->highest_pred_order)
+                b->highest_pred_order = b->adapt_pred_order[i];
+        }
+        if (b->highest_pred_order > s->nsegsamples) {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL adaptive predicition order\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Fixed predictor order
+        for (i = 0; i < c->nchannels; i++)
+            b->fixed_pred_order[i] = b->adapt_pred_order[i] ? 0 : get_bits(&s->gb, 2);
+
+        // Adaptive predictor quantized reflection coefficients
+        for (i = 0; i < c->nchannels; i++) {
+            for (j = 0; j < b->adapt_pred_order[i]; j++) {
+                k = get_linear(&s->gb, 8);
+                if (k == -128) {
+                    av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL reflection coefficient index\n");
+                    return AVERROR_INVALIDDATA;
+                }
+                if (k < 0)
+                    b->adapt_refl_coeff[i][j] = -(int)ff_dca2_xll_refl_coeff[-k];
+                else
+                    b->adapt_refl_coeff[i][j] =  (int)ff_dca2_xll_refl_coeff[ k];
+            }
+        }
+
+        // Downmix performed by encoder in extension frequency band
+        b->dmix_embedded = c->dmix_embedded && (band == 0 || get_bits1(&s->gb));
+
+        // MSB/LSB split flag in extension frequency band
+        if ((band == 0 && s->scalable_lsbs) || (band != 0 && get_bits1(&s->gb))) {
+            // Size of LSB section in any segment
+            b->lsb_section_size = get_bits_long(&s->gb, s->seg_size_nbits);
+            if (b->lsb_section_size < 0 || b->lsb_section_size > s->frame_size) {
+                av_log(s->avctx, AV_LOG_ERROR, "Invalid LSB section size\n");
+                return AVERROR_INVALIDDATA;
+            }
+
+            // Account for optional CRC bytes after LSB section
+            if (b->lsb_section_size && (s->band_crc_present > 2 ||
+                                        (band == 0 && s->band_crc_present > 1)))
+                b->lsb_section_size += 2;
+
+            // Number of bits to represent the samples in LSB part
+            for (i = 0; i < c->nchannels; i++) {
+                b->nscalablelsbs[i] = get_bits(&s->gb, 4);
+                if (b->nscalablelsbs[i] && !b->lsb_section_size) {
+                    av_log(s->avctx, AV_LOG_ERROR, "LSB section missing with non-zero LSB width\n");
+                    return AVERROR_INVALIDDATA;
+                }
+            }
+        } else {
+            b->lsb_section_size = 0;
+            for (i = 0; i < c->nchannels; i++)
+                b->nscalablelsbs[i] = 0;
+        }
+
+        // Scalable resolution flag in extension frequency band
+        if ((band == 0 && s->scalable_lsbs) || (band != 0 && get_bits1(&s->gb))) {
+            // Number of bits discarded by authoring
+            for (i = 0; i < c->nchannels; i++)
+                b->bit_width_adjust[i] = get_bits(&s->gb, 4);
+        } else {
+            for (i = 0; i < c->nchannels; i++)
+                b->bit_width_adjust[i] = 0;
+        }
+    }
+
+    // Reserved
+    // Byte align
+    // CRC16 of channel set sub-header
+    if (ff_dca2_seek_bits(&s->gb, header_pos + header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XLL sub-header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int chs_alloc_msb_band_data(DCA2XllDecoder *s, DCA2XllChSet *c)
+{
+    int ndecisamples = c->nfreqbands > 1 ? DCA2_XLL_DECI_HISTORY_MAX : 0;
+    int nchsamples = s->nframesamples + ndecisamples;
+    int nsamples = nchsamples * c->nchannels * c->nfreqbands;
+    int i, j, *ptr;
+
+    // Reallocate MSB sample buffer
+    av_fast_malloc(&c->sample_buffer[0], &c->sample_size[0], nsamples * sizeof(int));
+    if (!c->sample_buffer[0])
+        return AVERROR(ENOMEM);
+
+    ptr = c->sample_buffer[0] + ndecisamples;
+    for (i = 0; i < c->nfreqbands; i++) {
+        for (j = 0; j < c->nchannels; j++) {
+            c->bands[i].msb_sample_buffer[j] = ptr;
+            ptr += nchsamples;
+        }
+    }
+
+    return 0;
+}
+
+static int chs_alloc_lsb_band_data(DCA2XllDecoder *s, DCA2XllChSet *c)
+{
+    int nsamples = 0;
+    int i, j, *ptr;
+
+    // Determine number of frequency bands that have MSB/LSB split
+    for (i = 0; i < c->nfreqbands; i++)
+        if (c->bands[i].lsb_section_size)
+            nsamples += s->nframesamples * c->nchannels;
+    if (!nsamples)
+        return 0;
+
+    // Reallocate LSB sample buffer
+    av_fast_malloc(&c->sample_buffer[1], &c->sample_size[1], nsamples * sizeof(int));
+    if (!c->sample_buffer[1])
+        return AVERROR(ENOMEM);
+
+    ptr = c->sample_buffer[1];
+    for (i = 0; i < c->nfreqbands; i++) {
+        if (c->bands[i].lsb_section_size) {
+            for (j = 0; j < c->nchannels; j++) {
+                c->bands[i].lsb_sample_buffer[j] = ptr;
+                ptr += s->nframesamples;
+            }
+        } else {
+            for (j = 0; j < c->nchannels; j++)
+                c->bands[i].lsb_sample_buffer[j] = NULL;
+        }
+    }
+
+    return 0;
+}
+
+static int chs_parse_band_data(DCA2XllDecoder *s, DCA2XllChSet *c, int band, int seg, int band_data_end)
+{
+    DCA2XllBand *b = &c->bands[band];
+    int i, j, k;
+
+    // Start unpacking MSB portion of the segment
+    if (!(seg && get_bits1(&s->gb))) {
+        // Unpack segment type
+        // 0 - distinct coding parameters for each channel
+        // 1 - common coding parameters for all channels
+        c->seg_common = get_bits1(&s->gb);
+
+        // Determine number of coding parameters encoded in segment
+        k = c->seg_common ? 1 : c->nchannels;
+
+        // Unpack Rice coding parameters
+        for (i = 0; i < k; i++) {
+            // Unpack Rice coding flag
+            // 0 - linear code, 1 - Rice code
+            c->rice_code_flag[i] = get_bits1(&s->gb);
+            if (!c->seg_common && c->rice_code_flag[i]) {
+                // Unpack Hybrid Rice coding flag
+                // 0 - Rice code, 1 - Hybrid Rice code
+                if (get_bits1(&s->gb))
+                    // Unpack binary code length for isolated samples
+                    c->bitalloc_hybrid_linear[i] = get_bits(&s->gb, c->nabits) + 1;
+                else
+                    // 0 indicates no Hybrid Rice coding
+                    c->bitalloc_hybrid_linear[i] = 0;
+            } else {
+                // 0 indicates no Hybrid Rice coding
+                c->bitalloc_hybrid_linear[i] = 0;
+            }
+        }
+
+        // Unpack coding parameters
+        for (i = 0; i < k; i++) {
+            if (seg == 0) {
+                // Unpack coding parameter for part A of segment 0
+                c->bitalloc_part_a[i] = get_bits(&s->gb, c->nabits);
+
+                // Adjust for the linear code
+                if (!c->rice_code_flag[i] && c->bitalloc_part_a[i])
+                    c->bitalloc_part_a[i]++;
+
+                if (!c->seg_common)
+                    c->nsamples_part_a[i] = b->adapt_pred_order[i];
+                else
+                    c->nsamples_part_a[i] = b->highest_pred_order;
+            } else {
+                c->bitalloc_part_a[i] = 0;
+                c->nsamples_part_a[i] = 0;
+            }
+
+            // Unpack coding parameter for part B of segment
+            c->bitalloc_part_b[i] = get_bits(&s->gb, c->nabits);
+
+            // Adjust for the linear code
+            if (!c->rice_code_flag[i] && c->bitalloc_part_b[i])
+                c->bitalloc_part_b[i]++;
+        }
+    }
+
+    // Unpack entropy codes
+    for (i = 0; i < c->nchannels; i++) {
+        int *part_a, *part_b, nsamples_part_b;
+
+        // Select index of coding parameters
+        k = c->seg_common ? 0 : i;
+
+        // Slice the segment into parts A and B
+        part_a = b->msb_sample_buffer[i] + seg * s->nsegsamples;
+        part_b = part_a + c->nsamples_part_a[k];
+        nsamples_part_b = s->nsegsamples - c->nsamples_part_a[k];
+
+        if (get_bits_left(&s->gb) < 0)
+            return AVERROR_INVALIDDATA;
+
+        if (!c->rice_code_flag[k]) {
+            // Linear codes
+            // Unpack all residuals of part A of segment 0
+            get_linear_array(&s->gb, part_a, c->nsamples_part_a[k],
+                             c->bitalloc_part_a[k]);
+
+            // Unpack all residuals of part B of segment 0 and others
+            get_linear_array(&s->gb, part_b, nsamples_part_b,
+                             c->bitalloc_part_b[k]);
+        } else {
+            // Rice codes
+            // Unpack all residuals of part A of segment 0
+            get_rice_array(&s->gb, part_a, c->nsamples_part_a[k],
+                           c->bitalloc_part_a[k]);
+
+            if (c->bitalloc_hybrid_linear[k]) {
+                // Hybrid Rice codes
+                // Unpack the number of isolated samples
+                int nisosamples = get_bits(&s->gb, s->nsegsamples_log2);
+
+                // Set all locations to 0
+                memset(part_b, 0, sizeof(*part_b) * nsamples_part_b);
+
+                // Extract the locations of isolated samples and flag by -1
+                for (j = 0; j < nisosamples; j++) {
+                    int loc = get_bits(&s->gb, s->nsegsamples_log2);
+                    if (loc >= nsamples_part_b) {
+                        av_log(s->avctx, AV_LOG_ERROR, "Invalid isolated sample location\n");
+                        return AVERROR_INVALIDDATA;
+                    }
+                    part_b[loc] = -1;
+                }
+
+                // Unpack all residuals of part B of segment 0 and others
+                for (j = 0; j < nsamples_part_b; j++) {
+                    if (part_b[j])
+                        part_b[j] = get_linear(&s->gb, c->bitalloc_hybrid_linear[k]);
+                    else
+                        part_b[j] = get_rice(&s->gb, c->bitalloc_part_b[k]);
+                }
+            } else {
+                // Rice codes
+                // Unpack all residuals of part B of segment 0 and others
+                get_rice_array(&s->gb, part_b, nsamples_part_b, c->bitalloc_part_b[k]);
+            }
+        }
+    }
+
+    // Unpack decimator history for frequency band 1
+    if (seg == 0 && band == 1) {
+        int nbits = get_bits(&s->gb, 5) + 1;
+        for (i = 0; i < c->nchannels; i++)
+            for (j = 1; j < DCA2_XLL_DECI_HISTORY_MAX; j++)
+                c->deci_history[i][j] = get_sbits_long(&s->gb, nbits);
+    }
+
+    // Start unpacking LSB portion of the segment
+    if (b->lsb_section_size) {
+        // Skip to the start of LSB portion
+        if (ff_dca2_seek_bits(&s->gb, band_data_end - b->lsb_section_size * 8)) {
+            av_log(s->avctx, AV_LOG_ERROR, "Read past end of band data\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        // Unpack all LSB parts of residuals of this segment
+        for (i = 0; i < c->nchannels; i++) {
+            if (b->nscalablelsbs[i]) {
+                get_array(&s->gb,
+                          b->lsb_sample_buffer[i] + seg * s->nsegsamples,
+                          s->nsegsamples, b->nscalablelsbs[i]);
+            }
+        }
+    }
+
+    // Skip to the end of band data
+    if (ff_dca2_seek_bits(&s->gb, band_data_end)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of band data\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static void av_cold chs_clear_band_data(DCA2XllDecoder *s, DCA2XllChSet *c, int band, int seg)
+{
+    DCA2XllBand *b = &c->bands[band];
+    int i, offset, nsamples;
+
+    if (seg < 0) {
+        offset = 0;
+        nsamples = s->nframesamples;
+    } else {
+        offset = seg * s->nsegsamples;
+        nsamples = s->nsegsamples;
+    }
+
+    for (i = 0; i < c->nchannels; i++) {
+        memset(b->msb_sample_buffer[i] + offset, 0, nsamples * sizeof(int));
+        if (b->lsb_section_size)
+            memset(b->lsb_sample_buffer[i] + offset, 0, nsamples * sizeof(int));
+    }
+
+    if (seg <= 0 && band)
+        memset(c->deci_history, 0, sizeof(c->deci_history));
+
+    if (seg < 0) {
+        memset(b->nscalablelsbs, 0, sizeof(b->nscalablelsbs));
+        memset(b->bit_width_adjust, 0, sizeof(b->bit_width_adjust));
+    }
+}
+
+static void chs_filter_band_data(DCA2XllDecoder *s, DCA2XllChSet *c, int band)
+{
+    DCA2XllBand *b = &c->bands[band];
+    int nsamples = s->nframesamples;
+    int i, j, k;
+
+    // Inverse adaptive or fixed prediction
+    for (i = 0; i < c->nchannels; i++) {
+        int *buf = b->msb_sample_buffer[i];
+        int order = b->adapt_pred_order[i];
+        if (order > 0) {
+            int coeff[DCA2_XLL_ADAPT_PRED_ORDER_MAX];
+            // Conversion from reflection coefficients to direct form coefficients
+            for (j = 0; j < order; j++) {
+                int rc = b->adapt_refl_coeff[i][j];
+                for (k = 0; k < (j + 1) / 2; k++) {
+                    int tmp1 = coeff[    k    ];
+                    int tmp2 = coeff[j - k - 1];
+                    coeff[    k    ] = tmp1 + mul16(rc, tmp2);
+                    coeff[j - k - 1] = tmp2 + mul16(rc, tmp1);
+                }
+                coeff[j] = rc;
+            }
+            // Inverse adaptive prediction
+            for (j = 0; j < nsamples - order; j++) {
+                int64_t err = INT64_C(0);
+                for (k = 0; k < order; k++)
+                    err += (int64_t)buf[j + k] * coeff[order - k - 1];
+                buf[j + k] -= clip23(norm16(err));
+            }
+        } else {
+            // Inverse fixed coefficient prediction
+            for (j = 0; j < b->fixed_pred_order[i]; j++)
+                for (k = 1; k < nsamples; k++)
+                    buf[k] += buf[k - 1];
+        }
+    }
+
+    // Inverse pairwise channel decorrellation
+    if (b->decor_enabled) {
+        int *tmp[DCA2_XLL_CHANNELS_MAX];
+
+        for (i = 0; i < c->nchannels / 2; i++) {
+            int coeff = b->decor_coeff[i];
+            if (coeff) {
+                int *src = b->msb_sample_buffer[i * 2    ];
+                int *dst = b->msb_sample_buffer[i * 2 + 1];
+                for (j = 0; j < nsamples; j++)
+                    dst[j] += mul3(src[j], coeff);
+            }
+        }
+
+        // Reorder channel pointers to the original order
+        for (i = 0; i < c->nchannels; i++)
+            tmp[i] = b->msb_sample_buffer[i];
+
+        for (i = 0; i < c->nchannels; i++)
+            b->msb_sample_buffer[b->orig_order[i]] = tmp[i];
+    }
+
+    // Map output channel pointers for frequency band 0
+    if (c->nfreqbands == 1)
+        for (i = 0; i < c->nchannels; i++)
+            s->output_samples[c->ch_remap[i]] = b->msb_sample_buffer[i];
+
+}
+
+static int chs_get_lsb_width(DCA2XllDecoder *s, DCA2XllChSet *c, int band, int ch)
+{
+    int adj = c->bands[band].bit_width_adjust[ch];
+    int shift = c->bands[band].nscalablelsbs[ch];
+
+    if (s->fixed_lsb_width)
+        shift = s->fixed_lsb_width;
+    else if (shift && adj)
+        shift += adj - 1;
+    else
+        shift += adj;
+
+    return shift;
+}
+
+static void chs_assemble_msbs_lsbs(DCA2XllDecoder *s, DCA2XllChSet *c, int band)
+{
+    DCA2XllBand *b = &c->bands[band];
+    int n, ch, nsamples = s->nframesamples;
+
+    for (ch = 0; ch < c->nchannels; ch++) {
+        int shift = chs_get_lsb_width(s, c, band, ch);
+        if (shift) {
+            int *msb = b->msb_sample_buffer[ch];
+            if (b->nscalablelsbs[ch]) {
+                int *lsb = b->lsb_sample_buffer[ch];
+                int adj = b->bit_width_adjust[ch];
+                for (n = 0; n < nsamples; n++)
+                    msb[n] = msb[n] * (1 << shift) + (lsb[n] << adj);
+            } else {
+                for (n = 0; n < nsamples; n++)
+                    msb[n] = msb[n] * (1 << shift);
+            }
+        }
+    }
+}
+
+static int chs_assemble_freq_bands(DCA2XllDecoder *s, DCA2XllChSet *c)
+{
+    static const int32_t band_coeff1[DCA2_XLL_DECI_HISTORY_MAX] = {
+          -20577,  122631,  -393647,  904476,
+        -1696305, 2825313, -4430736, 6791313
+    };
+
+    static const int32_t band_coeff2[DCA2_XLL_DECI_HISTORY_MAX] = {
+          41153,  -245210,  785564, -1788164,
+        3259333, -5074941, 6928550, -8204883
+    };
+
+    int i, ch, nsamples = s->nframesamples, *ptr;
+
+    // Reallocate frequency band assembly buffer
+    av_fast_malloc(&c->sample_buffer[2], &c->sample_size[2],
+                   2 * nsamples * c->nchannels * sizeof(int));
+    if (!c->sample_buffer[2])
+        return AVERROR(ENOMEM);
+
+    // Assemble frequency bands 0 and 1
+    ptr = c->sample_buffer[2];
+    for (ch = 0; ch < c->nchannels; ch++) {
+        int *band0 = c->bands[0].msb_sample_buffer[ch];
+        int *band1 = c->bands[1].msb_sample_buffer[ch];
+
+        // Copy decimator history
+        for (i = 1; i < DCA2_XLL_DECI_HISTORY_MAX; i++)
+            band0[i - DCA2_XLL_DECI_HISTORY_MAX] = c->deci_history[ch][i];
+
+        // Filter
+        vmul22_sub(band0, band1,   868669, nsamples);
+        vmul22_sub(band1, band0, -5931642, nsamples);
+        vmul22_sub(band0, band1, -1228483, nsamples);
+        vmul22_sub(band1, band0,  1 << 22, nsamples);
+
+        for (i = 0; i < DCA2_XLL_DECI_HISTORY_MAX; i++) {
+            vmul23_sub(band0, band1, band_coeff1[i], nsamples);
+            vmul23_sub(band1, band0, band_coeff2[i], nsamples);
+            vmul23_sub(band0, band1, band_coeff1[i], nsamples);
+            band0--;
+        }
+
+        // Remap output channel pointer to assembly buffer
+        s->output_samples[c->ch_remap[ch]] = ptr;
+
+        // Assemble
+        for (i = 0; i < nsamples; i++) {
+            *ptr++ = *band1++;
+            *ptr++ = *++band0;
+        }
+    }
+
+    return 0;
+}
+
+static int is_hier_dmix_chset(DCA2XllChSet *c)
+{
+    return !c->primary_chset && c->dmix_embedded && c->hier_chset;
+}
+
+static DCA2XllChSet *find_next_hier_dmix_chset(DCA2XllDecoder *s, DCA2XllChSet *c)
+{
+    if (c->hier_chset)
+        while (++c < &s->chset[s->nchsets])
+            if (is_hier_dmix_chset(c))
+                return c;
+
+    return NULL;
+}
+
+static void prescale_down_mix(DCA2XllChSet *c, DCA2XllChSet *o)
+{
+    int i, j, *coeff_ptr = c->dmix_coeff;
+
+    for (i = 0; i < c->hier_ofs; i++) {
+        int scale = o->dmix_scale[i];
+        int scale_inv = o->dmix_scale_inv[i];
+        c->dmix_scale[i] = mul15(c->dmix_scale[i], scale);
+        c->dmix_scale_inv[i] = mul16(c->dmix_scale_inv[i], scale_inv);
+        for (j = 0; j < c->nchannels; j++) {
+            int coeff = mul16(*coeff_ptr, scale_inv);
+            *coeff_ptr++ = mul15(coeff, o->dmix_scale[c->hier_ofs + j]);
+        }
+    }
+}
+
+static void undo_down_mix(DCA2XllDecoder *s, DCA2XllChSet *o, int band)
+{
+    int i, j, k, nchannels = 0, nsamples = s->nframesamples, *coeff_ptr = o->dmix_coeff;
+    DCA2XllChSet *c;
+
+    for (i = 0, c = s->chset; i < s->nactivechsets; i++, c++) {
+        if (!c->hier_chset)
+            continue;
+        for (j = 0; j < c->nchannels; j++) {
+            for (k = 0; k < o->nchannels; k++) {
+                int coeff = *coeff_ptr++;
+                if (coeff) {
+                    vmul15_sub(c->bands[band].msb_sample_buffer[j],
+                               o->bands[band].msb_sample_buffer[k],
+                               coeff, nsamples);
+                    if (band)
+                        vmul15_sub(c->deci_history[j],
+                                   o->deci_history[k],
+                                   coeff, DCA2_XLL_DECI_HISTORY_MAX);
+                }
+            }
+        }
+        nchannels += c->nchannels;
+        if (nchannels >= o->hier_ofs)
+            break;
+    }
+}
+
+static void scale_down_mix(DCA2XllDecoder *s, DCA2XllChSet *o, int band)
+{
+    int i, j, nchannels = 0, nsamples = s->nframesamples;
+    DCA2XllChSet *c;
+
+    for (i = 0, c = s->chset; i < s->nactivechsets; i++, c++) {
+        if (!c->hier_chset)
+            continue;
+        for (j = 0; j < c->nchannels; j++) {
+            int scale = o->dmix_scale[nchannels++];
+            if (scale != (1 << 15)) {
+                vmul15(c->bands[band].msb_sample_buffer[j], scale, nsamples);
+                if (band)
+                    vmul15(c->deci_history[j], scale, DCA2_XLL_DECI_HISTORY_MAX);
+            }
+        }
+        if (nchannels >= o->hier_ofs)
+            break;
+    }
+}
+
+static void av_cold force_lossy_output(DCA2XllDecoder *s, DCA2CoreDecoder *core, DCA2XllChSet *c)
+{
+    int band, ch;
+
+    // Clear all band data
+    for (band = 0; band < c->nfreqbands; band++)
+        chs_clear_band_data(s, c, band, -1);
+
+    // Replace non-residual encoded channels with lossy counterparts
+    for (ch = 0; ch < c->nchannels; ch++) {
+        if (!(c->residual_encode & (1 << ch)))
+            continue;
+        if (ff_dca2_core_map_spkr(core, c->ch_remap[ch]) < 0)
+            continue;
+        c->residual_encode &= ~(1 << ch);
+    }
+}
+
+static void combine_residual_frame(DCA2XllDecoder *s, DCA2CoreDecoder *core, DCA2XllChSet *c)
+{
+    int ch, nsamples = s->nframesamples;
+    DCA2XllChSet *o;
+
+    av_assert0(c->freq == core->output_rate);
+    av_assert0(nsamples == core->npcmsamples);
+
+    // See if this channel set is downmixed and find the next channel set in
+    // hierarchy. If downmixed, undo core pre-scaling before combining with
+    // residual (residual is not scaled).
+    o = find_next_hier_dmix_chset(s, c);
+
+    // Reduce core bit width and combine with residual
+    for (ch = 0; ch < c->nchannels; ch++) {
+        int n, *src, *dst, spkr, shift, round;
+
+        if (c->residual_encode & (1 << ch))
+            continue;
+
+        spkr = ff_dca2_core_map_spkr(core, c->ch_remap[ch]);
+        av_assert0(spkr >= 0);
+
+        // Account for LSB width
+        shift = 24 - c->pcm_bit_res + chs_get_lsb_width(s, c, 0, ch);
+        round = shift > 0 ? 1 << (shift - 1) : 0;
+
+        dst = c->bands[0].msb_sample_buffer[ch];
+        src = core->output_samples[spkr];
+        if (o) {
+            // Undo embedded core downmix pre-scaling
+            int scale_inv = o->dmix_scale_inv[c->hier_ofs + ch];
+            for (n = 0; n < nsamples; n++)
+                dst[n] += clip23((mul16(src[n], scale_inv) + round) >> shift);
+        } else {
+            // No downmix scaling
+            for (n = 0; n < nsamples; n++)
+                dst[n] += (src[n] + round) >> shift;
+        }
+    }
+}
+
+int ff_dca2_xll_filter(DCA2XllDecoder *s)
+{
+    DCA2Context *dca = s->avctx->priv_data;
+    DCA2XllChSet *c;
+    int i, j, ret;
+
+    // Force lossy downmixed output during recovery
+    if (dca->packet & DCA2_PACKET_RECOVERY) {
+        for (i = 0, c = s->chset; i < s->nchsets; i++, c++) {
+            if (i < s->nactivechsets)
+                force_lossy_output(s, &dca->core, c);
+
+            if (!c->primary_chset)
+                c->dmix_embedded = 0;
+        }
+
+        s->scalable_lsbs = 0;
+        s->fixed_lsb_width = 0;
+    }
+
+    // Filter frequency bands for active channel sets
+    s->output_mask = 0;
+    for (i = 0, c = s->chset; i < s->nactivechsets; i++, c++) {
+        chs_filter_band_data(s, c, 0);
+
+        if (c->residual_encode != (1 << c->nchannels) - 1)
+            combine_residual_frame(s, &dca->core, c);
+
+        if (s->scalable_lsbs)
+            chs_assemble_msbs_lsbs(s, c, 0);
+
+        if (c->nfreqbands > 1) {
+            chs_filter_band_data(s, c, 1);
+            chs_assemble_msbs_lsbs(s, c, 1);
+        }
+
+        s->output_mask |= c->ch_mask;
+    }
+
+    // Undo hierarchial downmix and/or apply scaling
+    for (i = 1, c = &s->chset[1]; i < s->nchsets; i++, c++) {
+        if (!is_hier_dmix_chset(c))
+            continue;
+
+        if (i >= s->nactivechsets) {
+            for (j = 0; j < c->nfreqbands; j++)
+                if (c->bands[j].dmix_embedded)
+                    scale_down_mix(s, c, j);
+            break;
+        }
+
+        for (j = 0; j < c->nfreqbands; j++)
+            if (c->bands[j].dmix_embedded)
+                undo_down_mix(s, c, j);
+    }
+
+    // Assemble frequency bands for active channel sets
+    if (s->nfreqbands > 1) {
+        for (i = 0; i < s->nactivechsets; i++)
+            if ((ret = chs_assemble_freq_bands(s, &s->chset[i])) < 0)
+                return ret;
+    }
+
+    // Normalize to regular 5.1 layout if downmixing
+    if (dca->request_channel_layout) {
+        if (s->output_mask & DCA2_SPEAKER_MASK_Lss) {
+            s->output_samples[DCA2_SPEAKER_Ls] = s->output_samples[DCA2_SPEAKER_Lss];
+            s->output_mask = (s->output_mask & ~DCA2_SPEAKER_MASK_Lss) | DCA2_SPEAKER_MASK_Ls;
+        }
+        if (s->output_mask & DCA2_SPEAKER_MASK_Rss) {
+            s->output_samples[DCA2_SPEAKER_Rs] = s->output_samples[DCA2_SPEAKER_Rss];
+            s->output_mask = (s->output_mask & ~DCA2_SPEAKER_MASK_Rss) | DCA2_SPEAKER_MASK_Rs;
+        }
+    }
+
+    return 0;
+}
+
+static int parse_common_header(DCA2XllDecoder *s)
+{
+    int stream_ver, header_size, frame_size_nbits, nframesegs_log2;
+
+    // XLL extension sync word
+    if (get_bits_long(&s->gb, 32) != DCA_SYNCWORD_XLL) {
+        av_log(s->avctx, AV_LOG_VERBOSE, "Invalid XLL sync word\n");
+        return AVERROR(EAGAIN);
+    }
+
+    // Version number
+    stream_ver = get_bits(&s->gb, 4) + 1;
+    if (stream_ver > 1) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported XLL stream version (%d)\n", stream_ver);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Lossless frame header length
+    header_size = get_bits(&s->gb, 8) + 1;
+
+    // Check CRC
+    if (ff_dca2_check_crc(&s->gb, 32, header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL common header checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Number of bits used to read frame size
+    frame_size_nbits = get_bits(&s->gb, 5) + 1;
+
+    // Number of bytes in a lossless frame
+    s->frame_size = get_bits_long(&s->gb, frame_size_nbits);
+    if (s->frame_size < 0 || s->frame_size >= DCA2_XLL_PBR_BUFFER_MAX) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid XLL frame size (%d)\n", s->frame_size);
+        return AVERROR_INVALIDDATA;
+    }
+    s->frame_size++;
+
+    // Number of channels sets per frame
+    s->nchsets = get_bits(&s->gb, 4) + 1;
+    if (s->nchsets > DCA2_XLL_CHSETS_MAX) {
+        av_log(s->avctx, AV_LOG_WARNING, "Unsupported number of XLL channel sets (%d)\n", s->nchsets);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    // Number of segments per frame
+    nframesegs_log2 = get_bits(&s->gb, 4);
+    s->nframesegs = 1 << nframesegs_log2;
+    if (s->nframesegs > 1024) {
+        av_log(s->avctx, AV_LOG_ERROR, "Too many segments per XLL frame\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Samples in segment per one frequency band for the first channel set
+    // Maximum value is 256 for sampling frequencies <= 48 kHz
+    // Maximum value is 512 for sampling frequencies > 48 kHz
+    s->nsegsamples_log2 = get_bits(&s->gb, 4);
+    if (!s->nsegsamples_log2) {
+        av_log(s->avctx, AV_LOG_ERROR, "Too few samples per XLL segment\n");
+        return AVERROR_INVALIDDATA;
+    }
+    s->nsegsamples = 1 << s->nsegsamples_log2;
+    if (s->nsegsamples > 512) {
+        av_log(s->avctx, AV_LOG_ERROR, "Too many samples per XLL segment\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Samples in frame per one frequency band for the first channel set
+    s->nframesamples_log2 = s->nsegsamples_log2 + nframesegs_log2;
+    s->nframesamples = 1 << s->nframesamples_log2;
+    if (s->nframesamples > 65536) {
+        av_log(s->avctx, AV_LOG_ERROR, "Too many samples per XLL frame\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Number of bits used to read segment size
+    s->seg_size_nbits = get_bits(&s->gb, 5) + 1;
+
+    // Presence of CRC16 within each frequency band
+    // 0 - No CRC16 within band
+    // 1 - CRC16 placed at the end of MSB0
+    // 2 - CRC16 placed at the end of MSB0 and LSB0
+    // 3 - CRC16 placed at the end of MSB0 and LSB0 and other frequency bands
+    s->band_crc_present = get_bits(&s->gb, 2);
+
+    // MSB/LSB split flag
+    s->scalable_lsbs = get_bits1(&s->gb);
+
+    // Channel position mask
+    s->ch_mask_nbits = get_bits(&s->gb, 5) + 1;
+
+    // Fixed LSB width
+    if (s->scalable_lsbs)
+        s->fixed_lsb_width = get_bits(&s->gb, 4);
+    else
+        s->fixed_lsb_width = 0;
+
+    // Reserved
+    // Byte align
+    // Header CRC16 protection
+    if (ff_dca2_seek_bits(&s->gb, header_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XLL common header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int parse_sub_headers(DCA2XllDecoder *s, DCA2ExssAsset *asset)
+{
+    DCA2Context *dca = s->avctx->priv_data;
+    DCA2XllChSet *c;
+    int i, ret;
+
+    // Parse channel set headers
+    s->nfreqbands = 0;
+    s->nchannels = 0;
+    for (i = 0, c = s->chset; i < s->nchsets; i++, c++) {
+        c->hier_ofs = s->nchannels;
+        if ((ret = chs_parse_header(s, c, asset)) < 0)
+            return ret;
+        if (c->nfreqbands > s->nfreqbands)
+            s->nfreqbands = c->nfreqbands;
+        if (c->hier_chset)
+            s->nchannels += c->nchannels;
+    }
+
+    // Pre-scale downmixing coefficients for all non-primary channel sets
+    for (i = s->nchsets - 1, c = &s->chset[i]; i > 0; i--, c--) {
+        if (is_hier_dmix_chset(c)) {
+            DCA2XllChSet *o = find_next_hier_dmix_chset(s, c);
+            if (o)
+                prescale_down_mix(c, o);
+        }
+    }
+
+    // Determine number of active channel sets to decode
+    switch (dca->request_channel_layout) {
+    case DCA2_SPEAKER_LAYOUT_STEREO:
+        s->nactivechsets = 1;
+        break;
+    case DCA2_SPEAKER_LAYOUT_5POINT0:
+    case DCA2_SPEAKER_LAYOUT_5POINT1:
+        s->nactivechsets = (s->chset[0].nchannels < 5 && s->nchsets > 1) ? 2 : 1;
+        break;
+    default:
+        s->nactivechsets = s->nchsets;
+        break;
+    }
+
+    return 0;
+}
+
+static int parse_navi_table(DCA2XllDecoder *s)
+{
+    int chs, seg, band, navi_nb, navi_pos, *navi_ptr;
+    DCA2XllChSet *c;
+
+    // Determine size of NAVI table
+    navi_nb = s->nfreqbands * s->nframesegs * s->nchsets;
+    if (navi_nb > 1024) {
+        av_log(s->avctx, AV_LOG_ERROR, "Too many NAVI entries (%d)\n", navi_nb);
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Reallocate NAVI table
+    av_fast_malloc(&s->navi, &s->navi_size, navi_nb * sizeof(*s->navi));
+    if (!s->navi)
+        return AVERROR(ENOMEM);
+
+    // Parse NAVI
+    navi_pos = get_bits_count(&s->gb);
+    navi_ptr = s->navi;
+    for (band = 0; band < s->nfreqbands; band++) {
+        for (seg = 0; seg < s->nframesegs; seg++) {
+            for (chs = 0, c = s->chset; chs < s->nchsets; chs++, c++) {
+                int size = 0;
+                if (c->nfreqbands > band) {
+                    size = get_bits_long(&s->gb, s->seg_size_nbits);
+                    if (size < 0 || size >= s->frame_size) {
+                        av_log(s->avctx, AV_LOG_ERROR, "Invalid NAVI segment size (%d)\n", size);
+                        return AVERROR_INVALIDDATA;
+                    }
+                    size++;
+                }
+                *navi_ptr++ = size;
+            }
+        }
+    }
+
+    // Byte align
+    // CRC16
+    skip_bits(&s->gb, -get_bits_count(&s->gb) & 7);
+    skip_bits(&s->gb, 16);
+
+    // Check CRC
+    if (ff_dca2_check_crc(&s->gb, navi_pos, get_bits_count(&s->gb))) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid NAVI checksum\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int parse_band_data(DCA2XllDecoder *s)
+{
+    int ret, chs, seg, band, navi_pos, *navi_ptr;
+    DCA2XllChSet *c;
+
+    for (chs = 0, c = s->chset; chs < s->nactivechsets; chs++, c++) {
+        if ((ret = chs_alloc_msb_band_data(s, c)) < 0)
+            return ret;
+        if ((ret = chs_alloc_lsb_band_data(s, c)) < 0)
+            return ret;
+    }
+
+    navi_pos = get_bits_count(&s->gb);
+    navi_ptr = s->navi;
+    for (band = 0; band < s->nfreqbands; band++) {
+        for (seg = 0; seg < s->nframesegs; seg++) {
+            for (chs = 0, c = s->chset; chs < s->nchsets; chs++, c++) {
+                if (c->nfreqbands > band) {
+                    navi_pos += *navi_ptr * 8;
+                    if (navi_pos > s->gb.size_in_bits) {
+                        av_log(s->avctx, AV_LOG_ERROR, "Invalid NAVI position\n");
+                        return AVERROR_INVALIDDATA;
+                    }
+                    if (chs < s->nactivechsets &&
+                        (ret = chs_parse_band_data(s, c, band, seg, navi_pos)) < 0) {
+                        if (s->avctx->err_recognition & AV_EF_EXPLODE)
+                            return ret;
+                        chs_clear_band_data(s, c, band, seg);
+                    }
+                    s->gb.index = navi_pos;
+                }
+                navi_ptr++;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int parse_frame(DCA2XllDecoder *s, uint8_t *data, int size, DCA2ExssAsset *asset)
+{
+    int ret;
+
+    if ((ret = init_get_bits8(&s->gb, data, size)) < 0)
+        return ret;
+    if ((ret = parse_common_header(s)) < 0)
+        return ret;
+    if ((ret = parse_sub_headers(s, asset)) < 0)
+        return ret;
+    if ((ret = parse_navi_table(s)) < 0)
+        return ret;
+    if ((ret = parse_band_data(s)) < 0)
+        return ret;
+    if (ff_dca2_seek_bits(&s->gb, s->frame_size * 8)) {
+        av_log(s->avctx, AV_LOG_ERROR, "Read past end of XLL frame\n");
+        return AVERROR_INVALIDDATA;
+    }
+    return ret;
+}
+
+static void clear_pbr(DCA2XllDecoder *s)
+{
+    s->pbr_length = 0;
+    s->pbr_delay = 0;
+}
+
+static int copy_to_pbr(DCA2XllDecoder *s, uint8_t *data, int size, int delay)
+{
+    if (size > DCA2_XLL_PBR_BUFFER_MAX)
+        return AVERROR(ENOSPC);
+
+    if (!s->pbr_buffer && !(s->pbr_buffer = av_malloc(DCA2_XLL_PBR_BUFFER_MAX + DCA2_BUFFER_PADDING_SIZE)))
+        return AVERROR(ENOMEM);
+
+    memcpy(s->pbr_buffer, data, size);
+    s->pbr_length = size;
+    s->pbr_delay = delay;
+    return 0;
+}
+
+static int parse_frame_no_pbr(DCA2XllDecoder *s, uint8_t *data, int size, DCA2ExssAsset *asset)
+{
+    int ret = parse_frame(s, data, size, asset);
+
+    // If XLL packet data didn't start with a sync word, we must have jumped
+    // right into the middle of PBR smoothing period
+    if (ret == AVERROR(EAGAIN) && asset->xll_sync_present && asset->xll_sync_offset < size) {
+        // Skip to the next sync word in this packet
+        data += asset->xll_sync_offset;
+        size -= asset->xll_sync_offset;
+
+        // If decoding delay is set, put the frame into PBR buffer and return
+        // failure code. Higher level decoder is expected to switch to lossy
+        // core decoding or mute its output until decoding delay expires.
+        if (asset->xll_delay_nframes > 0) {
+            if ((ret = copy_to_pbr(s, data, size, asset->xll_delay_nframes)) < 0)
+                return ret;
+            return AVERROR(EAGAIN);
+        }
+
+        // No decoding delay, just parse the frame in place
+        ret = parse_frame(s, data, size, asset);
+    }
+
+    if (ret < 0)
+        return ret;
+
+    if (s->frame_size > size)
+        return AVERROR(EINVAL);
+
+    // If the XLL decoder didn't consume full packet, start PBR smoothing period
+    if (s->frame_size < size)
+        if ((ret = copy_to_pbr(s, data + s->frame_size, size - s->frame_size, 0)) < 0)
+            return ret;
+
+    return 0;
+}
+
+static int parse_frame_pbr(DCA2XllDecoder *s, uint8_t *data, int size, DCA2ExssAsset *asset)
+{
+    int ret;
+
+    if (size > DCA2_XLL_PBR_BUFFER_MAX - s->pbr_length) {
+        ret = AVERROR(ENOSPC);
+        goto fail;
+    }
+
+    memcpy(s->pbr_buffer + s->pbr_length, data, size);
+    s->pbr_length += size;
+
+    // Respect decoding delay after synchronization error
+    if (s->pbr_delay > 0 && --s->pbr_delay)
+        return AVERROR(EAGAIN);
+
+    if ((ret = parse_frame(s, s->pbr_buffer, s->pbr_length, asset)) < 0)
+        goto fail;
+
+    if (s->frame_size > s->pbr_length) {
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    if (s->frame_size == s->pbr_length) {
+        // End of PBR smoothing period
+        clear_pbr(s);
+    } else {
+        s->pbr_length -= s->frame_size;
+        memmove(s->pbr_buffer, s->pbr_buffer + s->frame_size, s->pbr_length);
+    }
+
+    return 0;
+
+fail:
+    // For now, throw out all PBR state on failure.
+    // Perhaps we can be smarter and try to resync somehow.
+    clear_pbr(s);
+    return ret;
+}
+
+int ff_dca2_xll_parse(DCA2XllDecoder *s, uint8_t *data, DCA2ExssAsset *asset)
+{
+    int ret;
+
+    if (s->hd_stream_id != asset->hd_stream_id) {
+        clear_pbr(s);
+        s->hd_stream_id = asset->hd_stream_id;
+    }
+
+    if (s->pbr_length)
+        ret = parse_frame_pbr(s, data + asset->xll_offset, asset->xll_size, asset);
+    else
+        ret = parse_frame_no_pbr(s, data + asset->xll_offset, asset->xll_size, asset);
+
+    return ret;
+}
+
+av_cold void ff_dca2_xll_flush(DCA2XllDecoder *s)
+{
+    clear_pbr(s);
+}
+
+av_cold void ff_dca2_xll_close(DCA2XllDecoder *s)
+{
+    DCA2XllChSet *c;
+    int i, j;
+
+    for (i = 0, c = s->chset; i < DCA2_XLL_CHSETS_MAX; i++, c++) {
+        for (j = 0; j < DCA2_XLL_SAMPLE_BUFFERS_MAX; j++) {
+            av_freep(&c->sample_buffer[j]);
+            c->sample_size[j] = 0;
+        }
+    }
+
+    av_freep(&s->navi);
+    s->navi_size = 0;
+
+    av_freep(&s->pbr_buffer);
+    clear_pbr(s);
+}
diff --git a/libavcodec/dcadata2.c b/libavcodec/dcadata2.c
new file mode 100644
index 0000000..a1cfd73
--- /dev/null
+++ b/libavcodec/dcadata2.c
@@ -0,0 +1,637 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dcadata2.h"
+
+const uint8_t ff_dca2_quant_index_sel_nbits[10] = {
+    1, 2, 2, 2, 2, 3, 3, 3, 3, 3
+};
+
+const uint8_t ff_dca2_block_code_nbits[7] = {
+    7, 10, 12, 13, 15, 17, 19
+};
+
+const uint8_t ff_dca2_dmix_primary_nch[7] = {
+    1, 2, 2, 3, 3, 4, 4
+};
+
+const int32_t ff_dca2_quant_levels[32] = {
+          0,       3,       5,     7,      9,     13,     17,      25,
+         32,      64,     128,   256,    512,   1024,   2048,    4096,
+       8192,   16384,   32768, 65536, 131072, 262144, 524288, 1048576,
+    2097152, 4194304, 8388608,    -1,     -1,     -1,     -1,      -1
+};
+
+const int32_t ff_dca2_scale_factor_adj[4] = {
+    4194304, 4718592, 5242880, 6029312
+};
+
+const int32_t ff_dca2_joint_scale_factors[129] = {
+       3288,    3490,    3691,    3909,    4144,    4387,    4647,    4924,
+       5218,    5528,    5855,    6199,    6568,    6963,    7374,    7810,
+       8271,    8758,    9278,    9831,   10410,   11031,   11685,   12373,
+      13103,   13883,   14705,   15578,   16500,   17482,   18514,   19613,
+      20770,   22003,   23312,   24688,   26156,   27699,   29343,   31080,
+      32925,   34871,   36943,   39133,   41448,   43906,   46506,   49258,
+      52177,   55273,   58544,   62017,   65691,   69584,   73711,   78073,
+      82703,   87602,   92795,   98289,  104111,  110285,  116820,  123740,
+     131072,  138840,  147069,  155776,  165012,  174785,  185145,  196117,
+     207735,  220042,  233086,  246894,  261523,  277017,  293434,  310823,
+     329236,  348748,  369409,  391303,  414490,  439043,  465064,  492621,
+     521805,  552725,  585475,  620170,  656920,  695843,  737073,  780745,
+     827008,  876014,  927923,  982902, 1041144, 1102834, 1168181, 1237404,
+    1310720, 1388382, 1470649, 1557790, 1650098, 1747876, 1851441, 1961147,
+    2077355, 2200441, 2330825, 2468935, 2615232, 2770195, 2934335, 3108206,
+    3292378, 3487463, 3694108, 3913000, 4144862, 4390455, 4650611, 4926176,
+    5218066
+};
+
+const int32_t ff_dca2_band_fir_perfect_fixed[512] = {
+           0,        0,       -3,      -10,
+         -35,     -105,     -218,     -141,
+        -170,     -216,     -239,     -254,
+        -257,     -251,     -235,     -212,
+        -267,     -317,     -362,     -400,
+        -425,     -434,     -427,     -373,
+        -339,     -593,     -321,     -120,
+         -39,      -16,        0,        1,
+           1,        1,       -3,       -1,
+          -6,      -38,      -93,     -496,
+        -723,     -970,    -1235,    -1501,
+       -1753,    -1978,    -2163,    -2295,
+       -2891,    -2915,    -2860,    -2726,
+       -2517,    -2243,    -1915,    -1590,
+       -1192,     -252,     -117,      -22,
+          -6,      -13,       12,       14,
+          32,       25,      469,      942,
+        1403,     1421,     1239,     2838,
+        3539,     4259,     5002,     5716,
+        6365,     6908,     7311,     7545,
+       11680,    12355,    12785,    12951,
+       12841,    12453,    11803,    10864,
+        9762,     7099,     6725,     5954,
+        4284,     2584,      215,      379,
+         557,      701,      -29,     -687,
+       -1578,    -2749,    -4076,    -7933,
+      -10049,   -12133,   -14039,   -15752,
+      -17213,   -18400,   -19291,   -19878,
+       -1444,    -3005,    -4523,    -5927,
+       -7143,    -8093,    -8713,    -8939,
+       -8700,    -9481,    -7515,    -5279,
+       -2725,       61,     5763,     6113,
+        7571,     6735,    17126,    20165,
+       23328,    26775,    30310,    32639,
+       35464,    38064,    40423,    42512,
+       44261,    45632,    46578,    46974,
+      -45572,   -45008,   -43753,   -41661,
+      -38655,   -34660,   -29587,   -23375,
+      -15998,    -7631,     2472,    13757,
+       26188,    39942,    49789,    67293,
+       84699,   101701,   127325,   148404,
+      170391,   193280,   217044,   241451,
+      266537,   292144,   318161,   344417,
+      370786,   397082,   423133,   448757,
+      475085,   499136,   522007,   543516,
+      563424,   581467,   597422,   611005,
+      621975,   630083,   634996,   636457,
+      634311,   628147,   619871,   604524,
+      585077,   561301,   529204,   494129,
+      453552,   407189,   354920,   296502,
+      231916,   161012,    83700,      -86,
+      -90377,  -187193,  -290528,  -400329,
+      516487,   639054,   767835,   902710,
+     1043512,  1190048,  1342100,  1499418,
+     1661729,  1828700,  2000071,  2175433,
+     2354437,  2536630,  2721120,  2908704,
+     3098059,  3288764,  3480801,  3672922,
+     3864970,  4056432,  4246767,  4435454,
+     4621921,  4805642,  4986073,  5162677,
+     5334921,  5502279,  5664239,  5820300,
+     5969913,  6112723,  6248225,  6375985,
+     6495593,  6606663,  6708832,  6801769,
+     6885168,  6958762,  7022294,  7075566,
+     7118382,  7150633,  7172314,  7183082,
+     7183082,  7172314,  7150633,  7118382,
+     7075566,  7022294,  6958762,  6885168,
+     6801769,  6708832,  6606663,  6495593,
+     6375985,  6248225,  6112723,  5969913,
+    -5820300, -5664239, -5502279, -5334921,
+    -5162677, -4986073, -4805642, -4621921,
+    -4435454, -4246767, -4056432, -3864970,
+    -3672922, -3480801, -3288764, -3098059,
+    -2908704, -2721120, -2536630, -2354437,
+    -2175433, -2000071, -1828700, -1661729,
+    -1499418, -1342100, -1190048, -1043512,
+     -902710,  -767835,  -639054,  -516487,
+     -400329,  -290528,  -187193,   -90377,
+         -86,    83700,   161012,   231916,
+      296502,   354920,   407189,   453552,
+      494129,   529204,   561301,   585077,
+      604524,   619871,   628147,   634311,
+      636457,   634996,   630083,   621975,
+      611005,   597422,   581467,   563424,
+      543516,   522007,   499136,   475085,
+     -448757,  -423133,  -397082,  -370786,
+     -344417,  -318161,  -292144,  -266537,
+     -241451,  -217044,  -193280,  -170391,
+     -148404,  -127325,  -101701,   -84699,
+      -67293,   -49789,   -39942,   -26188,
+      -13757,    -2472,     7631,    15998,
+       23375,    29587,    34660,    38655,
+       41661,    43753,    45008,    45572,
+       46974,    46578,    45632,    44261,
+       42512,    40423,    38064,    35464,
+       32639,    30310,    26775,    23328,
+       20165,    17126,     6735,     7571,
+        6113,     5763,       61,    -2725,
+       -5279,    -7515,    -9481,    -8700,
+       -8939,    -8713,    -8093,    -7143,
+       -5927,    -4523,    -3005,    -1444,
+       19878,    19291,    18400,    17213,
+       15752,    14039,    12133,    10049,
+        7933,     4076,     2749,     1578,
+         687,       29,     -701,     -557,
+        -379,     -215,    -2584,    -4284,
+       -5954,    -6725,    -7099,    -9762,
+      -10864,   -11803,   -12453,   -12841,
+      -12951,   -12785,   -12355,   -11680,
+        7545,     7311,     6908,     6365,
+        5716,     5002,     4259,     3539,
+        2838,     1239,     1421,     1403,
+         942,      469,       25,       32,
+          14,       12,      -13,       -6,
+         -22,     -117,     -252,    -1192,
+       -1590,    -1915,    -2243,    -2517,
+       -2726,    -2860,    -2915,    -2891,
+        2295,     2163,     1978,     1753,
+        1501,     1235,      970,      723,
+         496,       93,       38,        6,
+           1,        3,       -1,       -1,
+          -1,        0,       16,       39,
+         120,      321,      593,      339,
+         373,      427,      434,      425,
+         400,      362,      317,      267,
+        -212,     -235,     -251,     -257,
+        -254,     -239,     -216,     -170,
+        -141,     -218,     -105,      -35,
+         -10,       -3,        0,        0
+};
+
+const int32_t ff_dca2_band_fir_nonperfect_fixed[512] = {
+         -53,      -64,      -77,      -91,
+        -107,     -124,     -144,     -165,
+        -189,     -215,     -244,     -277,
+        -313,     -353,     -397,     -447,
+         502,      563,      631,      706,
+         789,      881,      983,     1095,
+        1218,     1354,     1502,     1665,
+        1843,     2036,     2247,     2475,
+        2723,     2990,     3277,     3586,
+        3916,     4270,     4646,     5046,
+        5470,     5918,     6390,     6886,
+        7405,     7947,     8510,     9094,
+        9698,    10319,    10955,    11605,
+       12265,    12933,    13605,    14277,
+       14945,    15604,    16250,    16877,
+       17480,    18051,    18585,    19075,
+       19513,    19891,    20202,    20436,
+       20587,    20643,    20597,    20439,
+       20160,    19749,    19198,    18496,
+       17634,    16603,    15393,    13996,
+      -12403,   -10605,    -8595,    -6366,
+       -3911,    -1225,     1697,     4860,
+        8265,    11916,    15812,    19953,
+       24337,    28961,    33819,    38904,
+       44210,    49725,    55437,    61334,
+       67398,    73614,    79961,    86417,
+       92960,    99563,   106198,   112837,
+      119446,   125994,   132443,   138758,
+      144898,   150823,   156491,   161858,
+      166879,   171507,   175697,   179400,
+      182566,   185149,   187097,   188363,
+      188899,   188654,   187581,   185635,
+      182770,   178943,   174112,   168238,
+      161285,   153218,   144007,   133624,
+      122046,   109254,    95232,    79969,
+       63462,    45709,    26715,     6492,
+       14943,    37567,    61350,    86256,
+      112242,   139258,   167246,   196143,
+      225877,   256368,   287532,   319275,
+      351496,   384088,   416936,   449919,
+      482909,   515770,   548362,   580539,
+      612148,   643030,   673024,   701963,
+      729674,   755985,   780717,   803690,
+      824721,   843628,   860226,   874332,
+      885761,   894330,   899861,   902174,
+      901096,   896456,   888088,   875832,
+      859535,   839050,   814237,   784966,
+      751116,   712574,   669239,   621021,
+      567840,   509632,   446341,   377927,
+      304365,   225641,   141757,    52732,
+      -41403,  -140599,  -244793,  -353905,
+     -467840,  -586486,  -709716,  -837385,
+      969336,  1105393,  1245366,  1389049,
+     1536224,  1686655,  1840096,  1996285,
+     2154949,  2315802,  2478547,  2642877,
+     2808475,  2975015,  3142163,  3309579,
+     3476914,  3643818,  3809934,  3974901,
+     4138360,  4299948,  4459303,  4616064,
+     4769873,  4920374,  5067219,  5210063,
+     5348569,  5482406,  5611255,  5734805,
+     5852757,  5964823,  6070729,  6170216,
+     6263037,  6348961,  6427777,  6499286,
+     6563310,  6619688,  6668279,  6708963,
+     6741632,  6766206,  6782623,  6790843,
+     6790843,  6782623,  6766206,  6741632,
+     6708963,  6668279,  6619688,  6563310,
+     6499286,  6427777,  6348961,  6263037,
+     6170216,  6070729,  5964823,  5852757,
+    -5734805, -5611255, -5482406, -5348569,
+    -5210063, -5067219, -4920374, -4769873,
+    -4616064, -4459303, -4299948, -4138360,
+    -3974901, -3809934, -3643818, -3476914,
+    -3309579, -3142163, -2975015, -2808475,
+    -2642877, -2478547, -2315802, -2154949,
+    -1996285, -1840096, -1686655, -1536224,
+    -1389049, -1245366, -1105393,  -969336,
+     -837385,  -709716,  -586486,  -467840,
+     -353905,  -244793,  -140599,   -41403,
+       52732,   141757,   225641,   304365,
+      377927,   446341,   509632,   567840,
+      621021,   669239,   712574,   751116,
+      784966,   814237,   839050,   859535,
+      875832,   888088,   896456,   901096,
+      902174,   899861,   894330,   885761,
+     -874332,  -860226,  -843628,  -824721,
+     -803690,  -780717,  -755985,  -729674,
+     -701963,  -673024,  -643030,  -612148,
+     -580539,  -548362,  -515770,  -482909,
+     -449919,  -416936,  -384088,  -351496,
+     -319275,  -287532,  -256368,  -225877,
+     -196143,  -167246,  -139258,  -112242,
+      -86256,   -61350,   -37567,   -14943,
+        6492,    26715,    45709,    63462,
+       79969,    95232,   109254,   122046,
+      133624,   144007,   153218,   161285,
+      168238,   174112,   178943,   182770,
+      185635,   187581,   188654,   188899,
+      188363,   187097,   185149,   182566,
+      179400,   175697,   171507,   166879,
+      161858,   156491,   150823,   144898,
+     -138758,  -132443,  -125994,  -119446,
+     -112837,  -106198,   -99563,   -92960,
+      -86417,   -79961,   -73614,   -67398,
+      -61334,   -55437,   -49725,   -44210,
+      -38904,   -33819,   -28961,   -24337,
+      -19953,   -15812,   -11916,    -8265,
+       -4860,    -1697,     1225,     3911,
+        6366,     8595,    10605,    12403,
+       13996,    15393,    16603,    17634,
+       18496,    19198,    19749,    20160,
+       20439,    20597,    20643,    20587,
+       20436,    20202,    19891,    19513,
+       19075,    18585,    18051,    17480,
+       16877,    16250,    15604,    14945,
+       14277,    13605,    12933,    12265,
+       11605,    10955,    10319,     9698,
+       -9094,    -8510,    -7947,    -7405,
+       -6886,    -6390,    -5918,    -5470,
+       -5046,    -4646,    -4270,    -3916,
+       -3586,    -3277,    -2990,    -2723,
+       -2475,    -2247,    -2036,    -1843,
+       -1665,    -1502,    -1354,    -1218,
+       -1095,     -983,     -881,     -789,
+        -706,     -631,     -563,     -502,
+        -447,     -397,     -353,     -313,
+        -277,     -244,     -215,     -189,
+        -165,     -144,     -124,     -107,
+         -91,      -77,      -64,      -53
+};
+
+const int32_t ff_dca2_lfe_fir_64_fixed[256] = {
+     6103,   52170, -558064, 1592440, 6290049, 1502534, -546669, 53047,
+     1930,   51089, -568920, 1683709, 6286575, 1414057, -534782, 53729,
+     2228,   49794, -579194, 1776276, 6279634, 1327070, -522445, 54228,
+     2552,   48275, -588839, 1870070, 6269231, 1241632, -509702, 54550,
+     2904,   46523, -597808, 1965017, 6255380, 1157798, -496595, 54708,
+     3287,   44529, -606054, 2061044, 6238099, 1075621, -483164, 54710,
+     3704,   42282, -613529, 2158071, 6217408,  995149, -469451, 54566,
+     4152,   39774, -620186, 2256019, 6193332,  916430, -455494, 54285,
+     4631,   36995, -625976, 2354805, 6165900,  839507, -441330, 53876,
+     5139,   33937, -630850, 2454343, 6135146,  764419, -426998, 53348,
+     5682,   30591, -634759, 2554547, 6101107,  691203, -412531, 52711,
+     6264,   26948, -637655, 2655326, 6063824,  619894, -397966, 51972,
+     6886,   23001, -639488, 2756591, 6023343,  550521, -383335, 51140,
+     7531,   18741, -640210, 2858248, 5979711,  483113, -368671, 50224,
+     8230,   14162, -639772, 2960201, 5932981,  417692, -354003, 49231,
+     8959,    9257, -638125, 3062355, 5883210,  354281, -339362, 48168,
+     9727,    4018, -635222, 3164612, 5830457,  292897, -324777, 47044,
+    10535,   -1558, -631014, 3266872, 5774785,  233555, -310273, 45866,
+    11381,   -7480, -625455, 3369035, 5716260,  176267, -295877, 44640,
+    12267,  -13750, -618499, 3471000, 5654952,  121042, -281613, 43373,
+    13190,  -20372, -610098, 3572664, 5590933,   67886, -267505, 42072,
+    14152,  -27352, -600209, 3673924, 5524280,   16800, -253574, 40743,
+    15153,  -34691, -588788, 3774676, 5455069,  -32214, -239840, 39391,
+    16192,  -42390, -575791, 3874816, 5383383,  -79159, -226323, 38022,
+    17267,  -50453, -561178, 3974239, 5309305, -124041, -213041, 36642,
+    18377,  -58879, -544906, 4072841, 5232922, -166869, -200010, 35256,
+    19525,  -67667, -526937, 4170517, 5154321, -207653, -187246, 33866,
+    20704,  -76817, -507233, 4267162, 5073593, -246406, -174764, 32480,
+    21915,  -86327, -485757, 4362672, 4990831, -283146, -162575, 31101,
+    23157,  -96193, -462476, 4456942, 4906129, -317890, -150692, 29732,
+    24426, -106412, -437356, 4549871, 4819584, -350658, -139125, 28376,
+    25721, -116977, -410365, 4641355, 4731293, -381475, -127884, 27038
+};
+
+const int32_t ff_dca2_band_fir_x96_fixed[1024] = {
+         -38,      -38,      -43,      -48,
+         -52,      -57,      -62,      -67,
+         -73,      -79,      -85,      -91,
+         -98,     -105,     -113,     -121,
+        -129,     -138,     -147,     -157,
+        -167,     -178,     -190,     -202,
+        -215,     -228,     -242,     -257,
+        -273,     -289,     -307,     -325,
+         345,      365,      387,      410,
+         433,      459,      485,      513,
+         543,      574,      606,      640,
+         676,      714,      753,      795,
+         839,      884,      932,      983,
+        1035,     1090,     1148,     1208,
+        1271,     1336,     1405,     1476,
+        1550,     1628,     1709,     1793,
+        1880,     1971,     2065,     2163,
+        2265,     2370,     2479,     2592,
+        2709,     2830,     2955,     3084,
+        3217,     3354,     3496,     3642,
+        3791,     3946,     4104,     4267,
+        4433,     4604,     4780,     4959,
+        5143,     5330,     5522,     5717,
+        5916,     6119,     6326,     6536,
+        6749,     6966,     7186,     7408,
+        7633,     7861,     8090,     8322,
+        8556,     8791,     9027,     9264,
+        9501,     9739,     9977,    10214,
+       10450,    10685,    10918,    11149,
+       11377,    11603,    11825,    12042,
+       12255,    12463,    12665,    12861,
+       13050,    13231,    13405,    13569,
+       13724,    13869,    14002,    14125,
+       14235,    14331,    14415,    14483,
+       14536,    14573,    14594,    14596,
+       14580,    14544,    14488,    14412,
+       14313,    14191,    14046,    13877,
+       13682,    13461,    13213,    12937,
+       12632,    12298,    11934,    11538,
+       11111,    10650,    10156,     9628,
+       -9065,    -8466,    -7830,    -7158,
+       -6447,    -5698,    -4910,    -4083,
+       -3215,    -2306,    -1357,     -366,
+         668,     1743,     2861,     4022,
+        5226,     6474,     7764,     9098,
+       10476,    11897,    13361,    14868,
+       16418,    18011,    19645,    21322,
+       23039,    24798,    26596,    28433,
+       30309,    32222,    34172,    36158,
+       38177,    40231,    42315,    44431,
+       46575,    48747,    50945,    53167,
+       55411,    57676,    59959,    62258,
+       64571,    66897,    69231,    71573,
+       73919,    76268,    78615,    80959,
+       83296,    85624,    87939,    90239,
+       92519,    94778,    97011,    99215,
+      101386,   103521,   105616,   107668,
+      109673,   111626,   113524,   115362,
+      117138,   118847,   120484,   122045,
+      123527,   124925,   126234,   127451,
+      128571,   129591,   130504,   131308,
+      131997,   132568,   133016,   133338,
+      133528,   133582,   133495,   133265,
+      132886,   132355,   131668,   130820,
+      129807,   128626,   127274,   125746,
+      124038,   122148,   120071,   117806,
+      115348,   112694,   109843,   106790,
+      103534,   100071,    96401,    92520,
+       88426,    84119,    79597,    74857,
+       69900,    64723,    59327,    53711,
+       47875,    41818,    35542,    29045,
+       22330,    15397,     8247,      881,
+        6697,    14487,    22487,    30692,
+       39101,    47711,    56517,    65516,
+       74704,    84076,    93628,   103355,
+      113251,   123311,   133528,   143897,
+      154410,   165061,   175843,   186747,
+      197766,   208892,   220116,   231429,
+      242822,   254285,   265810,   277384,
+      288999,   300644,   312306,   323976,
+      335641,   347289,   358909,   370488,
+      382013,   393471,   404848,   416133,
+      427310,   438366,   449286,   460057,
+      470663,   481090,   491323,   501347,
+      511147,   520707,   530011,   539044,
+      547790,   556233,   564357,   572146,
+      579584,   586654,   593341,   599627,
+      605498,   610936,   615925,   620449,
+      624491,   628037,   631069,   633571,
+      635529,   636925,   637745,   637972,
+      637593,   636592,   634953,   632662,
+      629705,   626068,   621737,   616698,
+      610938,   604443,   597202,   589202,
+      580431,   570877,   560530,   549378,
+      537411,   524620,   510994,   496525,
+      481205,   465026,   447979,   430058,
+      411256,   391569,   370989,   349514,
+      327137,   303857,   279670,   254573,
+      228564,   201644,   173811,   145065,
+      115408,    84840,    53365,    20984,
+      -12298,   -46478,   -81550,  -117508,
+     -154347,  -192060,  -230638,  -270073,
+     -310356,  -351478,  -393427,  -436192,
+     -479762,  -524124,  -569264,  -615168,
+      661821,   709209,   757314,   806121,
+      855611,   905766,   956569,  1007998,
+     1060035,  1112658,  1165846,  1219578,
+     1273830,  1328580,  1383805,  1439479,
+     1495578,  1552077,  1608950,  1666171,
+     1723714,  1781550,  1839653,  1897995,
+     1956546,  2015279,  2074163,  2133170,
+     2192270,  2251432,  2310626,  2369822,
+     2428988,  2488093,  2547106,  2605996,
+     2664731,  2723279,  2781607,  2839685,
+     2897481,  2954962,  3012096,  3068851,
+     3125195,  3181097,  3236524,  3291445,
+     3345829,  3399643,  3452858,  3505441,
+     3557362,  3608591,  3659098,  3708853,
+     3757825,  3805987,  3853309,  3899763,
+     3945322,  3989957,  4033642,  4076350,
+     4118055,  4158733,  4198357,  4236904,
+     4274351,  4310673,  4345850,  4379859,
+     4412678,  4444289,  4474670,  4503803,
+     4531671,  4558255,  4583539,  4607508,
+     4630146,  4651438,  4671373,  4689936,
+     4707117,  4722905,  4737290,  4750262,
+     4761813,  4771936,  4780625,  4787874,
+     4793679,  4798036,  4800943,  4802396,
+     4802396,  4800943,  4798036,  4793679,
+     4787874,  4780625,  4771936,  4761813,
+     4750262,  4737290,  4722905,  4707117,
+     4689936,  4671373,  4651438,  4630146,
+     4607508,  4583539,  4558255,  4531671,
+     4503803,  4474670,  4444289,  4412678,
+     4379859,  4345850,  4310673,  4274351,
+     4236904,  4198357,  4158733,  4118055,
+    -4076350, -4033642, -3989957, -3945322,
+    -3899763, -3853309, -3805987, -3757825,
+    -3708853, -3659098, -3608591, -3557362,
+    -3505441, -3452858, -3399643, -3345829,
+    -3291445, -3236524, -3181097, -3125195,
+    -3068851, -3012096, -2954962, -2897481,
+    -2839685, -2781607, -2723279, -2664731,
+    -2605996, -2547106, -2488093, -2428988,
+    -2369822, -2310626, -2251432, -2192270,
+    -2133170, -2074163, -2015279, -1956546,
+    -1897995, -1839653, -1781550, -1723714,
+    -1666171, -1608950, -1552077, -1495578,
+    -1439479, -1383805, -1328580, -1273830,
+    -1219578, -1165846, -1112658, -1060035,
+    -1007998,  -956569,  -905766,  -855611,
+     -806121,  -757314,  -709209,  -661821,
+     -615168,  -569264,  -524124,  -479762,
+     -436192,  -393427,  -351478,  -310356,
+     -270073,  -230638,  -192060,  -154347,
+     -117508,   -81550,   -46478,   -12298,
+       20984,    53365,    84840,   115408,
+      145065,   173811,   201644,   228564,
+      254573,   279670,   303857,   327137,
+      349514,   370989,   391569,   411256,
+      430058,   447979,   465026,   481205,
+      496525,   510994,   524620,   537411,
+      549378,   560530,   570877,   580431,
+      589202,   597202,   604443,   610938,
+      616698,   621737,   626068,   629705,
+      632662,   634953,   636592,   637593,
+      637972,   637745,   636925,   635529,
+      633571,   631069,   628037,   624491,
+     -620449,  -615925,  -610936,  -605498,
+     -599627,  -593341,  -586654,  -579584,
+     -572146,  -564357,  -556233,  -547790,
+     -539044,  -530011,  -520707,  -511147,
+     -501347,  -491323,  -481090,  -470663,
+     -460057,  -449286,  -438366,  -427310,
+     -416133,  -404848,  -393471,  -382013,
+     -370488,  -358909,  -347289,  -335641,
+     -323976,  -312306,  -300644,  -288999,
+     -277384,  -265810,  -254285,  -242822,
+     -231429,  -220116,  -208892,  -197766,
+     -186747,  -175843,  -165061,  -154410,
+     -143897,  -133528,  -123311,  -113251,
+     -103355,   -93628,   -84076,   -74704,
+      -65516,   -56517,   -47711,   -39101,
+      -30692,   -22487,   -14487,    -6697,
+         881,     8247,    15397,    22330,
+       29045,    35542,    41818,    47875,
+       53711,    59327,    64723,    69900,
+       74857,    79597,    84119,    88426,
+       92520,    96401,   100071,   103534,
+      106790,   109843,   112694,   115348,
+      117806,   120071,   122148,   124038,
+      125746,   127274,   128626,   129807,
+      130820,   131668,   132355,   132886,
+      133265,   133495,   133582,   133528,
+      133338,   133016,   132568,   131997,
+      131308,   130504,   129591,   128571,
+      127451,   126234,   124925,   123527,
+      122045,   120484,   118847,   117138,
+      115362,   113524,   111626,   109673,
+      107668,   105616,   103521,   101386,
+      -99215,   -97011,   -94778,   -92519,
+      -90239,   -87939,   -85624,   -83296,
+      -80959,   -78615,   -76268,   -73919,
+      -71573,   -69231,   -66897,   -64571,
+      -62258,   -59959,   -57676,   -55411,
+      -53167,   -50945,   -48747,   -46575,
+      -44431,   -42315,   -40231,   -38177,
+      -36158,   -34172,   -32222,   -30309,
+      -28433,   -26596,   -24798,   -23039,
+      -21322,   -19645,   -18011,   -16418,
+      -14868,   -13361,   -11897,   -10476,
+       -9098,    -7764,    -6474,    -5226,
+       -4022,    -2861,    -1743,     -668,
+         366,     1357,     2306,     3215,
+        4083,     4910,     5698,     6447,
+        7158,     7830,     8466,     9065,
+        9628,    10156,    10650,    11111,
+       11538,    11934,    12298,    12632,
+       12937,    13213,    13461,    13682,
+       13877,    14046,    14191,    14313,
+       14412,    14488,    14544,    14580,
+       14596,    14594,    14573,    14536,
+       14483,    14415,    14331,    14235,
+       14125,    14002,    13869,    13724,
+       13569,    13405,    13231,    13050,
+       12861,    12665,    12463,    12255,
+       12042,    11825,    11603,    11377,
+       11149,    10918,    10685,    10450,
+       10214,     9977,     9739,     9501,
+        9264,     9027,     8791,     8556,
+        8322,     8090,     7861,     7633,
+        7408,     7186,     6966,     6749,
+       -6536,    -6326,    -6119,    -5916,
+       -5717,    -5522,    -5330,    -5143,
+       -4959,    -4780,    -4604,    -4433,
+       -4267,    -4104,    -3946,    -3791,
+       -3642,    -3496,    -3354,    -3217,
+       -3084,    -2955,    -2830,    -2709,
+       -2592,    -2479,    -2370,    -2265,
+       -2163,    -2065,    -1971,    -1880,
+       -1793,    -1709,    -1628,    -1550,
+       -1476,    -1405,    -1336,    -1271,
+       -1208,    -1148,    -1090,    -1035,
+        -983,     -932,     -884,     -839,
+        -795,     -753,     -714,     -676,
+        -640,     -606,     -574,     -543,
+        -513,     -485,     -459,     -433,
+        -410,     -387,     -365,     -345,
+        -325,     -307,     -289,     -273,
+        -257,     -242,     -228,     -215,
+        -202,     -190,     -178,     -167,
+        -157,     -147,     -138,     -129,
+        -121,     -113,     -105,      -98,
+         -91,      -85,      -79,      -73,
+         -67,      -62,      -57,      -52,
+         -48,      -43,      -38,      -38
+};
+
+const uint16_t ff_dca2_xll_refl_coeff[128] = {
+        0,  3070,  5110,  7140,  9156, 11154, 13132, 15085,
+    17010, 18904, 20764, 22588, 24373, 26117, 27818, 29474,
+    31085, 32648, 34164, 35631, 37049, 38418, 39738, 41008,
+    42230, 43404, 44530, 45609, 46642, 47630, 48575, 49477,
+    50337, 51157, 51937, 52681, 53387, 54059, 54697, 55302,
+    55876, 56421, 56937, 57426, 57888, 58326, 58741, 59132,
+    59502, 59852, 60182, 60494, 60789, 61066, 61328, 61576,
+    61809, 62029, 62236, 62431, 62615, 62788, 62951, 63105,
+    63250, 63386, 63514, 63635, 63749, 63855, 63956, 64051,
+    64140, 64224, 64302, 64376, 64446, 64512, 64573, 64631,
+    64686, 64737, 64785, 64830, 64873, 64913, 64950, 64986,
+    65019, 65050, 65079, 65107, 65133, 65157, 65180, 65202,
+    65222, 65241, 65259, 65275, 65291, 65306, 65320, 65333,
+    65345, 65357, 65368, 65378, 65387, 65396, 65405, 65413,
+    65420, 65427, 65434, 65440, 65446, 65451, 65456, 65461,
+    65466, 65470, 65474, 65478, 65481, 65485, 65488, 65491
+};
diff --git a/libavcodec/dcadata2.h b/libavcodec/dcadata2.h
new file mode 100644
index 0000000..f2b7f6e
--- /dev/null
+++ b/libavcodec/dcadata2.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_DCADATA2_H
+#define AVCODEC_DCADATA2_H
+
+#include <stdint.h>
+
+extern const uint8_t ff_dca2_quant_index_sel_nbits[10];
+extern const uint8_t ff_dca2_block_code_nbits[7];
+extern const uint8_t ff_dca2_dmix_primary_nch[7];
+extern const int32_t ff_dca2_quant_levels[32];
+extern const int32_t ff_dca2_scale_factor_adj[4];
+extern const int32_t ff_dca2_joint_scale_factors[129];
+extern const int32_t ff_dca2_band_fir_perfect_fixed[512];
+extern const int32_t ff_dca2_band_fir_nonperfect_fixed[512];
+extern const int32_t ff_dca2_lfe_fir_64_fixed[256];
+extern const int32_t ff_dca2_band_fir_x96_fixed[1024];
+extern const uint16_t ff_dca2_xll_refl_coeff[128];
+
+#endif
diff --git a/libavcodec/dcadec2.c b/libavcodec/dcadec2.c
new file mode 100644
index 0000000..9169457
--- /dev/null
+++ b/libavcodec/dcadec2.c
@@ -0,0 +1,542 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca.h"    // for avpriv_dca_convert_bitstream()
+#include "dca2.h"
+#include "dca2_math.h"
+
+#define MIN_PACKET_SIZE     16
+#define MAX_PACKET_SIZE     0x104000
+
+int ff_dca2_set_channel_layout(AVCodecContext *avctx, int *ch_remap, int dca_mask)
+{
+    static const uint8_t dca2wav_norm[28] = {
+         2,  0, 1, 9, 10,  3,  8,  4,  5,  9, 10, 6, 7, 12,
+        13, 14, 3, 6,  7, 11, 12, 14, 16, 15, 17, 8, 4,  5,
+    };
+
+    static const uint8_t dca2wav_wide[28] = {
+         2,  0, 1, 4,  5,  3,  8,  4,  5,  9, 10, 6, 7, 12,
+        13, 14, 3, 9, 10, 11, 12, 14, 16, 15, 17, 8, 4,  5,
+    };
+
+    int dca_ch, wav_ch, nchannels = 0;
+
+    if (avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE) {
+        for (dca_ch = 0; dca_ch < DCA2_SPEAKER_COUNT; dca_ch++)
+            if (dca_mask & (1U << dca_ch))
+                ch_remap[nchannels++] = dca_ch;
+        avctx->channel_layout = dca_mask;
+    } else {
+        int wav_mask = 0;
+        int wav_map[18];
+        const uint8_t *dca2wav;
+        if (dca_mask == DCA2_SPEAKER_LAYOUT_7POINT0_WIDE ||
+            dca_mask == DCA2_SPEAKER_LAYOUT_7POINT1_WIDE)
+            dca2wav = dca2wav_wide;
+        else
+            dca2wav = dca2wav_norm;
+        for (dca_ch = 0; dca_ch < 28; dca_ch++) {
+            if (dca_mask & (1 << dca_ch)) {
+                wav_ch = dca2wav[dca_ch];
+                if (!(wav_mask & (1 << wav_ch))) {
+                    wav_map[wav_ch] = dca_ch;
+                    wav_mask |= 1 << wav_ch;
+                }
+            }
+        }
+        for (wav_ch = 0; wav_ch < 18; wav_ch++)
+            if (wav_mask & (1 << wav_ch))
+                ch_remap[nchannels++] = wav_map[wav_ch];
+        avctx->channel_layout = wav_mask;
+    }
+
+    avctx->channels = nchannels;
+    return nchannels;
+}
+
+static uint16_t crc16(const uint8_t *data, int size)
+{
+    static const uint16_t crctab[16] = {
+        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+        0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+    };
+
+    uint16_t res = 0xffff;
+    for (int i = 0; i < size; i++) {
+        res = (res << 4) ^ crctab[(data[i] >> 4) ^ (res >> 12)];
+        res = (res << 4) ^ crctab[(data[i] & 15) ^ (res >> 12)];
+    }
+
+    return res;
+}
+
+int ff_dca2_check_crc(GetBitContext *s, int p1, int p2)
+{
+    if (((p1 | p2) & 7) || p1 < 0 || p2 > s->size_in_bits || p2 - p1 < 16)
+        return -1;
+    if (crc16(s->buffer + p1 / 8, (p2 - p1) / 8))
+        return -1;
+    return 0;
+}
+
+void ff_dca2_downmix_to_stereo_fixed(int **samples, int *coeff_l, int nsamples, int ch_mask)
+{
+    int pos, spkr, max_spkr = av_log2(ch_mask);
+    int *coeff_r = coeff_l + av_popcount(ch_mask);
+
+    av_assert0((ch_mask & DCA2_SPEAKER_LAYOUT_STEREO) == DCA2_SPEAKER_LAYOUT_STEREO);
+
+    // Scale left and right channels
+    pos = (ch_mask & DCA2_SPEAKER_MASK_C);
+    vmul15(samples[DCA2_SPEAKER_L], coeff_l[pos    ], nsamples);
+    vmul15(samples[DCA2_SPEAKER_R], coeff_r[pos + 1], nsamples);
+
+    // Downmix remaining channels
+    for (spkr = 0; spkr <= max_spkr; spkr++) {
+        if (!(ch_mask & (1U << spkr)))
+            continue;
+
+        if (*coeff_l && spkr != DCA2_SPEAKER_L)
+            vmul15_add(samples[DCA2_SPEAKER_L], samples[spkr], *coeff_l, nsamples);
+
+        if (*coeff_r && spkr != DCA2_SPEAKER_R)
+            vmul15_add(samples[DCA2_SPEAKER_R], samples[spkr], *coeff_r, nsamples);
+
+        coeff_l++;
+        coeff_r++;
+    }
+}
+
+void ff_dca2_downmix_to_stereo_float(AVFloatDSPContext *fdsp, float **samples,
+                                     int *coeff_l, int nsamples, int ch_mask)
+{
+    int pos, spkr, max_spkr = av_log2(ch_mask);
+    int *coeff_r = coeff_l + av_popcount(ch_mask);
+
+    av_assert0((ch_mask & DCA2_SPEAKER_LAYOUT_STEREO) == DCA2_SPEAKER_LAYOUT_STEREO);
+
+    // Scale left and right channels
+    pos = (ch_mask & DCA2_SPEAKER_MASK_C);
+    fdsp->vector_fmul_scalar(samples[DCA2_SPEAKER_L],
+                             samples[DCA2_SPEAKER_L],
+                             coeff_l[pos    ] * (1.0f / (1 << 15)),
+                             nsamples);
+    fdsp->vector_fmul_scalar(samples[DCA2_SPEAKER_R],
+                             samples[DCA2_SPEAKER_R],
+                             coeff_r[pos + 1] * (1.0f / (1 << 15)),
+                             nsamples);
+
+    // Downmix remaining channels
+    for (spkr = 0; spkr <= max_spkr; spkr++) {
+        if (!(ch_mask & (1U << spkr)))
+            continue;
+
+        if (*coeff_l && spkr != DCA2_SPEAKER_L)
+            fdsp->vector_fmac_scalar(samples[DCA2_SPEAKER_L],
+                                     samples[spkr],
+                                     *coeff_l * (1.0f / (1 << 15)),
+                                     nsamples);
+
+        if (*coeff_r && spkr != DCA2_SPEAKER_R)
+            fdsp->vector_fmac_scalar(samples[DCA2_SPEAKER_R],
+                                     samples[spkr],
+                                     *coeff_r * (1.0f / (1 << 15)),
+                                     nsamples);
+
+        coeff_l++;
+        coeff_r++;
+    }
+}
+
+static int filter_core_frame(DCA2Context *s, AVFrame *frame)
+{
+    int ret = ff_dca2_core_filter_frame(&s->core, frame);
+
+    if (ret < 0) {
+        s->core_residual_valid = 0;
+        return ret;
+    }
+
+    s->core_residual_valid = !!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT);
+    return 0;
+}
+
+static int filter_hd_ma_frame(DCA2Context *s, AVFrame *frame)
+{
+    AVCodecContext *avctx = s->avctx;
+    DCA2XllChSet *p = &s->xll.chset[0];
+    enum AVMatrixEncoding matrix_encoding = AV_MATRIX_ENCODING_NONE;
+    int i, k, ret, shift, nsamples, request_mask;
+    int ch_remap[DCA2_SPEAKER_COUNT];
+
+    if (s->packet & DCA2_PACKET_CORE) {
+        int x96_synth = 0;
+
+        if (p->freq == 96000 && s->core.sample_rate == 48000)
+            x96_synth = 1;
+
+        if ((ret = ff_dca2_core_filter_fixed(&s->core, x96_synth)) < 0) {
+            s->core_residual_valid = 0;
+            return ret;
+        }
+
+        if (!s->core_residual_valid) {
+            if (s->has_residual_encoded && s->xll.nchsets > 1)
+                s->packet |= DCA2_PACKET_RECOVERY;
+            s->core_residual_valid = 1;
+        }
+    }
+
+    if ((ret = ff_dca2_xll_filter(&s->xll)) < 0)
+        return ret;
+
+    // Handle downmixing to stereo request
+    if (s->request_channel_layout == DCA2_SPEAKER_LAYOUT_STEREO
+        && (s->xll.output_mask & DCA2_SPEAKER_LAYOUT_STEREO) == DCA2_SPEAKER_LAYOUT_STEREO
+        && p->dmix_embedded && (p->dmix_type == DCA2_DMIX_TYPE_LoRo ||
+                                p->dmix_type == DCA2_DMIX_TYPE_LtRt))
+        request_mask = DCA2_SPEAKER_LAYOUT_STEREO;
+    else
+        request_mask = s->xll.output_mask;
+    if (!ff_dca2_set_channel_layout(avctx, ch_remap, request_mask))
+        return AVERROR(EINVAL);
+
+    avctx->sample_rate = p->freq << (s->xll.nfreqbands - 1);
+
+    switch (p->storage_bit_res) {
+    case 16:
+        avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
+        break;
+    case 24:
+        avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
+        break;
+    default:
+        return AVERROR(EINVAL);
+    }
+
+    avctx->bits_per_raw_sample = p->storage_bit_res;
+    avctx->profile = FF_PROFILE_DTS_HD_MA;
+    avctx->bit_rate = 0;
+
+    frame->nb_samples = nsamples = s->xll.nframesamples << (s->xll.nfreqbands - 1);
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    // Downmix primary channel set to stereo
+    if (request_mask != s->xll.output_mask) {
+        ff_dca2_downmix_to_stereo_fixed(s->xll.output_samples, p->dmix_coeff,
+                                        nsamples, s->xll.output_mask);
+    }
+
+    shift = p->storage_bit_res - p->pcm_bit_res;
+    for (i = 0; i < avctx->channels; i++) {
+        int32_t *samples = s->xll.output_samples[ch_remap[i]];
+        if (frame->format == AV_SAMPLE_FMT_S16P) {
+            int16_t *plane = (int16_t *)frame->extended_data[i];
+            for (k = 0; k < nsamples; k++)
+                plane[k] = av_clip_int16(samples[k] * (1 << shift));
+        } else {
+            int32_t *plane = (int32_t *)frame->extended_data[i];
+            for (k = 0; k < nsamples; k++)
+                plane[k] = clip23(samples[k] * (1 << shift)) * (1 << 8);
+        }
+    }
+
+    if (!s->exss.assets[0].one_to_one_map_ch_to_spkr) {
+        if (s->exss.assets[0].representation_type == DCA2_REPR_TYPE_LtRt)
+            matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
+        else if (s->exss.assets[0].representation_type == DCA2_REPR_TYPE_LhRh)
+            matrix_encoding = AV_MATRIX_ENCODING_DOLBYHEADPHONE;
+    } else if (request_mask != s->xll.output_mask && p->dmix_type == DCA2_DMIX_TYPE_LtRt) {
+        matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
+    }
+    if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0)
+        return ret;
+
+    return 0;
+}
+
+// Verify that core is compatible if there are residual encoded channel sets
+static int validate_hd_ma_frame(DCA2Context *s)
+{
+    DCA2XllChSet *p = &s->xll.chset[0], *c;
+    int i, ch, ch_mask;
+
+    s->has_residual_encoded = 0;
+    for (i = 0, c = s->xll.chset, ch_mask = 0; i < s->xll.nactivechsets; i++, c++) {
+        if (ch_mask & c->ch_mask) {
+            av_log(s->avctx, AV_LOG_WARNING, "Channel masks overlap between XLL channel sets\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        if (c->residual_encode != (1 << c->nchannels) - 1) {
+            if (!(s->packet & DCA2_PACKET_CORE)) {
+                av_log(s->avctx, AV_LOG_WARNING, "Residual encoded channels are present without core\n");
+                return AVERROR_INVALIDDATA;
+            }
+
+            for (ch = 0; ch < c->nchannels; ch++) {
+                if (ff_dca2_core_map_spkr(&s->core, c->ch_remap[ch]) < 0) {
+                    av_log(s->avctx, AV_LOG_WARNING, "Residual encoded channel (%d) references unavailable core channel\n", c->ch_remap[ch]);
+                    return AVERROR_INVALIDDATA;
+                }
+            }
+
+            s->has_residual_encoded = 1;
+        }
+
+        ch_mask |= c->ch_mask;
+    }
+
+    if (s->has_residual_encoded) {
+        int rate = s->core.sample_rate;
+        int nsamples = s->core.npcmblocks * DCA2_PCMBLOCK_SAMPLES;
+
+        // Double sampling frequency if needed
+        if (p->freq == 96000 && rate == 48000) {
+            rate *= 2;
+            nsamples *= 2;
+        }
+
+        if (p->freq != rate) {
+            av_log(s->avctx, AV_LOG_WARNING, "Sample rate mismatch between core (%d) and XLL (%d)\n", rate, p->freq);
+            return AVERROR_INVALIDDATA;
+        }
+
+        if (s->xll.nframesamples != nsamples) {
+            av_log(s->avctx, AV_LOG_WARNING, "Number of samples per frame mismatch between core (%d) and XLL (%d)\n", nsamples, s->xll.nframesamples);
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
+static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
+                               int *got_frame_ptr, AVPacket *avpkt)
+{
+    DCA2Context *s = avctx->priv_data;
+    AVFrame *frame = data;
+    uint8_t *input = avpkt->data;
+    int input_size = avpkt->size;
+    int i, ret, prev_packet = s->packet;
+
+    if (input_size < MIN_PACKET_SIZE || input_size > MAX_PACKET_SIZE) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid packet size\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    av_fast_malloc(&s->buffer, &s->buffer_size,
+                   FFALIGN(input_size, 4096) + DCA2_BUFFER_PADDING_SIZE);
+    if (!s->buffer)
+        return AVERROR(ENOMEM);
+
+    for (i = 0, ret = AVERROR_INVALIDDATA; i < input_size - MIN_PACKET_SIZE + 1 && ret < 0; i++)
+        ret = avpriv_dca_convert_bitstream(input + i, input_size - i, s->buffer, s->buffer_size);
+
+    if (ret < 0)
+        return ret;
+
+    input      = s->buffer;
+    input_size = ret;
+
+    s->packet = 0;
+
+    // Parse backward compatible core sub-stream
+    if (AV_RB32(input) == DCA_SYNCWORD_CORE_BE) {
+        int frame_size;
+
+        if ((ret = ff_dca2_core_parse(&s->core, input, input_size)) < 0) {
+            s->core_residual_valid = 0;
+            return ret;
+        }
+
+        s->packet |= DCA2_PACKET_CORE;
+
+        // EXXS data must be aligned on 4-byte boundary
+        frame_size = FFALIGN(s->core.frame_size, 4);
+        if (input_size - 4 > frame_size) {
+            input      += frame_size;
+            input_size -= frame_size;
+        }
+    }
+
+    if (!s->core_only) {
+        DCA2ExssAsset *asset = NULL;
+
+        // Parse extension sub-stream (EXSS)
+        if (AV_RB32(input) == DCA_SYNCWORD_SUBSTREAM) {
+            if ((ret = ff_dca2_exss_parse(&s->exss, input, input_size)) < 0) {
+                if (avctx->err_recognition & AV_EF_EXPLODE)
+                    return ret;
+            } else {
+                asset = &s->exss.assets[0];
+            }
+        }
+
+        // Parse XLL component in EXSS
+        if (asset && (asset->extension_mask & DCA2_EXSS_XLL)) {
+            if ((ret = ff_dca2_xll_parse(&s->xll, input, asset)) < 0) {
+                // Conceal XLL synchronization error
+                if (ret == AVERROR(EAGAIN) &&
+                    (prev_packet & DCA2_PACKET_XLL) &&
+                    (s->packet & DCA2_PACKET_CORE)) {
+                    s->packet |= DCA2_PACKET_XLL | DCA2_PACKET_RECOVERY;
+                } else {
+                    if (avctx->err_recognition & AV_EF_EXPLODE)
+                        return ret;
+                }
+            } else {
+                s->packet |= DCA2_PACKET_XLL;
+            }
+        }
+
+        // Parse core extensions in EXSS or backward compatible core sub-stream
+        if ((s->packet & DCA2_PACKET_CORE)
+            && (ret = ff_dca2_core_parse_exss(&s->core, input, asset)) < 0)
+            return ret;
+    }
+
+    // Filter
+    if (s->packet & DCA2_PACKET_XLL) {
+        if ((ret = validate_hd_ma_frame(s)) < 0) {
+            if (avctx->err_recognition & AV_EF_EXPLODE)
+                return ret;
+            if (!(s->packet & DCA2_PACKET_CORE))
+                return ret;
+            if ((ret = filter_core_frame(s, frame)) < 0)
+                return ret;
+        } else {
+            if ((ret = filter_hd_ma_frame(s, frame)) < 0)
+                return ret;
+        }
+    } else if (s->packet & DCA2_PACKET_CORE) {
+        if ((ret = filter_core_frame(s, frame)) < 0)
+            return ret;
+    } else {
+        return AVERROR(EINVAL);
+    }
+
+    *got_frame_ptr = 1;
+
+    return avpkt->size;
+}
+
+static av_cold void dcadec_flush(AVCodecContext *avctx)
+{
+    DCA2Context *s = avctx->priv_data;
+
+    ff_dca2_core_flush(&s->core);
+    ff_dca2_xll_flush(&s->xll);
+
+    s->core_residual_valid = 0;
+}
+
+static av_cold int dcadec_close(AVCodecContext *avctx)
+{
+    DCA2Context *s = avctx->priv_data;
+
+    ff_dca2_core_close(&s->core);
+    ff_dca2_xll_close(&s->xll);
+
+    av_freep(&s->buffer);
+    s->buffer_size = 0;
+
+    return 0;
+}
+
+static av_cold int dcadec_init(AVCodecContext *avctx)
+{
+    DCA2Context *s = avctx->priv_data;
+    int ret;
+
+    s->avctx = avctx;
+    s->core.avctx = avctx;
+    s->exss.avctx = avctx;
+    s->xll.avctx = avctx;
+
+    if ((ret = ff_dca2_core_init(&s->core)) < 0)
+        return ret;
+
+    switch (avctx->request_channel_layout & ~AV_CH_LAYOUT_NATIVE) {
+    case 0:
+        s->request_channel_layout = 0;
+        break;
+    case AV_CH_LAYOUT_STEREO:
+    case AV_CH_LAYOUT_STEREO_DOWNMIX:
+        s->request_channel_layout = DCA2_SPEAKER_LAYOUT_STEREO;
+        break;
+    case AV_CH_LAYOUT_5POINT0:
+        s->request_channel_layout = DCA2_SPEAKER_LAYOUT_5POINT0;
+        break;
+    case AV_CH_LAYOUT_5POINT1:
+        s->request_channel_layout = DCA2_SPEAKER_LAYOUT_5POINT1;
+        break;
+    default:
+        av_log(avctx, AV_LOG_WARNING, "Invalid request_channel_layout\n");
+        break;
+    }
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
+    avctx->bits_per_raw_sample = 24;
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(DCA2Context, x)
+#define PARAM AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption dcadec_options[] = {
+    { "core_only",  "Decode core only without extensions",    OFFSET(core_only),  AV_OPT_TYPE_BOOL,  { .i64 = 0 }, 0,       1,       PARAM },
+    { NULL }
+};
+
+static const AVClass dcadec_class = {
+    .class_name = "DCA-2 decoder",
+    .item_name  = av_default_item_name,
+    .option     = dcadec_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+    .category   = AV_CLASS_CATEGORY_DECODER,
+};
+
+static const AVProfile profiles[] = {
+    { FF_PROFILE_DTS,         "DTS"         },
+    { FF_PROFILE_DTS_ES,      "DTS-ES"      },
+    { FF_PROFILE_DTS_96_24,   "DTS 96/24"   },
+    { FF_PROFILE_DTS_HD_HRA,  "DTS-HD HRA"  },
+    { FF_PROFILE_DTS_HD_MA,   "DTS-HD MA"   },
+    { FF_PROFILE_UNKNOWN },
+};
+
+AVCodec ff_dca2_decoder = {
+    .name           = "dca2",
+    .long_name      = NULL_IF_CONFIG_SMALL("DCA-2 (DTS Coherent Acoustics)"),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_DTS,
+    .priv_data_size = sizeof(DCA2Context),
+    .init           = dcadec_init,
+    .decode         = dcadec_decode_frame,
+    .close          = dcadec_close,
+    .flush          = dcadec_flush,
+    .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
+                                                      AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE },
+    .priv_class     = &dcadec_class,
+    .profiles       = NULL_IF_CONFIG_SMALL(profiles),
+};
diff --git a/libavcodec/dcadsp2_fixed.c b/libavcodec/dcadsp2_fixed.c
new file mode 100644
index 0000000..ec4165b
--- /dev/null
+++ b/libavcodec/dcadsp2_fixed.c
@@ -0,0 +1,516 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca2.h"
+#include "dca2_math.h"
+
+static void lfe_fir_c(int *pcm_samples, int *lfe_samples, int npcmblocks)
+{
+    // Select decimation factor
+    int nlfesamples = npcmblocks >> 1;
+    int i, j, k;
+
+    for (i = 0; i < nlfesamples; i++) {
+        // One decimated sample generates 64 interpolated ones
+        for (j = 0; j < 32; j++) {
+            int64_t a = INT64_C(0);
+            int64_t b = INT64_C(0);
+
+            for (k = 0; k < 8; k++) {
+                a += (int64_t)ff_dca2_lfe_fir_64_fixed[      j * 8 + k] * lfe_samples[-k];
+                b += (int64_t)ff_dca2_lfe_fir_64_fixed[255 - j * 8 - k] * lfe_samples[-k];
+            }
+
+            pcm_samples[     j] = clip23(norm23(a));
+            pcm_samples[32 + j] = clip23(norm23(b));
+        }
+
+        lfe_samples++;
+        pcm_samples += 64;
+    }
+}
+
+static void sum_a(const int *input, int *output, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        output[i] = input[2 * i] + input[2 * i + 1];
+}
+
+static void sum_b(const int *input, int *output, int len)
+{
+    int i;
+
+    output[0] = input[0];
+    for (i = 1; i < len; i++)
+        output[i] = input[2 * i] + input[2 * i - 1];
+}
+
+static void sum_c(const int *input, int *output, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        output[i] = input[2 * i];
+}
+
+static void sum_d(const int *input, int *output, int len)
+{
+    int i;
+
+    output[0] = input[1];
+    for (i = 1; i < len; i++)
+        output[i] = input[2 * i - 1] + input[2 * i + 1];
+}
+
+static void dct_a(const int *input, int *output)
+{
+    static const int cos_mod[8][8] = {
+         { 8348215,  8027397,  7398092,  6484482,  5321677,  3954362,  2435084,   822227 },
+         { 8027397,  5321677,   822227, -3954362, -7398092, -8348215, -6484482, -2435084 },
+         { 7398092,   822227, -6484482, -8027397, -2435084,  5321677,  8348215,  3954362 },
+         { 6484482, -3954362, -8027397,   822227,  8348215,  2435084, -7398092, -5321677 },
+         { 5321677, -7398092, -2435084,  8348215,  -822227, -8027397,  3954362,  6484482 },
+         { 3954362, -8348215,  5321677,  2435084, -8027397,  6484482,   822227, -7398092 },
+         { 2435084, -6484482,  8348215, -7398092,  3954362,   822227, -5321677,  8027397 },
+         {  822227, -2435084,  3954362, -5321677,  6484482, -7398092,  8027397, -8348215 }
+    };
+
+    int i, j;
+
+    for (i = 0; i < 8; i++) {
+        int64_t res = INT64_C(0);
+        for (j = 0; j < 8; j++)
+            res += (int64_t)cos_mod[i][j] * input[j];
+        output[i] = norm23(res);
+    }
+}
+
+static void dct_b(const int *input, int *output)
+{
+    static const int cos_mod[8][7] = {
+        {  8227423,  7750063,  6974873,  5931642,  4660461,  3210181,  1636536 },
+        {  6974873,  3210181, -1636536, -5931642, -8227423, -7750063, -4660461 },
+        {  4660461, -3210181, -8227423, -5931642,  1636536,  7750063,  6974873 },
+        {  1636536, -7750063, -4660461,  5931642,  6974873, -3210181, -8227423 },
+        { -1636536, -7750063,  4660461,  5931642, -6974873, -3210181,  8227423 },
+        { -4660461, -3210181,  8227423, -5931642, -1636536,  7750063, -6974873 },
+        { -6974873,  3210181,  1636536, -5931642,  8227423, -7750063,  4660461 },
+        { -8227423,  7750063, -6974873,  5931642, -4660461,  3210181, -1636536 }
+    };
+
+    int i, j;
+
+    for (i = 0; i < 8; i++) {
+        int64_t res = (int64_t)input[0] * (1 << 23);
+        for (j = 0; j < 7; j++)
+            res += (int64_t)cos_mod[i][j] * input[1 + j];
+        output[i] = norm23(res);
+    }
+}
+
+static void mod_a(const int *input, int *output)
+{
+    static const int cos_mod[16] = {
+          4199362,   4240198,   4323885,   4454708,
+          4639772,   4890013,   5221943,   5660703,
+         -6245623,  -7040975,  -8158494,  -9809974,
+        -12450076, -17261920, -28585092, -85479984
+    };
+
+    int i, k;
+
+    for (i = 0; i < 8; i++)
+        output[i] = mul23(cos_mod[i], input[i] + input[8 + i]);
+
+    for (i = 8, k = 7; i < 16; i++, k--)
+        output[i] = mul23(cos_mod[i], input[k] - input[8 + k]);
+}
+
+static void mod_b(int *input, int *output)
+{
+    static const int cos_mod[8] = {
+        4214598,  4383036,  4755871,  5425934,
+        6611520,  8897610, 14448934, 42791536
+    };
+
+    int i, k;
+
+    for (i = 0; i < 8; i++)
+        input[8 + i] = mul23(cos_mod[i], input[8 + i]);
+
+    for (i = 0; i < 8; i++)
+        output[i] = input[i] + input[8 + i];
+
+    for (i = 8, k = 7; i < 16; i++, k--)
+        output[i] = input[k] - input[8 + k];
+}
+
+static void mod_c(const int *input, int *output)
+{
+    static const int cos_mod[32] = {
+         1048892,  1051425,   1056522,   1064244,
+         1074689,  1087987,   1104313,   1123884,
+         1146975,  1173922,   1205139,   1241133,
+         1282529,  1330095,   1384791,   1447815,
+        -1520688, -1605358,  -1704360,  -1821051,
+        -1959964, -2127368,  -2332183,  -2587535,
+        -2913561, -3342802,  -3931480,  -4785806,
+        -6133390, -8566050, -14253820, -42727120
+    };
+
+    int i, k;
+
+    for (i = 0; i < 16; i++)
+        output[i] = mul23(cos_mod[i], input[i] + input[16 + i]);
+
+    for (i = 16, k = 15; i < 32; i++, k--)
+        output[i] = mul23(cos_mod[i], input[k] - input[16 + k]);
+}
+
+static void clp_v(int *input, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        input[i] = clip23(input[i]);
+}
+
+static void idct32(int *input, int *output)
+{
+    int i, mag, shift, round;
+
+    mag = 0;
+    for (i = 0; i < 32; i++)
+        mag += abs(input[i]);
+
+    shift = mag > 0x400000 ? 2 : 0;
+    round = shift > 0 ? 1 << (shift - 1) : 0;
+
+    for (i = 0; i < 32; i++)
+        input[i] = (input[i] + round) >> shift;
+
+    sum_a(input, output +  0, 16);
+    sum_b(input, output + 16, 16);
+    clp_v(output, 32);
+
+    sum_a(output +  0, input +  0, 8);
+    sum_b(output +  0, input +  8, 8);
+    sum_c(output + 16, input + 16, 8);
+    sum_d(output + 16, input + 24, 8);
+    clp_v(input, 32);
+
+    dct_a(input +  0, output +  0);
+    dct_b(input +  8, output +  8);
+    dct_b(input + 16, output + 16);
+    dct_b(input + 24, output + 24);
+    clp_v(output, 32);
+
+    mod_a(output +  0, input +  0);
+    mod_b(output + 16, input + 16);
+    clp_v(input, 32);
+
+    mod_c(input, output);
+
+    for (i = 0; i < 32; i++)
+        output[i] = clip23(output[i] * (1 << shift));
+}
+
+static void mod64_a(const int *input, int *output)
+{
+    static const int cos_mod[32] = {
+          4195568,   4205700,   4226086,    4256977,
+          4298755,   4351949,   4417251,    4495537,
+          4587901,   4695690,   4820557,    4964534,
+          5130115,   5320382,   5539164,    5791261,
+         -6082752,  -6421430,  -6817439,   -7284203,
+         -7839855,  -8509474,  -9328732,  -10350140,
+        -11654242, -13371208, -15725922,  -19143224,
+        -24533560, -34264200, -57015280, -170908480
+    };
+
+    int i, k;
+
+    for (i = 0; i < 16; i++)
+        output[i] = mul23(cos_mod[i], input[i] + input[16 + i]);
+
+    for (i = 16, k = 15; i < 32; i++, k--)
+        output[i] = mul23(cos_mod[i], input[k] - input[16 + k]);
+}
+
+static void mod64_b(int *input, int *output)
+{
+    static const int cos_mod[16] = {
+         4199362,  4240198,  4323885,  4454708,
+         4639772,  4890013,  5221943,  5660703,
+         6245623,  7040975,  8158494,  9809974,
+        12450076, 17261920, 28585092, 85479984
+    };
+
+    int i, k;
+
+    for (i = 0; i < 16; i++)
+        input[16 + i] = mul23(cos_mod[i], input[16 + i]);
+
+    for (i = 0; i < 16; i++)
+        output[i] = input[i] + input[16 + i];
+
+    for (i = 16, k = 15; i < 32; i++, k--)
+        output[i] = input[k] - input[16 + k];
+}
+
+static void mod64_c(const int *input, int *output)
+{
+    static const int cos_mod[64] = {
+          741511,    741958,    742853,    744199,
+          746001,    748262,    750992,    754197,
+          757888,    762077,    766777,    772003,
+          777772,    784105,    791021,    798546,
+          806707,    815532,    825054,    835311,
+          846342,    858193,    870912,    884554,
+          899181,    914860,    931667,    949686,
+          969011,    989747,   1012012,   1035941,
+        -1061684,  -1089412,  -1119320,  -1151629,
+        -1186595,  -1224511,  -1265719,  -1310613,
+        -1359657,  -1413400,  -1472490,  -1537703,
+        -1609974,  -1690442,  -1780506,  -1881904,
+        -1996824,  -2128058,  -2279225,  -2455101,
+        -2662128,  -2909200,  -3208956,  -3579983,
+        -4050785,  -4667404,  -5509372,  -6726913,
+        -8641940, -12091426, -20144284, -60420720
+    };
+
+    int i, k;
+
+    for (i = 0; i < 32; i++)
+        output[i] = mul23(cos_mod[i], input[i] + input[32 + i]);
+
+    for (i = 32, k = 31; i < 64; i++, k--)
+        output[i] = mul23(cos_mod[i], input[k] - input[32 + k]);
+}
+
+static void idct64(int *input, int *output)
+{
+    int i, mag, shift, round;
+
+    mag = 0;
+    for (i = 0; i < 64; i++)
+        mag += abs(input[i]);
+
+    shift = mag > 0x400000 ? 2 : 0;
+    round = shift > 0 ? 1 << (shift - 1) : 0;
+
+    for (i = 0; i < 64; i++)
+        input[i] = (input[i] + round) >> shift;
+
+    sum_a(input, output +  0, 32);
+    sum_b(input, output + 32, 32);
+    clp_v(output, 64);
+
+    sum_a(output +  0, input +  0, 16);
+    sum_b(output +  0, input + 16, 16);
+    sum_c(output + 32, input + 32, 16);
+    sum_d(output + 32, input + 48, 16);
+    clp_v(input, 64);
+
+    sum_a(input +  0, output +  0, 8);
+    sum_b(input +  0, output +  8, 8);
+    sum_c(input + 16, output + 16, 8);
+    sum_d(input + 16, output + 24, 8);
+    sum_c(input + 32, output + 32, 8);
+    sum_d(input + 32, output + 40, 8);
+    sum_c(input + 48, output + 48, 8);
+    sum_d(input + 48, output + 56, 8);
+    clp_v(output, 64);
+
+    dct_a(output +  0, input +  0);
+    dct_b(output +  8, input +  8);
+    dct_b(output + 16, input + 16);
+    dct_b(output + 24, input + 24);
+    dct_b(output + 32, input + 32);
+    dct_b(output + 40, input + 40);
+    dct_b(output + 48, input + 48);
+    dct_b(output + 56, input + 56);
+    clp_v(input, 64);
+
+    mod_a(input +  0, output +  0);
+    mod_b(input + 16, output + 16);
+    mod_b(input + 32, output + 32);
+    mod_b(input + 48, output + 48);
+    clp_v(output, 64);
+
+    mod64_a(output +  0, input +  0);
+    mod64_b(output + 32, input + 32);
+    clp_v(input, 64);
+
+    mod64_c(input, output);
+
+    for (i = 0; i < 64; i++)
+        output[i] = clip23(output[i] * (1 << shift));
+}
+
+static void sub_qmf32_c(int *pcm_samples,
+                        int **subband_samples_lo,
+                        int **subband_samples_hi,
+                        DCA2DspData *dsp,
+                        int nsamples, int perfect)
+{
+    int input[32];
+    int output[32];
+    int i, j, k, sample, *hist_ptr;
+    const int32_t *filter_coeff = perfect ? ff_dca2_band_fir_perfect_fixed :
+                                            ff_dca2_band_fir_nonperfect_fixed;
+
+    for (sample = 0; sample < nsamples; sample++) {
+        // Load in one sample from each subband
+        for (i = 0; i < 32; i++)
+            input[i] = subband_samples_lo[i][sample];
+
+        // Inverse DCT
+        idct32(input, output);
+
+        // Get history pointer
+        hist_ptr = dsp->u.fix32.hist1 + dsp->offset;
+
+        // Store history
+        for (i = 0, k = 31; i < 16; i++, k--) {
+            hist_ptr[     i] = clip23(output[i] - output[k]);
+            hist_ptr[16 + i] = clip23(output[i] + output[k]);
+        }
+
+        // One subband sample generates 32 interpolated ones
+        for (i = 0, k = 15; i < 16; i++, k--) {
+            int64_t a = dsp->u.fix32.hist2[     i] * (INT64_C(1) << 21);
+            int64_t b = dsp->u.fix32.hist2[16 + i] * (INT64_C(1) << 21);
+            int64_t c = INT64_C(0);
+            int64_t d = INT64_C(0);
+
+            for (j = 0; j < 512 - dsp->offset; j += 64) {
+                a += (int64_t)hist_ptr[     i + j] * filter_coeff[     i + j];
+                b += (int64_t)hist_ptr[     k + j] * filter_coeff[16 + i + j];
+                c += (int64_t)hist_ptr[16 + i + j] * filter_coeff[32 + i + j];
+                d += (int64_t)hist_ptr[16 + k + j] * filter_coeff[48 + i + j];
+            }
+
+            for (; j < 512; j += 64) {
+                a += (int64_t)hist_ptr[     i + j - 512] * filter_coeff[     i + j];
+                b += (int64_t)hist_ptr[     k + j - 512] * filter_coeff[16 + i + j];
+                c += (int64_t)hist_ptr[16 + i + j - 512] * filter_coeff[32 + i + j];
+                d += (int64_t)hist_ptr[16 + k + j - 512] * filter_coeff[48 + i + j];
+            }
+
+            // Save interpolated samples
+            pcm_samples[     i] = clip23(norm21(a));
+            pcm_samples[16 + i] = clip23(norm21(b));
+
+            // Save intermediate history
+            dsp->u.fix32.hist2[     i] = norm21(c);
+            dsp->u.fix32.hist2[16 + i] = norm21(d);
+        }
+
+        // Advance output pointer
+        pcm_samples += 32;
+
+        // Shift history
+        dsp->offset = (dsp->offset - 32) & 511;
+    }
+}
+
+static void sub_qmf64_c(int *pcm_samples,
+                        int **subband_samples_lo,
+                        int **subband_samples_hi,
+                        DCA2DspData *dsp,
+                        int nsamples, int perfect)
+{
+    int input[64];
+    int output[64];
+    int i, j, k, sample, *hist_ptr;
+
+    for (sample = 0; sample < nsamples; sample++) {
+        // Load in one sample from each subband
+        if (subband_samples_hi) {
+            // Full 64 subbands, first 32 are residual coded
+            for (i =  0; i < 32; i++)
+                input[i] = subband_samples_lo[i][sample] + subband_samples_hi[i][sample];
+            for (i = 32; i < 64; i++)
+                input[i] = subband_samples_hi[i][sample];
+        } else {
+            // Only first 32 subbands
+            for (i =  0; i < 32; i++)
+                input[i] = subband_samples_lo[i][sample];
+            for (i = 32; i < 64; i++)
+                input[i] = 0;
+        }
+
+        // Inverse DCT
+        idct64(input, output);
+
+        // Get history pointer
+        hist_ptr = dsp->u.fix64.hist1 + dsp->offset;
+
+        // Store history
+        for (i = 0, k = 63; i < 32; i++, k--) {
+            hist_ptr[     i] = clip23(output[i] - output[k]);
+            hist_ptr[32 + i] = clip23(output[i] + output[k]);
+        }
+
+        // One subband sample generates 64 interpolated ones
+        for (i = 0, k = 31; i < 32; i++, k--) {
+            int64_t a = dsp->u.fix64.hist2[     i] * (INT64_C(1) << 20);
+            int64_t b = dsp->u.fix64.hist2[32 + i] * (INT64_C(1) << 20);
+            int64_t c = INT64_C(0);
+            int64_t d = INT64_C(0);
+
+            for (j = 0; j < 1024 - dsp->offset; j += 128) {
+                a += (int64_t)hist_ptr[     i + j] * ff_dca2_band_fir_x96_fixed[     i + j];
+                b += (int64_t)hist_ptr[     k + j] * ff_dca2_band_fir_x96_fixed[32 + i + j];
+                c += (int64_t)hist_ptr[32 + i + j] * ff_dca2_band_fir_x96_fixed[64 + i + j];
+                d += (int64_t)hist_ptr[32 + k + j] * ff_dca2_band_fir_x96_fixed[96 + i + j];
+            }
+
+            for (; j < 1024; j += 128) {
+                a += (int64_t)hist_ptr[     i + j - 1024] * ff_dca2_band_fir_x96_fixed[     i + j];
+                b += (int64_t)hist_ptr[     k + j - 1024] * ff_dca2_band_fir_x96_fixed[32 + i + j];
+                c += (int64_t)hist_ptr[32 + i + j - 1024] * ff_dca2_band_fir_x96_fixed[64 + i + j];
+                d += (int64_t)hist_ptr[32 + k + j - 1024] * ff_dca2_band_fir_x96_fixed[96 + i + j];
+            }
+
+            // Save interpolated samples
+            pcm_samples[     i] = clip23(norm20(a));
+            pcm_samples[32 + i] = clip23(norm20(b));
+
+            // Save intermediate history
+            dsp->u.fix64.hist2[     i] = norm20(c);
+            dsp->u.fix64.hist2[32 + i] = norm20(d);
+        }
+
+        // Advance output pointer
+        pcm_samples += 64;
+
+        // Shift history
+        dsp->offset = (dsp->offset - 64) & 1023;
+    }
+}
+
+av_cold void ff_dcadsp2_fixed_init(DCA2FixedDspContext *s)
+{
+    s->lfe_fir = lfe_fir_c;
+    s->sub_qmf[0] = sub_qmf32_c;
+    s->sub_qmf[1] = sub_qmf64_c;
+}
diff --git a/libavcodec/dcadsp2_float.c b/libavcodec/dcadsp2_float.c
new file mode 100644
index 0000000..3455fd9
--- /dev/null
+++ b/libavcodec/dcadsp2_float.c
@@ -0,0 +1,183 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dca2.h"
+#include "dca2_math.h"
+
+static void lfe_fir_c(float *pcm_samples, int *lfe_samples, int npcmblocks,
+                      const float *filter_coeff, int dec_select)
+{
+    // Select decimation factor
+    int factor = 64 << dec_select;
+    int ncoeffs = 8 >> dec_select;
+    int nlfesamples = npcmblocks >> (dec_select + 1);
+    int i, j, k;
+
+    for (i = 0; i < nlfesamples; i++) {
+        // One decimated sample generates 64 or 128 interpolated ones
+        for (j = 0; j < factor / 2; j++) {
+            float a = 0.0f;
+            float b = 0.0f;
+
+            for (k = 0; k < ncoeffs; k++) {
+                a += filter_coeff[      j * ncoeffs + k] * lfe_samples[-k];
+                b += filter_coeff[255 - j * ncoeffs - k] * lfe_samples[-k];
+            }
+
+            pcm_samples[             j] = a;
+            pcm_samples[factor / 2 + j] = b;
+        }
+
+        lfe_samples++;
+        pcm_samples += factor;
+    }
+}
+
+static void lfe_fir1_c(float *pcm_samples, int *lfe_samples, int npcmblocks)
+{
+    lfe_fir_c(pcm_samples, lfe_samples, npcmblocks, ff_dca_lfe_fir_64, 0);
+}
+
+static void lfe_fir2_c(float *pcm_samples, int *lfe_samples, int npcmblocks)
+{
+    lfe_fir_c(pcm_samples, lfe_samples, npcmblocks, ff_dca_lfe_fir_128, 1);
+}
+
+static void sub_qmf32_c(FFTContext *imdct,
+                        SynthFilterContext *synth,
+                        float *pcm_samples,
+                        int **subband_samples_lo,
+                        int **subband_samples_hi,
+                        DCA2DspData *dsp,
+                        int nsamples, int perfect)
+{
+    LOCAL_ALIGNED_32(float, input, [32]);
+    int i, sample;
+    const float *filter_coeff = perfect ? ff_dca_fir_32bands_perfect :
+                                          ff_dca_fir_32bands_nonperfect;
+
+    for (sample = 0; sample < nsamples; sample++) {
+        // Load in one sample from each subband
+        for (i = 0; i < 32; i++) {
+            if ((i - 1) & 2)
+                input[i] = -subband_samples_lo[i][sample];
+            else
+                input[i] =  subband_samples_lo[i][sample];
+        }
+
+        // One subband sample generates 32 interpolated ones
+        synth->synth_filter_float(imdct, dsp->u.flt32.hist1, &dsp->offset,
+                                  dsp->u.flt32.hist2, filter_coeff,
+                                  pcm_samples, input, 1.0f / (1 << 17));
+
+        // Advance output pointer
+        pcm_samples += 32;
+    }
+}
+
+static void sub_qmf64_c(FFTContext *imdct,
+                        SynthFilterContext *synth,
+                        float *pcm_samples,
+                        int **subband_samples_lo,
+                        int **subband_samples_hi,
+                        DCA2DspData *dsp,
+                        int nsamples, int perfect)
+{
+    LOCAL_ALIGNED_32(float, input, [64]);
+    int i, j, k, sample;
+    float *hist_ptr;
+
+    for (sample = 0; sample < nsamples; sample++) {
+        // Load in one sample from each subband
+        if (subband_samples_hi) {
+            // Full 64 subbands, first 32 are residual coded
+            for (i =  0; i < 32; i++) {
+                if ((i - 1) & 2)
+                    input[i] = -subband_samples_lo[i][sample] - subband_samples_hi[i][sample];
+                else
+                    input[i] =  subband_samples_lo[i][sample] + subband_samples_hi[i][sample];
+            }
+            for (i = 32; i < 64; i++) {
+                if ((i - 1) & 2)
+                    input[i] = -subband_samples_hi[i][sample];
+                else
+                    input[i] =  subband_samples_hi[i][sample];
+            }
+        } else {
+            // Only first 32 subbands
+            for (i =  0; i < 32; i++) {
+                if ((i - 1) & 2)
+                    input[i] = -subband_samples_lo[i][sample];
+                else
+                    input[i] =  subband_samples_lo[i][sample];
+            }
+            for (i = 32; i < 64; i++)
+                input[i] = 0;
+        }
+
+        // Get history pointer
+        hist_ptr = dsp->u.flt64.hist1 + dsp->offset;
+
+        // Inverse DCT
+        imdct->imdct_half(imdct, hist_ptr, input);
+
+        // One subband sample generates 64 interpolated ones
+        for (i = 0, k = 31; i < 32; i++, k--) {
+            float a = dsp->u.flt64.hist2[     i];
+            float b = dsp->u.flt64.hist2[32 + i];
+            float c = 0.0f;
+            float d = 0.0f;
+
+            for (j = 0; j < 1024 - dsp->offset; j += 128) {
+                a -= hist_ptr[     k + j] * ff_dca_fir_64bands[     i + j];
+                b += hist_ptr[     i + j] * ff_dca_fir_64bands[32 + i + j];
+                c += hist_ptr[32 + i + j] * ff_dca_fir_64bands[64 + i + j];
+                d += hist_ptr[32 + k + j] * ff_dca_fir_64bands[96 + i + j];
+            }
+
+            for (; j < 1024; j += 128) {
+                a -= hist_ptr[     k + j - 1024] * ff_dca_fir_64bands[     i + j];
+                b += hist_ptr[     i + j - 1024] * ff_dca_fir_64bands[32 + i + j];
+                c += hist_ptr[32 + i + j - 1024] * ff_dca_fir_64bands[64 + i + j];
+                d += hist_ptr[32 + k + j - 1024] * ff_dca_fir_64bands[96 + i + j];
+            }
+
+            // Save interpolated samples
+            pcm_samples[     i] = a * (1.0f / (1 << 16));
+            pcm_samples[32 + i] = b * (1.0f / (1 << 16));
+
+            // Save intermediate history
+            dsp->u.flt64.hist2[     i] = c;
+            dsp->u.flt64.hist2[32 + i] = d;
+        }
+
+        // Advance output pointer
+        pcm_samples += 64;
+
+        // Shift history
+        dsp->offset = (dsp->offset - 64) & 1023;
+    }
+}
+
+av_cold void ff_dcadsp2_float_init(DCA2FloatDspContext *s)
+{
+    s->lfe_fir[0] = lfe_fir1_c;
+    s->lfe_fir[1] = lfe_fir2_c;
+    s->sub_qmf[0] = sub_qmf32_c;
+    s->sub_qmf[1] = sub_qmf64_c;
+}
diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile
index 0d09fe6..2f3cc26 100644
--- a/libavcodec/x86/Makefile
+++ b/libavcodec/x86/Makefile
@@ -44,6 +44,7 @@ OBJS-$(CONFIG_ADPCM_G722_ENCODER)      += x86/g722dsp_init.o
 OBJS-$(CONFIG_ALAC_DECODER)            += x86/alacdsp_init.o
 OBJS-$(CONFIG_APNG_DECODER)            += x86/pngdsp_init.o
 OBJS-$(CONFIG_CAVS_DECODER)            += x86/cavsdsp.o
+OBJS-$(CONFIG_DCA2_DECODER)            += x86/dcadsp_init.o
 OBJS-$(CONFIG_DCA_DECODER)             += x86/dcadsp_init.o
 OBJS-$(CONFIG_DNXHD_ENCODER)           += x86/dnxhdenc_init.o
 OBJS-$(CONFIG_HEVC_DECODER)            += x86/hevcdsp_init.o
@@ -132,6 +133,7 @@ YASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp.o
 YASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp.o
 YASM-OBJS-$(CONFIG_ALAC_DECODER)       += x86/alacdsp.o
 YASM-OBJS-$(CONFIG_APNG_DECODER)       += x86/pngdsp.o
+YASM-OBJS-$(CONFIG_DCA2_DECODER)       += x86/dcadsp.o
 YASM-OBJS-$(CONFIG_DCA_DECODER)        += x86/dcadsp.o
 YASM-OBJS-$(CONFIG_DIRAC_DECODER)      += x86/diracdsp_mmx.o x86/diracdsp_yasm.o \
                                           x86/dwt_yasm.o
-- 
2.1.4



More information about the ffmpeg-devel mailing list