Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/libdcadec.c')
-rw-r--r--libavcodec/libdcadec.c80
1 files changed, 71 insertions, 9 deletions
diff --git a/libavcodec/libdcadec.c b/libavcodec/libdcadec.c
index 3ab3b1a652..62a3672d6b 100644
--- a/libavcodec/libdcadec.c
+++ b/libavcodec/libdcadec.c
@@ -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);