#include "internal.h"
typedef struct DCADecContext {
+ const AVClass *class;
struct dcadec_context *ctx;
uint8_t *buffer;
int buffer_size;
- int downmix_warned;
+ int lfe_filter;
+ int core_only;
} DCADecContext;
+static void my_log_cb(int level, const char *file, int line,
+ const char *message, void *cbarg)
+{
+ int av_level;
+
+ switch (level) {
+ case DCADEC_LOG_ERROR:
+ av_level = AV_LOG_ERROR;
+ break;
+ case DCADEC_LOG_WARNING:
+ av_level = AV_LOG_WARNING;
+ break;
+ case DCADEC_LOG_INFO:
+ av_level = AV_LOG_INFO;
+ break;
+ case DCADEC_LOG_VERBOSE:
+ av_level = AV_LOG_VERBOSE;
+ break;
+ case DCADEC_LOG_DEBUG:
+ default:
+ av_level = AV_LOG_DEBUG;
+ break;
+ }
+
+ av_log(cbarg, av_level, "%s\n", message);
+}
+
static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
&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_EXTERNAL;
- } else if (ret > 0) {
- av_log(avctx, AV_LOG_WARNING, "dcadec_context_filter() warning: %d (%s)\n", ret, dcadec_strerror(ret));
}
avctx->channels = av_get_channel_layout_nb_channels(channel_mask);
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;
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) {
+ if (avctx->err_recognition & AV_EF_EXPLODE)
+ flags |= DCADEC_FLAG_STRICT;
+
+ if (avctx->request_channel_layout) {
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;
+ flags |= DCADEC_FLAG_KEEP_DMIX_2CH;
break;
case AV_CH_LAYOUT_5POINT1:
flags |= DCADEC_FLAG_KEEP_DMIX_6CH;
break;
+ case AV_CH_LAYOUT_NATIVE:
+ flags |= DCADEC_FLAG_NATIVE_LAYOUT;
+ break;
default:
av_log(avctx, AV_LOG_WARNING, "Invalid request_channel_layout\n");
break;
}
}
+ if (s->core_only)
+ flags |= DCADEC_FLAG_CORE_ONLY;
+
+ switch (s->lfe_filter) {
+#if DCADEC_API_VERSION >= DCADEC_VERSION_CODE(0, 1, 0)
+ case 1:
+ flags |= DCADEC_FLAG_CORE_LFE_IIR;
+ break;
+#endif
+ case 2:
+ flags |= DCADEC_FLAG_CORE_LFE_FIR;
+ break;
+ }
+
s->ctx = dcadec_context_create(flags);
if (!s->ctx)
return AVERROR(ENOMEM);
+ dcadec_context_set_log_cb(s->ctx, my_log_cb, avctx);
+
avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
avctx->bits_per_raw_sample = 24;
return 0;
}
+#define OFFSET(x) offsetof(DCADecContext, x)
+#define PARAM AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption dcadec_options[] = {
+ { "lfe_filter", "Lossy LFE channel interpolation filter", OFFSET(lfe_filter), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, PARAM, "lfe_filter" },
+ { "default", "Library default", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, PARAM, "lfe_filter" },
+ { "iir", "IIR filter", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, PARAM, "lfe_filter" },
+ { "fir", "FIR filter", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, PARAM, "lfe_filter" },
+ { "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 = "libdcadec 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" },
.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_NONE },
+ .priv_class = &dcadec_class,
.profiles = NULL_IF_CONFIG_SMALL(profiles),
};