]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/libdcadec.c
Merge commit '7c6eb0a1b7bf1aac7f033a7ec6d8cacc3b5c2615'
[ffmpeg] / libavcodec / libdcadec.c
index 3ab3b1a6524a21dc3801380ac4462b2dc3f3c63d..62a3672d6ba0394c8c3ef4a2b36cc58aeadbd29e 100644 (file)
@@ -2,20 +2,20 @@
  * libdcadec decoder wrapper
  * Copyright (C) 2015 Hendrik Leppkes
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * 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.
  *
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -34,6 +34,7 @@ typedef struct DCADecContext {
     struct dcadec_context *ctx;
     uint8_t *buffer;
     int buffer_size;
+    int downmix_warned;
 } DCADecContext;
 
 static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
@@ -41,6 +42,7 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
 {
     DCADecContext *s = avctx->priv_data;
     AVFrame *frame = data;
+    struct dcadec_exss_info *exss;
     int ret, i, k;
     int **samples, nsamples, channel_mask, sample_rate, bits_per_sample, profile;
     uint32_t mrk;
@@ -58,7 +60,10 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
         if (!s->buffer)
             return AVERROR(ENOMEM);
 
-        if ((ret = ff_dca_convert_bitstream(avpkt->data, avpkt->size, s->buffer, s->buffer_size)) < 0)
+        for (i = 0, ret = AVERROR_INVALIDDATA; i < input_size - 3 && 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;
@@ -67,12 +72,12 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
 
     if ((ret = dcadec_context_parse(s->ctx, input, input_size)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "dcadec_context_parse() failed: %d (%s)\n", -ret, dcadec_strerror(ret));
-        return AVERROR_UNKNOWN;
+        return AVERROR_EXTERNAL;
     }
     if ((ret = dcadec_context_filter(s->ctx, &samples, &nsamples, &channel_mask,
                                      &sample_rate, &bits_per_sample, &profile)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "dcadec_context_filter() failed: %d (%s)\n", -ret, dcadec_strerror(ret));
-        return AVERROR_UNKNOWN;
+        return AVERROR_EXTERNAL;
     }
 
     avctx->channels       = av_get_channel_layout_nb_channels(channel_mask);
@@ -81,7 +86,7 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
 
     if (bits_per_sample == 16)
         avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
-    else if (bits_per_sample <= 24)
+    else if (bits_per_sample > 16 && bits_per_sample <= 24)
         avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
     else {
         av_log(avctx, AV_LOG_ERROR, "Unsupported number of bits per sample: %d\n",
@@ -124,6 +129,37 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
     } else
         avctx->bit_rate = 0;
 
+#if HAVE_STRUCT_DCADEC_EXSS_INFO_MATRIX_ENCODING
+    if (exss = dcadec_context_get_exss_info(s->ctx)) {
+        enum AVMatrixEncoding matrix_encoding = AV_MATRIX_ENCODING_NONE;
+
+        if (!s->downmix_warned) {
+            uint64_t layout = avctx->request_channel_layout;
+
+            if (((layout == AV_CH_LAYOUT_STEREO_DOWNMIX || layout == AV_CH_LAYOUT_STEREO) && !exss->embedded_stereo) ||
+                ( layout == AV_CH_LAYOUT_5POINT1 && !exss->embedded_6ch))
+                av_log(avctx, AV_LOG_WARNING, "%s downmix was requested but no custom coefficients are available, "
+                                              "this may result in clipping\n",
+                                              layout == AV_CH_LAYOUT_5POINT1 ? "5.1" : "Stereo");
+            s->downmix_warned = 1;
+        }
+
+        switch(exss->matrix_encoding) {
+        case DCADEC_MATRIX_ENCODING_SURROUND:
+            matrix_encoding = AV_MATRIX_ENCODING_DOLBY;
+            break;
+        case DCADEC_MATRIX_ENCODING_HEADPHONE:
+            matrix_encoding = AV_MATRIX_ENCODING_DOLBYHEADPHONE;
+            break;
+        }
+        dcadec_context_free_exss_info(exss);
+
+        if (matrix_encoding != AV_MATRIX_ENCODING_NONE &&
+            (ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0)
+            return ret;
+    }
+#endif
+
     frame->nb_samples = nsamples;
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
         return ret;
@@ -167,8 +203,34 @@ static av_cold int dcadec_close(AVCodecContext *avctx)
 static av_cold int dcadec_init(AVCodecContext *avctx)
 {
     DCADecContext *s = avctx->priv_data;
+    int flags = 0;
+
+    /* Affects only lossy DTS profiles. DTS-HD MA is always bitexact */
+    if (avctx->flags & AV_CODEC_FLAG_BITEXACT)
+        flags |= DCADEC_FLAG_CORE_BIT_EXACT;
+
+    if (avctx->request_channel_layout > 0 && avctx->request_channel_layout != AV_CH_LAYOUT_NATIVE) {
+        switch (avctx->request_channel_layout) {
+        case AV_CH_LAYOUT_STEREO:
+        case AV_CH_LAYOUT_STEREO_DOWNMIX:
+            /* libdcadec ignores the 2ch flag if used alone when no custom downmix coefficients
+               are available, silently outputting a 5.1 downmix if possible instead.
+               Using both the 2ch and 6ch flags together forces a 2ch downmix using default
+               coefficients in such cases. This matches the behavior of the 6ch flag when used
+               alone, where a 5.1 downmix is generated if possible, regardless of custom
+               coefficients being available or not. */
+            flags |= DCADEC_FLAG_KEEP_DMIX_2CH | DCADEC_FLAG_KEEP_DMIX_6CH;
+            break;
+        case AV_CH_LAYOUT_5POINT1:
+            flags |= DCADEC_FLAG_KEEP_DMIX_6CH;
+            break;
+        default:
+            av_log(avctx, AV_LOG_WARNING, "Invalid request_channel_layout\n");
+            break;
+        }
+    }
 
-    s->ctx = dcadec_context_create(0);
+    s->ctx = dcadec_context_create(flags);
     if (!s->ctx)
         return AVERROR(ENOMEM);