[FFmpeg-devel] [PATCH] avfilter: add uhdtvbars video source filter
Paul B Mahol
onemda at gmail.com
Tue Dec 24 19:21:58 EET 2019
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/vsrc_testsrc.c | 331 +++++++++++++++++++++++++++++++++++++
3 files changed, 333 insertions(+)
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 37d4eee858..477fd3727b 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -469,6 +469,7 @@ OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_TESTSRC_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_TESTSRC2_FILTER) += vsrc_testsrc.o
+OBJS-$(CONFIG_UHDTVBARS_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_YUVTESTSRC_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index c295f8e403..fce2cf41c5 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -447,6 +447,7 @@ extern AVFilter ff_vsrc_smptebars;
extern AVFilter ff_vsrc_smptehdbars;
extern AVFilter ff_vsrc_testsrc;
extern AVFilter ff_vsrc_testsrc2;
+extern AVFilter ff_vsrc_uhdtvbars;
extern AVFilter ff_vsrc_yuvtestsrc;
extern AVFilter ff_vsink_nullsink;
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index 3c9ddd5b16..7d313ffa58 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -79,6 +79,10 @@ typedef struct TestSourceContext {
/* only used by haldclut */
int level;
+
+ /* only used by uhdtvbars */
+ int simple;
+ int mode;
} TestSourceContext;
#define OFFSET(x) offsetof(TestSourceContext, x)
@@ -1803,3 +1807,330 @@ AVFilter ff_vsrc_allrgb = {
};
#endif /* CONFIG_ALLRGB_FILTER */
+
+#ifdef CONFIG_UHDTVBARS_FILTER
+
+static const AVOption uhdtvbars_options[] = {
+ COMMON_OPTIONS_NOSIZE
+ { "simple", "use simple bars", OFFSET(simple), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+ { "mode", "set bars mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "mode" },
+ { "4k", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
+ { "8k", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(uhdtvbars);
+
+static int uhdtvbars_query_formats(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+ static const enum AVPixelFormat pix_fmts10[] = {
+ AV_PIX_FMT_GBRP10,
+ AV_PIX_FMT_NONE,
+ };
+ static const enum AVPixelFormat pix_fmts12[] = {
+ AV_PIX_FMT_GBRP12,
+ AV_PIX_FMT_NONE,
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(test->mode ? pix_fmts12 : pix_fmts10);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const uint8_t order[3] = { 1, 2, 0 };
+
+static void draw_bar16(int f, const uint16_t color[4],
+ int x, int y, int w, int h,
+ AVFrame *frame)
+{
+ uint16_t *p, *p0;
+
+ x *= f;
+ y *= f;
+ w *= f;
+ h *= f;
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int c = color[comp];
+ const int linesize = frame->linesize[plane];
+
+ p = p0 = (uint16_t *)(frame->data[plane] + y * linesize + x * 2);
+ for (int i = 0; i < w; i++)
+ p[i] = c;
+ p += linesize / 2;
+ for (int i = 1; i < h; i++, p += linesize / 2)
+ memcpy(p, p0, w * 2);
+ }
+}
+
+static const uint16_t uhdtv_gray40[2][3] = { { 414, 414, 414 }, { 1656, 1656, 1656 } };
+static const uint16_t uhdtv_yellow40[2][3] = { { 414, 426, 283 }, { 1656, 1704, 1132 } };
+static const uint16_t uhdtv_cyan40[2][3] = { { 311, 454, 414 }, { 1244, 1816, 1656 } };
+static const uint16_t uhdtv_green40[2][3] = { { 311, 466, 283 }, { 1244, 1864, 1132 } };
+static const uint16_t uhdtv_magenta40[2][3] = { { 518, 363, 546 }, { 2072, 1452, 2184 } };
+static const uint16_t uhdtv_red40[2][3] = { { 518, 374, 414 }, { 2072, 1496, 1656 } };
+static const uint16_t uhdtv_blue40[2][3] = { { 414, 403, 546 }, { 1656, 1612, 2184 } };
+
+static const uint16_t uhdtv_white75[2][3] = { { 721, 721, 721 }, { 2884, 2884, 2884 } };
+static const uint16_t uhdtv_yellow75[2][3] = { { 721, 721, 64 }, { 2884, 2884, 256 } };
+static const uint16_t uhdtv_cyan75[2][3] = { { 64, 721, 721 }, { 256, 2884, 2884 } };
+static const uint16_t uhdtv_green75[2][3] = { { 64, 721, 64 }, { 256, 2884, 256 } };
+static const uint16_t uhdtv_megenta75[2][3] = { { 721, 64, 721 }, { 2884, 256, 2884 } };
+static const uint16_t uhdtv_red75[2][3] = { { 721, 64, 64 }, { 2884, 256, 256 } };
+static const uint16_t uhdtv_blue75[2][3] = { { 64, 64, 721 }, { 256, 256, 2884 } };
+
+static const uint16_t uhdtv_cyan100[2][3] = { { 64, 940, 940 }, { 256, 3760, 3760 } };
+static const uint16_t uhdtv_blue100[2][3] = { { 64, 64, 940 }, { 256, 256, 3760 } };
+static const uint16_t uhdtv_red100[2][3] = { { 940, 64, 64 }, { 3760, 256, 256 } };
+static const uint16_t uhdtv_yellow100[2][3] = { { 940, 940, 64 }, { 3760, 3760, 256 } };
+static const uint16_t uhdtv_magenta100[2][3]= { { 940, 64, 940 }, { 3760, 256, 3760 } };
+static const uint16_t uhdtv_white100[2][3] = { { 940, 940, 940 }, { 3760, 3760, 3760 } };
+static const uint16_t uhdtv_black0[2][3] = { { 64, 64, 64 }, { 256, 256, 256 } };
+
+static const uint16_t uhdtv_yellow[2][3] = { { 707, 717, 276 }, { 2828, 2868, 1104 } };
+static const uint16_t uhdtv_cyan[2][3] = { { 465, 698, 716 }, { 1860, 2792, 2864 } };
+static const uint16_t uhdtv_green[2][3] = { { 441, 694, 259 }, { 1764, 2776, 1036 } };
+static const uint16_t uhdtv_magenta[2][3] = { { 602, 250, 691 }, { 2408, 1000, 2764 } };
+static const uint16_t uhdtv_red[2][3] = { { 584, 237, 148 }, { 2336, 948, 592 } };
+static const uint16_t uhdtv_blue[2][3] = { { 201, 134, 686 }, { 804, 536, 2744 } };
+
+static const uint16_t uhdtv_black2p[2][3] = { { 80, 80, 80 }, { 320, 320, 320 } };
+static const uint16_t uhdtv_black2n[2][3] = { { 48, 48, 48 }, { 192, 192, 192 } };
+
+static const uint16_t uhdtv_magental[2][3] = { { 940, 502, 940 }, { 3760, 2008, 3760 } };
+static const uint16_t uhdtv_magentad[2][3] = { { 792, 502, 792 }, { 3168, 2008, 3168 } };
+
+static void draw_ramp16(int f, int x, int y, int w, int h,
+ AVFrame *frame)
+{
+ const int max = f == 2 ? 4095 : 1023;
+ uint16_t *p, *p0;
+
+ x *= f;
+ y *= f;
+ w *= f;
+ h *= f;
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int linesize = frame->linesize[plane];
+
+ p = p0 = (uint16_t *)(frame->data[plane] + y * linesize + x * 2);
+ for (int i = 0; i < w; i++) {
+ p[i] = i * max / w;
+ }
+ }
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int linesize = frame->linesize[plane];
+
+ p = p0 = (uint16_t *)(frame->data[plane] + y * linesize + x * 2);
+ p += linesize / 2;
+ for (int i = 1; i < h; i++, p += linesize / 2)
+ memcpy(p, p0, w * 2);
+ }
+}
+
+static const uint8_t cyclone_pattern[9][10] =
+{
+ {1,0,0,0,0,0,0,0,0,0},
+ {1,0,1,1,1,1,1,1,1,0},
+ {1,0,1,0,0,0,0,0,1,0},
+ {1,0,1,0,1,1,1,0,1,0},
+ {1,0,1,0,1,0,1,0,1,0},
+ {1,0,1,0,0,0,1,0,1,0},
+ {1,0,1,1,1,1,1,0,1,0},
+ {1,0,0,0,0,0,0,0,1,0},
+ {1,1,1,1,1,1,1,1,1,0},
+};
+
+static void draw_Xk_pattern(int m, int x, int y, int w, int h, AVFrame *out)
+{
+ const int f = m ? 2 : 1;
+
+ x *= f;
+ y *= f;
+ w *= f;
+ h *= f;
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int linesize = out->linesize[plane];
+ uint16_t *p, *p0;
+
+ p = p0 = (uint16_t *)(out->data[plane] + y * linesize + x * 2);
+ for (int i = 0; i < 200 * f; i++) {
+ const int c = i & 1 ? uhdtv_white100[m][comp] : uhdtv_magenta100[m][comp];
+
+ p[i] = c;
+ }
+
+ p += linesize / 2;
+ for (int i = 1; i < h / 2; i++, p += linesize / 2)
+ memcpy(p, p0, 200 * 2 * f);
+ }
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int linesize = out->linesize[plane];
+ const int c = uhdtv_magental[m][comp];
+ uint16_t *p, *p0;
+
+ p = p0 = (uint16_t *)(out->data[plane] + y * linesize + (x + 200 * f) * 2);
+ for (int i = 0; i < 80 * f; i++) {
+ p[i] = c;
+ }
+
+ p += linesize / 2;
+ for (int i = 1; i < 135 * f; i++, p += linesize / 2)
+ memcpy(p, p0, 80 * 2 * f);
+ }
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int linesize = out->linesize[plane];
+ const int c = uhdtv_magentad[m][comp];
+ uint16_t *p, *p0;
+
+ p = p0 = (uint16_t *)(out->data[plane] + (y + 135 * f) * linesize + (x + 200 * f) * 2);
+ for (int i = 0; i < 80 * f; i++) {
+ p[i] = c;
+ }
+
+ p += linesize / 2;
+ for (int i = 1; i < 135 * f; i++, p += linesize / 2)
+ memcpy(p, p0, 80 * 2 * f);
+ }
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int linesize = out->linesize[plane];
+ uint16_t *p;
+
+ p = (uint16_t *)(out->data[plane] + y * linesize + (x + 280 * f) * 2);
+ for (int j = 0; j < 270 * f; j++) {
+ const int c = j & 1 ? uhdtv_white100[m][comp] : uhdtv_magenta100[m][comp];
+
+ for (int i = 0; i < 200 * f; i++) {
+ p[i] = c;
+ }
+ p += linesize / 2;
+ }
+ }
+
+ for (int plane = 0; plane < 3; plane++) {
+ const int comp = order[plane];
+ const int linesize = out->linesize[plane];
+ uint16_t *p;
+
+ for (int j = 0; j < 30 * f; j++) {
+ for (int i = 0; i < 48 * f; i++) {
+ p = (uint16_t *)(out->data[plane] + (y + 9 * j + 270 * f) * linesize + (x + i * 10) * 2);
+ for (int k = 0; k < 9; k++) {
+ for (int l = 0; l < 10; l++) {
+ p[l] = cyclone_pattern[k][l] ? uhdtv_white100[m][comp] : uhdtv_black0[m][comp];
+ }
+ p += linesize / 2;
+ }
+ }
+ }
+ }
+}
+
+static void uhdtvbars_fill_picture(AVFilterContext *ctx, AVFrame *out)
+{
+ TestSourceContext *test = ctx->priv;
+ const int m = test->mode;
+ const int f = m ? 2 : 1;
+
+ draw_bar16(f, uhdtv_gray40[m], 0, 0, 480, 1260, out);
+ draw_bar16(f, uhdtv_white75[m], 480, 0, 412, 1440, out);
+ draw_bar16(f, uhdtv_yellow75[m], 892, 0, 412, 1260, out);
+ draw_bar16(f, uhdtv_cyan75[m], 1304, 0, 412, 1260, out);
+ draw_bar16(f, uhdtv_green75[m], 1716, 0, 408, 1260, out);
+ draw_bar16(f, uhdtv_megenta75[m], 2124, 0, 412, 1260, out);
+ draw_bar16(f, uhdtv_red75[m], 2536, 0, 412, 1260, out);
+ draw_bar16(f, uhdtv_blue75[m], 2948, 0, 412, 1260, out);
+ draw_bar16(f, uhdtv_gray40[m], 3360, 0, 480, 1260, out);
+
+ draw_bar16(f, uhdtv_cyan100[m], 0, 1260, 480, 180, out);
+ draw_bar16(f, uhdtv_yellow100[m], 0, 1440, 480, 180, out);
+
+ draw_bar16(f, uhdtv_yellow[m], 892, 1260, 412, 180, out);
+ draw_bar16(f, uhdtv_cyan[m], 1304, 1260, 412, 180, out);
+ draw_bar16(f, uhdtv_green[m], 1716, 1260, 408, 180, out);
+ draw_bar16(f, uhdtv_magenta[m], 2124, 1260, 412, 180, out);
+ draw_bar16(f, uhdtv_red[m], 2536, 1260, 412, 180, out);
+ draw_bar16(f, uhdtv_blue[m], 2948, 1260, 412, 180, out);
+
+ draw_bar16(f, uhdtv_blue100[m], 3360, 1260, 480, 180, out);
+ draw_bar16(f, uhdtv_red100[m], 3360, 1440, 480, 180, out);
+
+ draw_bar16(f, uhdtv_gray40[m], 0, 1620, 480, 540, out);
+ draw_bar16(f, uhdtv_gray40[m], 3360, 1620, 480, 540, out);
+
+ draw_ramp16(f, 480, 1440, 2880, 180, out);
+
+ draw_bar16(f, uhdtv_black0[m], 480, 1620, 564, 540, out);
+ draw_bar16(f, uhdtv_white100[m], 1044, 1620, 876, 540, out);
+ draw_bar16(f, uhdtv_black0[m], 1920, 1620, 464, 540, out);
+ draw_bar16(f, uhdtv_black2n[m], 2384, 1620, 136, 540, out);
+ draw_bar16(f, uhdtv_black0[m], 2520, 1620, 140, 540, out);
+ draw_bar16(f, uhdtv_black2p[m], 2660, 1620, 136, 540, out);
+ draw_bar16(f, uhdtv_black0[m], 2796, 1620, 564, 540, out);
+
+ if (!test->simple) {
+ draw_Xk_pattern(m, m ? 0 : 3360, 1620, 480, 540, out);
+
+ draw_bar16(f, uhdtv_yellow40[m], 200, 90, 80, 180, out);
+ draw_bar16(f, uhdtv_cyan40[m], 200, 270, 80, 180, out);
+ draw_bar16(f, uhdtv_green40[m], 200, 450, 80, 180, out);
+ draw_bar16(f, uhdtv_magenta40[m], 200, 630, 80, 180, out);
+ draw_bar16(f, uhdtv_red40[m], 200, 810, 80, 180, out);
+ draw_bar16(f, uhdtv_blue40[m], 200, 990, 80, 180, out);
+
+ draw_bar16(f, uhdtv_yellow40[m], 3560, 90, 80, 180, out);
+ draw_bar16(f, uhdtv_cyan40[m], 3560, 270, 80, 180, out);
+ draw_bar16(f, uhdtv_green40[m], 3560, 450, 80, 180, out);
+ draw_bar16(f, uhdtv_magenta40[m], 3560, 630, 80, 180, out);
+ draw_bar16(f, uhdtv_red40[m], 3560, 810, 80, 180, out);
+ draw_bar16(f, uhdtv_blue40[m], 3560, 990, 80, 180, out);
+ }
+}
+
+static av_cold int uhdtvbars_init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+
+ test->fill_picture_fn = uhdtvbars_fill_picture;
+ test->draw_once = 1;
+ test->w = 3840 * (1 + test->mode);
+ test->h = 2160 * (1 + test->mode);
+ return init(ctx);
+}
+
+static const AVFilterPad uhdtvbars_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_uhdtvbars = {
+ .name = "uhdtvbars",
+ .description = NULL_IF_CONFIG_SMALL("Generate UHDTV color bars."),
+ .priv_size = sizeof(TestSourceContext),
+ .priv_class = &uhdtvbars_class,
+ .init = uhdtvbars_init,
+ .uninit = uninit,
+ .query_formats = uhdtvbars_query_formats,
+ .inputs = NULL,
+ .outputs = uhdtvbars_outputs,
+};
+
+#endif /* CONFIG_UHDTVBARS_FILTER */
--
2.17.1
More information about the ffmpeg-devel
mailing list