diff mbox series

[FFmpeg-devel,4/7] libavfilter: Add filter to insert AFD/bar data

Message ID 1686169347-28987-5-git-send-email-dheitmueller@ltnglobal.com
State New
Headers show
Series Misc AFD improvements and support for Bar Data | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Devin Heitmueller June 7, 2023, 8:22 p.m. UTC
Introduce a new filter which allows the user to manually set the
AFD or bar data side data on AVFrames.

Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com>
---
 doc/filters.texi         |  52 ++++++++++++++++++
 libavfilter/Makefile     |   1 +
 libavfilter/allfilters.c |   1 +
 libavfilter/vf_afd.c     | 133 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 187 insertions(+)
 create mode 100644 libavfilter/vf_afd.c
diff mbox series

Patch

diff --git a/doc/filters.texi b/doc/filters.texi
index 9179c20..18aa998 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -21208,6 +21208,58 @@  This filter use field-dominance information in frame to decide which
 of each pair of fields to place first in the output.
 If it gets it wrong use @ref{setfield} filter before @code{separatefields} filter.
 
+@section setafd
+
+The @code{setafd} filter sets the Aspect Ratio Description side data for the
+output video.
+
+This filter allows configuration of AFD metadata (conforming to
+ETSI TS 101 154 or SMPTE ST2016-1), as well as Bar Data (conforming to
+SMPTE 2016-1, ATSC A/53, and SCTE 128-1)
+
+It accepts the following parameters:
+
+@table @option
+
+@item afd
+This parameters dictates whether AFD side data will be injected.  It is
+enabled by default.
+
+@item code
+If AFD output is enabled, this parameter will specify the AFD code to
+insert into the video stream.  Valid values are from 0x00 to 0x0f.
+
+@item bardata
+This parameter dictates whether bar data will be injected.  It is
+disabled by default.
+
+@item top
+@item bottom
+@item left
+@item right
+If bardata output is enabled, These parameters specify the dimensions
+of the bar data.  Typically only top/bottom or left/right would be specified.
+If either top or bottom are specified, the bar data inserted will be for those
+parameters (even if left/right are also specified).
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Set the AFD value to 0x08
+@example
+ffmpeg -i INPUT -vf setafd=code=0x08 OUTPUT
+@end example
+@item
+Set the Bar data to a top width of 100 and a bottom width of 120
+@example
+ffmpeg -i INPUT -vf setafd=afd=0:bardata=1:top=100:bottom=120 OUTPUT
+@end example
+
+@end itemize
+
 @section setdar, setsar
 
 The @code{setdar} filter sets the Display Aspect Ratio for the filter
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 18935b1..30954e1 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -467,6 +467,7 @@  OBJS-$(CONFIG_SELECTIVECOLOR_FILTER)         += vf_selectivecolor.o
 OBJS-$(CONFIG_SENDCMD_FILTER)                += f_sendcmd.o
 OBJS-$(CONFIG_SEPARATEFIELDS_FILTER)         += vf_separatefields.o
 OBJS-$(CONFIG_SETDAR_FILTER)                 += vf_aspect.o
+OBJS-$(CONFIG_SETAFD_FILTER)                 += vf_afd.o
 OBJS-$(CONFIG_SETFIELD_FILTER)               += vf_setparams.o
 OBJS-$(CONFIG_SETPARAMS_FILTER)              += vf_setparams.o
 OBJS-$(CONFIG_SETPTS_FILTER)                 += setpts.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index f1f7811..2ec9487 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -437,6 +437,7 @@  extern const AVFilter ff_vf_select;
 extern const AVFilter ff_vf_selectivecolor;
 extern const AVFilter ff_vf_sendcmd;
 extern const AVFilter ff_vf_separatefields;
+extern const AVFilter ff_vf_setafd;
 extern const AVFilter ff_vf_setdar;
 extern const AVFilter ff_vf_setfield;
 extern const AVFilter ff_vf_setparams;
diff --git a/libavfilter/vf_afd.c b/libavfilter/vf_afd.c
new file mode 100644
index 0000000..a6120c8
--- /dev/null
+++ b/libavfilter/vf_afd.c
@@ -0,0 +1,133 @@ 
+/*
+ * AFD and Bardata Insertion Filter
+ * Copyright (c) 2023 LTN Global Communications
+ *
+ * Author: Devin Heitmueller <dheitmueller@ltnglobal.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * 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.
+ *
+ * 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Active Format Description and Bar Data Insertion Filter
+ */
+
+#include "libavcodec/defs.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct AFDContext {
+    const AVClass *class;
+    int enable_afd;
+    int afd_code;
+    int enable_bardata;
+    int top;
+    int bottom;
+    int left;
+    int right;
+} AFDContext;
+
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
+{
+    AFDContext *s = link->dst->priv;
+    AVFrameSideData *side_data;
+    AVBarData *bar_data;
+
+    /* Insert/tweak the side-data for AFD */
+    if (s->enable_afd) {
+        /* Insert/tweak the side-data for Bar Data */
+        side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_AFD);
+        if (!side_data) {
+            side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_AFD, sizeof(unsigned char));
+            if (side_data == NULL)
+                return -ENOMEM;
+        }
+        side_data->data[0] = s->afd_code;
+    }
+
+    if (s->enable_bardata) {
+        /* Insert/tweak the side-data for Bar Data */
+        side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_BARDATA);
+        if (!side_data) {
+            side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_BARDATA, sizeof(AVBarData));
+            if (side_data == NULL)
+                return -ENOMEM;
+        }
+        bar_data = (AVBarData *) side_data->data;
+        if (s->top || s->bottom) {
+            bar_data->top_bottom = 1;
+            bar_data->top = s->top;
+            bar_data->bottom = s->bottom;
+            bar_data->left = 0;
+            bar_data->right = 0;
+        } else {
+            bar_data->top_bottom = 0;
+            bar_data->top = 0;
+            bar_data->bottom = 0;
+            bar_data->left = s->left;
+            bar_data->right = s->right;
+        }
+    }
+
+    return ff_filter_frame(link->dst->outputs[0], frame);
+}
+
+#define OFFSET(x) offsetof(AFDContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption setafd_options[] = {
+    /* AFD Options */
+    { "afd",    "Enable AFD insertion", OFFSET(enable_afd), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, .flags = FLAGS },
+    { "code",   "AFD code to insert", OFFSET(afd_code), AV_OPT_TYPE_INT, {.i64=0}, 0, 0x0F, FLAGS },
+
+    /* Bar data Options */
+    { "bardata","Enable Bar Data insertion", OFFSET(enable_bardata), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, .flags = FLAGS },
+    { "top",   "top bar position", OFFSET(top), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+    { "bottom","bottom bar position", OFFSET(bottom), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+    { "left",  "left bar position", OFFSET(left), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+    { "right", "right bar position", OFFSET(right), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(setafd);
+
+static const AVFilterPad avfilter_vf_setafd_inputs[] = {
+    {
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_VIDEO,
+        .filter_frame = filter_frame,
+    },
+};
+
+static const AVFilterPad avfilter_vf_setafd_outputs[] = {
+    {
+        .name = "default",
+        .type = AVMEDIA_TYPE_VIDEO,
+    },
+};
+
+const AVFilter ff_vf_setafd = {
+    .name        = "setafd",
+    .description = NULL_IF_CONFIG_SMALL("Set AFD and/or Bar Data for video frames"),
+    .priv_size   = sizeof(AFDContext),
+    .priv_class  = &setafd_class,
+    .flags       = AVFILTER_FLAG_METADATA_ONLY,
+    FILTER_INPUTS(avfilter_vf_setafd_inputs),
+    FILTER_OUTPUTS(avfilter_vf_setafd_outputs),
+};