From patchwork Tue Dec 24 17:21:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 16940 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id C815D44B1C0 for ; Tue, 24 Dec 2019 19:22:16 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A46BA689D90; Tue, 24 Dec 2019 19:22:16 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C0196687FE4 for ; Tue, 24 Dec 2019 19:22:09 +0200 (EET) Received: by mail-wr1-f66.google.com with SMTP id j42so20277684wrj.12 for ; Tue, 24 Dec 2019 09:22:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=8ZHs4kdFMEGVucewfT4P3ohbcDjd5m+Q9EnCKfep0KU=; b=S0uaGoojTT/OCQPYUUNGTUFgctO2g9NVfQQOvYsO2nIGs0Dvaod9kg9D8WXD66QMUT lO6WiRiNuXWncDoSP53kQCpDmz8PNa7AHiXXPqsIa6lyJoXBlZ1an4y9rpYn2E+JK/Vr YbC04YLmSvEHpRh6HHRua9Vk7NnlOP4XkEzXBxpmfYO3SMTSyl5fzDfozKbk5SxGuvBG hrykfU8TeyXPhk8p5Y/dsdFp+qFxwK1Zjmiwh+c9G8o2xLgVT4ww9Dl2VRK0imiDGNzU PE9eHwnRRCUq4dHDkDkdl50Mz70jdSY421QMKhwh9e6l5eXQVJsaRFfWjMqC7Y/NxW+L dKcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=8ZHs4kdFMEGVucewfT4P3ohbcDjd5m+Q9EnCKfep0KU=; b=fgIDVNXbFr7O6OJJkPJLlgMmONi3o5DNTfXAMgmCjMuDVHSOdpeXuMJ8PFYvhWFRq8 6FDJQ3f95xYnvyY5COHrKa3Zy1UVBmdkbB2IiPWnm0AYRN8D1IX0IdKBj4ZXCUdQ34F2 bkQRl6PHU2NfMqg84UtCem/EkwAdR55Pr2M/RILGloALOXyhqju1bBQA/Jw7b63aAnMR 0R+pozrsVE8pfss67GzZI6hoexbxwtlwQZuBWuf3eoqvt6KQSF2bY1xCTg3IOWSANI8Z PnAdDZMvI+AKzOVHsgXx/8StevPbqqrW3NxOeIs+DTVYHofa+4YVMsHBbxAzKrZx7VMW W+Hw== X-Gm-Message-State: APjAAAWifPa3W43imqd8+I693yqtYrbtFi8RhJtRleBuPLtl7fjlKWRf jTBSBwYRlsntbRiYOXNkM/9NnU8O X-Google-Smtp-Source: APXvYqyIF7Ev8efC90kwQ28KTYh+m4bjxzELB5rhfYaouh073i8SYLytxWEA0d6XUBoPUJDPgijrTw== X-Received: by 2002:a5d:45c4:: with SMTP id b4mr2824948wrs.303.1577208128672; Tue, 24 Dec 2019 09:22:08 -0800 (PST) Received: from localhost.localdomain ([37.244.227.78]) by smtp.gmail.com with ESMTPSA id o4sm24506713wrw.97.2019.12.24.09.22.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Dec 2019 09:22:07 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Tue, 24 Dec 2019 18:21:58 +0100 Message-Id: <20191224172158.30469-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avfilter: add uhdtvbars video source filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- 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 */