]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/dcadec.c
Use av_frame_copy() to simplify code where appropriate.
[ffmpeg] / libavcodec / dcadec.c
index cf1da8c09bd8d63d1a3e096925ddc3a7c80f38fe..6c240ee5fd6aa43259e91832cd452faf86857445 100644 (file)
@@ -32,6 +32,7 @@
 #include "libavutil/internal.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
 #include "libavutil/samplefmt.h"
 #include "avcodec.h"
 #include "fft.h"
@@ -49,6 +50,9 @@
 #if ARCH_ARM
 #   include "arm/dca.h"
 #endif
+#if ARCH_X86
+#   include "x86/dca.h"
+#endif
 
 //#define TRACE
 
@@ -262,6 +266,8 @@ static const int8_t dca_channel_reorder_nolfe_xch[][9] = {
 
 #define DCA_BUFFER_PADDING_SIZE   1024
 
+#define DCA_NSYNCAUX        0x9A1105A0
+
 /** Bit allocation */
 typedef struct {
     int offset;                 ///< code values offset
@@ -283,6 +289,7 @@ static av_always_inline int get_bitalloc(GetBitContext *gb, BitAlloc *ba,
 }
 
 typedef struct {
+    AVClass *class;             ///< class for AVOptions
     AVCodecContext *avctx;
     /* Frame header */
     int frame_type;             ///< type of the current frame
@@ -336,7 +343,7 @@ typedef struct {
     int scale_factor[DCA_PRIM_CHANNELS_MAX][DCA_SUBBANDS][2];    ///< scale factors (2 if transient)
     int joint_huff[DCA_PRIM_CHANNELS_MAX];                       ///< joint subband scale factors codebook
     int joint_scale_factor[DCA_PRIM_CHANNELS_MAX][DCA_SUBBANDS]; ///< joint subband scale factors
-    float downmix_coef[DCA_PRIM_CHANNELS_MAX][2];                ///< stereo downmix coefficients
+    float downmix_coef[DCA_PRIM_CHANNELS_MAX + 1][2];            ///< stereo downmix coefficients
     int dynrange_coef;                                           ///< dynamic range coefficient
 
     /* Core substream's embedded downmix coefficients (cf. ETSI TS 102 114 V1.4.1)
@@ -380,6 +387,7 @@ typedef struct {
     /* XCh extension information */
     int xch_present;            ///< XCh extension present and valid
     int xch_base_channel;       ///< index of first (only) channel containing XCH data
+    int xch_disable;            ///< whether the XCh extension should be decoded or not
 
     /* ExSS header parser */
     int static_fields;          ///< static fields present
@@ -949,23 +957,23 @@ static void lfe_interpolation_fir(DCAContext *s, int decimation_select,
      * samples_out: An array holding interpolated samples
      */
 
-    int decifactor;
+    int idx;
     const float *prCoeff;
     int deciindex;
 
     /* Select decimation filter */
     if (decimation_select == 1) {
-        decifactor = 64;
+        idx = 1;
         prCoeff = lfe_fir_128;
     } else {
-        decifactor = 32;
+        idx = 0;
         prCoeff = lfe_fir_64;
     }
     /* Interpolation */
     for (deciindex = 0; deciindex < num_deci_sample; deciindex++) {
-        s->dcadsp.lfe_fir(samples_out, samples_in, prCoeff, decifactor, scale);
+        s->dcadsp.lfe_fir[idx](samples_out, samples_in, prCoeff, scale);
         samples_in++;
-        samples_out += 2 * decifactor;
+        samples_out += 2 * 32 * (1 + idx);
     }
 }
 
@@ -991,8 +999,8 @@ static void lfe_interpolation_fir(DCAContext *s, int decimation_select,
         op2                                     \
     }
 
-static void dca_downmix(float **samples, int srcfmt,
-                        float coef[DCA_PRIM_CHANNELS_MAX][2],
+static void dca_downmix(float **samples, int srcfmt, int lfe_present,
+                        float coef[DCA_PRIM_CHANNELS_MAX + 1][2],
                         const int8_t *channel_mapping)
 {
     int c, l, r, sl, sr, s;
@@ -1001,13 +1009,13 @@ static void dca_downmix(float **samples, int srcfmt,
 
     switch (srcfmt) {
     case DCA_MONO:
-    case DCA_CHANNEL:
-    case DCA_STEREO_TOTAL:
-    case DCA_STEREO_SUMDIFF:
     case DCA_4F2R:
         av_log(NULL, 0, "Not implemented!\n");
         break;
+    case DCA_CHANNEL:
     case DCA_STEREO:
+    case DCA_STEREO_TOTAL:
+    case DCA_STEREO_SUMDIFF:
         break;
     case DCA_3F:
         c = channel_mapping[0];
@@ -1042,6 +1050,14 @@ static void dca_downmix(float **samples, int srcfmt,
                           MIX_REAR2(samples, sl, sr, 3, coef));
         break;
     }
+    if (lfe_present) {
+        int lf_buf = dca_lfe_index[srcfmt];
+        int lf_idx = dca_channels [srcfmt];
+        for (i = 0; i < 256; i++) {
+            samples[0][i] += samples[lf_buf][i] * coef[lf_idx][0];
+            samples[1][i] += samples[lf_buf][i] * coef[lf_idx][1];
+        }
+    }
 }
 
 
@@ -1073,12 +1089,10 @@ static const uint8_t abits_sizes[7]  = { 7, 10, 12, 13, 15, 17, 19 };
 static const uint8_t abits_levels[7] = { 3,  5,  7,  9, 13, 17, 25 };
 
 #ifndef int8x8_fmul_int32
-static inline void int8x8_fmul_int32(float *dst, const int8_t *src, int scale)
+static inline void int8x8_fmul_int32(DCADSPContext *dsp, float *dst,
+                                     const int8_t *src, int scale)
 {
-    float fscale = scale / 16.0;
-    int i;
-    for (i = 0; i < 8; i++)
-        dst[i] = src[i] * fscale;
+    dsp->int8x8_fmul_int32(dst, src, scale);
 }
 #endif
 
@@ -1206,7 +1220,7 @@ static int dca_subsubframe(DCAContext *s, int base_channel, int block_index)
                 s->debug_flag |= 0x01;
             }
 
-            int8x8_fmul_int32(subband_samples[k][l],
+            int8x8_fmul_int32(&s->dcadsp, subband_samples[k][l],
                               &high_freq_vq[hfvq][subsubframe * 8],
                               s->scale_factor[k][l][0]);
         }
@@ -1227,9 +1241,7 @@ static int dca_subsubframe(DCAContext *s, int base_channel, int block_index)
     /* Backup predictor history for adpcm */
     for (k = base_channel; k < s->prim_channels; k++)
         for (l = 0; l < s->vq_start_subband[k]; l++)
-            memcpy(s->subband_samples_hist[k][l],
-                   &subband_samples[k][l][4],
-                   4 * sizeof(subband_samples[0][0][0]));
+            AV_COPY128(s->subband_samples_hist[k][l], &subband_samples[k][l][4]);
 
     return 0;
 }
@@ -1249,14 +1261,8 @@ static int dca_filter_channels(DCAContext *s, int block_index)
                             M_SQRT1_2 / 32768.0 /* pcm_to_double[s->source_pcm_res] */);
     }
 
-    /* Down mixing */
-    if (s->prim_channels > 2 &&
-        s->avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
-        dca_downmix(s->samples_chanptr, s->amode, s->downmix_coef, s->channel_order_tab);
-    }
-
     /* Generate LFE samples for this subsubframe FIXME!!! */
-    if (s->output & DCA_LFE) {
+    if (s->lfe) {
         lfe_interpolation_fir(s, s->lfe, 2 * s->lfe,
                               s->lfe_data + 2 * s->lfe * (block_index + 4),
                               s->samples_chanptr[dca_lfe_index[s->amode]],
@@ -1264,6 +1270,13 @@ static int dca_filter_channels(DCAContext *s, int block_index)
         /* Outputs 20bits pcm samples */
     }
 
+    /* Downmixing to Stereo */
+    if (s->prim_channels + !!s->lfe > 2 &&
+        s->avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
+        dca_downmix(s->samples_chanptr, s->amode, !!s->lfe, s->downmix_coef,
+                    s->channel_order_tab);
+    }
+
     return 0;
 }
 
@@ -1271,6 +1284,7 @@ static int dca_filter_channels(DCAContext *s, int block_index)
 static int dca_subframe_footer(DCAContext *s, int base_channel)
 {
     int in, out, aux_data_count, aux_data_end, reserved;
+    uint32_t nsyncaux;
 
     /*
      * Unpack optional information
@@ -1289,8 +1303,11 @@ static int dca_subframe_footer(DCAContext *s, int base_channel)
 
             aux_data_end = 8 * aux_data_count + get_bits_count(&s->gb);
 
-            if (get_bits_long(&s->gb, 32) != 0x9A1105A0) // nSYNCAUX
+            if ((nsyncaux = get_bits_long(&s->gb, 32)) != DCA_NSYNCAUX) {
+                av_log(s->avctx, AV_LOG_ERROR, "nSYNCAUX mismatch %#"PRIx32"\n",
+                       nsyncaux);
                 return AVERROR_INVALIDDATA;
+            }
 
             if (get_bits1(&s->gb)) { // bAUXTimeStampFlag
                 avpriv_request_sample(s->avctx,
@@ -1302,7 +1319,8 @@ static int dca_subframe_footer(DCAContext *s, int base_channel)
             }
 
             if ((s->core_downmix = get_bits1(&s->gb))) {
-                switch (get_bits(&s->gb, 3)) {
+                int am = get_bits(&s->gb, 3);
+                switch (am) {
                 case 0:
                     s->core_downmix_amode = DCA_MONO;
                     break;
@@ -1325,13 +1343,20 @@ static int dca_subframe_footer(DCAContext *s, int base_channel)
                     s->core_downmix_amode = DCA_3F1R;
                     break;
                 default:
+                    av_log(s->avctx, AV_LOG_ERROR,
+                           "Invalid mode %d for embedded downmix coefficients\n",
+                           am);
                     return AVERROR_INVALIDDATA;
                 }
                 for (out = 0; out < dca_channels[s->core_downmix_amode]; out++) {
                     for (in = 0; in < s->prim_channels + !!s->lfe; in++) {
                         uint16_t tmp = get_bits(&s->gb, 9);
-                        if ((tmp & 0xFF) > 241)
+                        if ((tmp & 0xFF) > 241) {
+                            av_log(s->avctx, AV_LOG_ERROR,
+                                   "Invalid downmix coefficient code %"PRIu16"\n",
+                                   tmp);
                             return AVERROR_INVALIDDATA;
+                        }
                         s->core_downmix_codes[in][out] = tmp;
                     }
                 }
@@ -1341,9 +1366,11 @@ static int dca_subframe_footer(DCAContext *s, int base_channel)
             skip_bits(&s->gb, 16);  // nAUXCRC16
 
             // additional data (reserved, cf. ETSI TS 102 114 V1.4.1)
-            if ((reserved = (aux_data_end - get_bits_count(&s->gb))) < 0)
+            if ((reserved = (aux_data_end - get_bits_count(&s->gb))) < 0) {
+                 av_log(s->avctx, AV_LOG_ERROR,
+                        "Overread auxiliary data by %d bits\n", -reserved);
                 return AVERROR_INVALIDDATA;
-            else if (reserved) {
+            else if (reserved) {
                 avpriv_request_sample(s->avctx,
                                       "Core auxiliary data reserved content");
                 skip_bits_long(&s->gb, reserved);
@@ -1831,11 +1858,12 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
 
 #if FF_API_REQUEST_CHANNELS
 FF_DISABLE_DEPRECATION_WARNINGS
-        if (s->xch_present && (!avctx->request_channels ||
-                               avctx->request_channels > num_core_channels + !!s->lfe)) {
+        if (s->xch_present && !s->xch_disable &&
+            (!avctx->request_channels ||
+             avctx->request_channels > num_core_channels + !!s->lfe)) {
 FF_ENABLE_DEPRECATION_WARNINGS
 #else
-        if (s->xch_present) {
+        if (s->xch_present && !s->xch_disable) {
 #endif
             avctx->channel_layout |= AV_CH_BACK_CENTER;
             if (s->lfe) {
@@ -1858,22 +1886,21 @@ FF_ENABLE_DEPRECATION_WARNINGS
             s->channel_order_tab[channels - 1 - !!s->lfe] < 0)
             return AVERROR_INVALIDDATA;
 
-        if (s->prim_channels > 2 &&
+        if (s->prim_channels + !!s->lfe > 2 &&
             avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
             channels = 2;
-            s->output = DCA_STEREO;
+            s->output = s->prim_channels == 2 ? s->amode : DCA_STEREO;
             avctx->channel_layout = AV_CH_LAYOUT_STEREO;
 
             /* Stereo downmix coefficients
              *
              * The decoder can only downmix to 2-channel, so we need to ensure
              * embedded downmix coefficients are actually targeting 2-channel.
-             *
-             * Coefficients for the LFE channel are ignored (not supported) */
+             */
             if (s->core_downmix && (s->core_downmix_amode == DCA_STEREO ||
                                     s->core_downmix_amode == DCA_STEREO_TOTAL)) {
                 int sign, code;
-                for (i = 0; i < s->prim_channels; i++) {
+                for (i = 0; i < s->prim_channels + !!s->lfe; i++) {
                     sign = s->core_downmix_codes[i][0] & 0x100 ? 1 : -1;
                     code = s->core_downmix_codes[i][0] & 0x0FF;
                     s->downmix_coef[i][0] = (!code ? 0.0f :
@@ -1883,6 +1910,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
                     s->downmix_coef[i][1] = (!code ? 0.0f :
                                              sign * dca_dmixtable[code - 1]);
                 }
+                s->output = s->core_downmix_amode;
             } else {
                 int am = s->amode & DCA_CHANNEL_MASK;
                 if (am >= FF_ARRAY_ELEMS(dca_default_coeffs)) {
@@ -1890,18 +1918,19 @@ FF_ENABLE_DEPRECATION_WARNINGS
                            "Invalid channel mode %d\n", am);
                     return AVERROR_INVALIDDATA;
                 }
-                if (s->prim_channels > FF_ARRAY_ELEMS(dca_default_coeffs[0])) {
+                if (s->prim_channels + !!s->lfe >
+                    FF_ARRAY_ELEMS(dca_default_coeffs[0])) {
                     avpriv_request_sample(s->avctx, "Downmixing %d channels",
-                                          s->prim_channels);
+                                          s->prim_channels + !!s->lfe);
                     return AVERROR_PATCHWELCOME;
                 }
-                for (i = 0; i < s->prim_channels; i++) {
+                for (i = 0; i < s->prim_channels + !!s->lfe; i++) {
                     s->downmix_coef[i][0] = dca_default_coeffs[am][i][0];
                     s->downmix_coef[i][1] = dca_default_coeffs[am][i][1];
                 }
             }
             av_dlog(s->avctx, "Stereo downmix coeffs:\n");
-            for (i = 0; i < s->prim_channels; i++) {
+            for (i = 0; i < s->prim_channels + !!s->lfe; i++) {
                 av_dlog(s->avctx, "L, input channel %d = %f\n", i,
                         s->downmix_coef[i][0]);
                 av_dlog(s->avctx, "R, input channel %d = %f\n", i,
@@ -1971,6 +2000,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
     for (i = 0; i < 2 * s->lfe * 4; i++)
         s->lfe_data[i] = s->lfe_data[i + lfe_samples];
 
+    /* AVMatrixEncoding
+     *
+     * DCA_STEREO_TOTAL (Lt/Rt) is equivalent to Dolby Surround */
+    ret = ff_side_data_update_matrix_encoding(frame,
+                                              (s->output & ~DCA_LFE) == DCA_STEREO_TOTAL ?
+                                              AV_MATRIX_ENCODING_DOLBY : AV_MATRIX_ENCODING_NONE);
+    if (ret < 0)
+        return ret;
+
     *got_frame_ptr = 1;
 
     return buf_size;
@@ -2030,6 +2068,18 @@ static const AVProfile profiles[] = {
     { FF_PROFILE_UNKNOWN },
 };
 
+static const AVOption options[] = {
+    { "disable_xch", "disable decoding of the XCh extension", offsetof(DCAContext, xch_disable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_AUDIO_PARAM },
+    { NULL },
+};
+
+static const AVClass dca_decoder_class = {
+    .class_name = "DCA decoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 AVCodec ff_dca_decoder = {
     .name            = "dca",
     .long_name       = NULL_IF_CONFIG_SMALL("DCA (DTS Coherent Acoustics)"),
@@ -2043,4 +2093,5 @@ AVCodec ff_dca_decoder = {
     .sample_fmts     = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                        AV_SAMPLE_FMT_NONE },
     .profiles        = NULL_IF_CONFIG_SMALL(profiles),
+    .priv_class      = &dca_decoder_class,
 };