aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2016-08-26 16:12:30 +0200
committerLuca Barbato <lu_zero@gentoo.org>2016-08-29 19:09:59 +0200
commit728e80cd2e1d4b7c3e26489efcd77bd7a9e84a99 (patch)
tree77fa0700ed362642136a2f958fe55041d5b6150c
parent95f80293456d9d4b1b096621260c38bc90325ec0 (diff)
downloadffmpeg-728e80cd2e1d4b7c3e26489efcd77bd7a9e84a99.tar.gz
High Definition Compatible Digital (HDCD) decoder filter, using libhdcd
Signed-off-by: Burt P <pburt0@gmail.com> Signed-off-by: Diego Biurrun <diego@biurrun.de> Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
-rw-r--r--Changelog1
-rwxr-xr-xconfigure4
-rw-r--r--doc/filters.texi47
-rw-r--r--doc/general.texi9
-rw-r--r--libavfilter/Makefile1
-rw-r--r--libavfilter/af_hdcd.c197
-rw-r--r--libavfilter/allfilters.c1
-rw-r--r--libavfilter/version.h2
8 files changed, 261 insertions, 1 deletions
diff --git a/Changelog b/Changelog
index 0d04f476e7..b6c8fdbf2a 100644
--- a/Changelog
+++ b/Changelog
@@ -62,6 +62,7 @@ version <next>:
- Intel QSV video scaling and deinterlacing filter
- OpenH264 decoder wrapper
- Removed the legacy X11 screen grabber, use XCB instead
+- HDCD decoding filter through libhdcd
version 11:
diff --git a/configure b/configure
index e7bf5371f3..660b06284a 100755
--- a/configure
+++ b/configure
@@ -197,6 +197,7 @@ External library support:
--enable-libfontconfig font configuration and management
--enable-libfreetype font rendering
--enable-libgsm GSM audio encoding/decoding
+ --enable-libhdcd HDCD decoding filter
--enable-libilbc ILBC audio encoding/decoding
--enable-libkvazaar HEVC video encoding
--enable-libmp3lame MP3 audio encoding
@@ -1270,6 +1271,7 @@ EXTERNAL_LIBRARY_LIST="
libfontconfig
libfreetype
libgsm
+ libhdcd
libilbc
libkvazaar
libmp3lame
@@ -2426,6 +2428,7 @@ frei0r_filter_deps="frei0r dlopen"
frei0r_filter_extralibs='$ldl'
frei0r_src_filter_deps="frei0r dlopen"
frei0r_src_filter_extralibs='$ldl'
+hdcd_filter_deps="libhdcd"
hqdn3d_filter_deps="gpl"
interlace_filter_deps="gpl"
ocv_filter_deps="libopencv"
@@ -4606,6 +4609,7 @@ enabled libfreetype && require_pkg_config freetype2 "ft2build.h FT_FREETYP
enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
check_lib "${gsm_hdr}" gsm_create -lgsm && break;
done || die "ERROR: libgsm not found"; }
+enabled libhdcd && require_pkg_config libhdcd "hdcd/hdcd_simple.h" hdcd_new
enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc
enabled libkvazaar && require_pkg_config "kvazaar >= 0.8.1" kvazaar.h kvz_api_get
enabled libmfx && require_pkg_config libmfx "mfx/mfxvideo.h" MFXInit
diff --git a/doc/filters.texi b/doc/filters.texi
index 2651f170a0..954765f08e 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -647,6 +647,53 @@ avconv -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
out
@end example
+@section hdcd
+
+Decodes High Definition Compatible Digital (HDCD) data. A 16-bit PCM stream with
+embedded HDCD codes is expanded into a 20-bit PCM stream.
+
+The filter supports the Peak Extend and Low-level Gain Adjustment features
+of HDCD, and detects the Transient Filter flag.
+
+@example
+avconv -i HDCD16.flac -af hdcd OUT24.flac
+@end example
+
+When using the filter with WAV, note that the default encoding for WAV is 16-bit,
+so the resulting 20-bit stream will be truncated back to 16-bit. Use something
+like @command{-acodec pcm_s24le} after the filter to get 24-bit PCM output.
+@example
+avconv -i HDCD16.wav -af hdcd OUT16.wav
+avconv -i HDCD16.wav -af hdcd -acodec pcm_s24le OUT24.wav
+@end example
+
+The filter accepts the following options:
+
+@table @option
+@item analyze_mode
+Replace audio with a solid tone and adjust the amplitude to signal some
+specific aspect of the decoding process. The output file can be loaded in
+an audio editor alongside the original to aid analysis.
+
+Modes are:
+@table @samp
+@item 0, off
+Disabled
+@item 1, lle
+Gain adjustment level at each sample
+@item 2, pe
+Samples where peak extend occurs
+@item 3, cdt
+Samples where the code detect timer is active
+@item 4, tgm
+Samples where the target gain does not match between channels
+@item 5, pel
+Any samples above peak extend level
+@item 6, ltgm
+Gain adjustment level at each sample, in each channel
+@end table
+@end table
+
@section resample
Convert the audio sample format, sample rate and channel layout. It is
not meant to be used directly; it is inserted automatically by libavfilter
diff --git a/doc/general.texi b/doc/general.texi
index ea56beff92..1708871d8a 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -157,6 +157,15 @@ Go to @url{https://github.com/dekkers/libilbc} and follow the instructions for
installing the library. Then pass @code{--enable-libilbc} to configure to
enable it.
+@section libhdcd
+
+Libav can make use of the libhdcd library for High Definition Compatible
+Digital (HDCD) decoding via the @code{hdcd} filter.
+
+Go to @url{https://github.com/bp0/libhdcd} and follow the instructions for
+installing the library. Then pass @code{--enable-libhdcd} to configure to
+enable it.
+
@section AviSynth
Libav can read AviSynth scripts as input. To enable support you need a
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index dea8ffa50f..c3c1beaa0f 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -34,6 +34,7 @@ OBJS-$(CONFIG_BS2B_FILTER) += af_bs2b.o
OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o
OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o
OBJS-$(CONFIG_COMPAND_FILTER) += af_compand.o
+OBJS-$(CONFIG_HDCD_FILTER) += af_hdcd.o
OBJS-$(CONFIG_JOIN_FILTER) += af_join.o
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o
diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c
new file mode 100644
index 0000000000..b9dadecca4
--- /dev/null
+++ b/libavfilter/af_hdcd.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav 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,
+ * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * HDCD decoding filter, using libhdcd
+ */
+
+#include <hdcd/hdcd_simple.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+
+#include "audio.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+typedef struct HDCDContext {
+ const AVClass *class;
+
+ hdcd_simple *shdcd;
+
+ /* AVOption members */
+ /** analyze mode replaces the audio with a solid tone and adjusts
+ * the amplitude to signal some specific aspect of the decoding
+ * process. See docs or HDCD_ANA_* defines. */
+ int analyze_mode;
+ /* end AVOption members */
+} HDCDContext;
+
+#define OFFSET(x) offsetof(HDCDContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define HDCD_ANA_MAX 6
+static const AVOption hdcd_options[] = {
+ { "analyze_mode", "Replace audio with solid tone and signal some processing aspect in the amplitude.",
+ OFFSET(analyze_mode), AV_OPT_TYPE_INT, { .i64=HDCD_ANA_OFF }, 0, HDCD_ANA_MAX, A, "analyze_mode"},
+ { "off", HDCD_ANA_OFF_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_OFF}, 0, 0, A, "analyze_mode" },
+ { "lle", HDCD_ANA_LLE_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_LLE}, 0, 0, A, "analyze_mode" },
+ { "pe", HDCD_ANA_PE_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_PE}, 0, 0, A, "analyze_mode" },
+ { "cdt", HDCD_ANA_CDT_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_CDT}, 0, 0, A, "analyze_mode" },
+ { "tgm", HDCD_ANA_TGM_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_TGM}, 0, 0, A, "analyze_mode" },
+ { "pel", HDCD_ANA_PEL_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_PEL}, 0, 0, A, "analyze_mode" },
+ { "ltgm", HDCD_ANA_LTGM_DESC, 0, AV_OPT_TYPE_CONST, { .i64 = HDCD_ANA_LTGM}, 0, 0, A, "analyze_mode" },
+ { NULL }
+};
+
+static const AVClass hdcd_class = {
+ .class_name = "HDCD filter",
+ .item_name = av_default_item_name,
+ .option = hdcd_options,
+ .version = LIBAVFILTER_VERSION_INT,
+};
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ HDCDContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ const int16_t *in_data;
+ int32_t *out_data;
+ int n, result;
+ int channel_count = av_get_channel_layout_nb_channels(in->channel_layout);
+
+ out = ff_get_audio_buffer(outlink, in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ result = av_frame_copy_props(out, in);
+ if (result) {
+ av_frame_free(&out);
+ av_frame_free(&in);
+ return result;
+ }
+
+ in_data = (int16_t *)in->data[0];
+ out_data = (int32_t *)out->data[0];
+ for (n = 0; n < in->nb_samples * channel_count; n++)
+ out_data[n] = in_data[n];
+
+ hdcd_process(s->shdcd, out_data, in->nb_samples);
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *in_formats, *out_formats, *sample_rates = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ static const enum AVSampleFormat sample_fmts_in[] = {
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE
+ };
+ static const enum AVSampleFormat sample_fmts_out[] = {
+ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_NONE
+ };
+
+ ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
+
+ ff_set_common_channel_layouts(ctx, layouts);
+
+ in_formats = ff_make_format_list(sample_fmts_in);
+ out_formats = ff_make_format_list(sample_fmts_out);
+ if (!in_formats || !out_formats)
+ return AVERROR(ENOMEM);
+
+ ff_formats_ref(in_formats, &inlink->out_formats);
+ ff_formats_ref(out_formats, &outlink->in_formats);
+
+ ff_add_format(&sample_rates, 44100);
+ ff_set_common_samplerates(ctx, sample_rates);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ HDCDContext *s = ctx->priv;
+ char detect_str[256] = "";
+
+ /* log the HDCD decode information */
+ hdcd_detect_str(s->shdcd, detect_str, sizeof(detect_str));
+ av_log(ctx, AV_LOG_INFO, "%s\n", detect_str);
+
+ hdcd_free(s->shdcd);
+}
+
+/** callback for error logging */
+static void af_hdcd_log(const void *priv, const char *fmt, va_list args)
+{
+ av_vlog((AVFilterContext *)priv, AV_LOG_VERBOSE, fmt, args);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ HDCDContext *s = ctx->priv;
+
+ s->shdcd = hdcd_new();
+ hdcd_logger_attach(s->shdcd, af_hdcd_log, ctx);
+
+ if (s->analyze_mode)
+ hdcd_analyze_mode(s->shdcd, s->analyze_mode);
+ av_log(ctx, AV_LOG_VERBOSE, "Analyze mode: [%d] %s\n",
+ s->analyze_mode, hdcd_str_analyze_mode_desc(s->analyze_mode));
+
+ return 0;
+}
+
+static const AVFilterPad avfilter_af_hdcd_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_af_hdcd_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_hdcd = {
+ .name = "hdcd",
+ .description = NULL_IF_CONFIG_SMALL("Apply High Definition Compatible Digital (HDCD) decoding."),
+ .priv_size = sizeof(HDCDContext),
+ .priv_class = &hdcd_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = avfilter_af_hdcd_inputs,
+ .outputs = avfilter_af_hdcd_outputs,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index de49d65298..ec27b5ae6e 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -57,6 +57,7 @@ void avfilter_register_all(void)
REGISTER_FILTER(CHANNELMAP, channelmap, af);
REGISTER_FILTER(CHANNELSPLIT, channelsplit, af);
REGISTER_FILTER(COMPAND, compand, af);
+ REGISTER_FILTER(HDCD, hdcd, af);
REGISTER_FILTER(JOIN, join, af);
REGISTER_FILTER(RESAMPLE, resample, af);
REGISTER_FILTER(VOLUME, volume, af);
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 7f3ede2d04..febfc8fa1d 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 6
-#define LIBAVFILTER_VERSION_MINOR 6
+#define LIBAVFILTER_VERSION_MINOR 7
#define LIBAVFILTER_VERSION_MICRO 0
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \