From feb2ea6e09bfe4048bfd2c3a59d3976f3d9e9835 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 24 Aug 2016 18:55:05 +0200 Subject: [PATCH] avfilter: add yuvtestsrc source filter --- Changelog | 1 + doc/filters.texi | 6 +- libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vsrc_testsrc.c | 176 +++++++++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 70f0f2501c..dc1a0732c2 100644 --- a/Changelog +++ b/Changelog @@ -21,6 +21,7 @@ version : - maskedclamp filter - hysteresis filter - lut2 filter +- yuvtestsrc filter version 3.1: diff --git a/doc/filters.texi b/doc/filters.texi index d4eca3a3c9..4d1f5a20e7 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -14867,7 +14867,8 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c @anchor{smptehdbars} @anchor{testsrc} @anchor{testsrc2} -@section allrgb, allyuv, color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2 +@anchor{yuvtestsrc} +@section allrgb, allyuv, color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc The @code{allrgb} source returns frames of size 4096x4096 of all rgb colors. @@ -14900,6 +14901,9 @@ The @code{testsrc2} source is similar to testsrc, but supports more pixel formats instead of just @code{rgb24}. This allows using it as an input for other tests without requiring a format conversion. +The @code{yuvtestsrc} source generates an YUV test pattern. You should +see a y, cb and cr stripe from top to bottom. + The sources accept the following parameters: @table @option diff --git a/libavfilter/Makefile b/libavfilter/Makefile index ff9d527e5e..d00b40cbb6 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -315,6 +315,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_YUVTESTSRC_FILTER) += vsrc_testsrc.o # multimedia filters OBJS-$(CONFIG_ADRAWGRAPH_FILTER) += f_drawgraph.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index b6e62c1877..ca1bfb7991 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -330,6 +330,7 @@ void avfilter_register_all(void) REGISTER_FILTER(SMPTEHDBARS, smptehdbars, vsrc); REGISTER_FILTER(TESTSRC, testsrc, vsrc); REGISTER_FILTER(TESTSRC2, testsrc2, vsrc); + REGISTER_FILTER(YUVTESTSRC, yuvtestsrc, vsrc); REGISTER_FILTER(NULLSINK, nullsink, vsink); diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index 30c70bc1c7..08f6e07e50 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -1070,6 +1070,182 @@ AVFilter ff_vsrc_rgbtestsrc = { #endif /* CONFIG_RGBTESTSRC_FILTER */ +#if CONFIG_YUVTESTSRC_FILTER + +#define yuvtestsrc_options options +AVFILTER_DEFINE_CLASS(yuvtestsrc); + +static void yuvtest_fill_picture8(AVFilterContext *ctx, AVFrame *frame) +{ + int x, y, w = frame->width, h = frame->height / 3; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + const int factor = 1 << desc->comp[0].depth; + const int mid = 1 << (desc->comp[0].depth - 1); + uint8_t *ydst = frame->data[0]; + uint8_t *udst = frame->data[1]; + uint8_t *vdst = frame->data[2]; + int ylinesize = frame->linesize[0]; + int ulinesize = frame->linesize[1]; + int vlinesize = frame->linesize[2]; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = c; + udst[x] = mid; + vdst[x] = mid; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } + + h += h; + for (; y < h; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = mid; + udst[x] = c; + vdst[x] = mid; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } + + for (; y < frame->height; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = mid; + udst[x] = mid; + vdst[x] = c; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } +} + +static void yuvtest_fill_picture16(AVFilterContext *ctx, AVFrame *frame) +{ + int x, y, w = frame->width, h = frame->height / 3; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + const int factor = 1 << desc->comp[0].depth; + const int mid = 1 << (desc->comp[0].depth - 1); + uint16_t *ydst = (uint16_t *)frame->data[0]; + uint16_t *udst = (uint16_t *)frame->data[1]; + uint16_t *vdst = (uint16_t *)frame->data[2]; + int ylinesize = frame->linesize[0] / 2; + int ulinesize = frame->linesize[1] / 2; + int vlinesize = frame->linesize[2] / 2; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = c; + udst[x] = mid; + vdst[x] = mid; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } + + h += h; + for (; y < h; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = mid; + udst[x] = c; + vdst[x] = mid; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } + + for (; y < frame->height; y++) { + for (x = 0; x < w; x++) { + int c = factor * x / w; + + ydst[x] = mid; + udst[x] = mid; + vdst[x] = c; + } + + ydst += ylinesize; + udst += ulinesize; + vdst += vlinesize; + } +} + +static av_cold int yuvtest_init(AVFilterContext *ctx) +{ + TestSourceContext *test = ctx->priv; + + test->draw_once = 1; + return init(ctx); +} + +static int yuvtest_query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static int yuvtest_config_props(AVFilterLink *outlink) +{ + TestSourceContext *test = outlink->src->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); + + test->fill_picture_fn = desc->comp[0].depth > 8 ? yuvtest_fill_picture16 : yuvtest_fill_picture8; + return config_props(outlink); +} + +static const AVFilterPad avfilter_vsrc_yuvtestsrc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = request_frame, + .config_props = yuvtest_config_props, + }, + { NULL } +}; + +AVFilter ff_vsrc_yuvtestsrc = { + .name = "yuvtestsrc", + .description = NULL_IF_CONFIG_SMALL("Generate YUV test pattern."), + .priv_size = sizeof(TestSourceContext), + .priv_class = &yuvtestsrc_class, + .init = yuvtest_init, + .uninit = uninit, + .query_formats = yuvtest_query_formats, + .inputs = NULL, + .outputs = avfilter_vsrc_yuvtestsrc_outputs, +}; + +#endif /* CONFIG_YUVTESTSRC_FILTER */ + #if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER static const uint8_t rainbow[7][4] = {