diff --git a/doc/filters.texi b/doc/filters.texi index 04c97f429e..ff4fa1a8bc 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -7401,10 +7401,12 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c @end example @end itemize -@section color, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc +@section color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc The @code{color} source provides an uniformly colored input. +The @code{haldclutsrc} source provides an identity Hald CLUT. + The @code{nullsrc} source returns unprocessed video frames. It is mainly useful to be employed in analysis / debugging tools, or as the source for filters which ignore the input data. @@ -7433,11 +7435,19 @@ source. It can be the name of a color (case insensitive match) or a 0xRRGGBB[AA] sequence, possibly followed by an alpha specifier. The default value is "black". +@item level +Specify the level of the Hald CLUT, only available in the @code{haldclutsrc} +source. A level of @code{N} generates a picture of @code{N*N*N} by @code{N*N*N} +pixels to be used as identity matrix for 3D lookup tables. Each component is +coded on a @code{1/(N*N)} scale. + @item size, s Specify the size of the sourced video, it may be a string of the form @var{width}x@var{height}, or the name of a size abbreviation. The default value is "320x240". +This option is not available with the @code{haldclutsrc} filter. + @item rate, r Specify the frame rate of the sourced video, as the number of frames generated per second. It has to be a string in the format diff --git a/libavfilter/Makefile b/libavfilter/Makefile index fa601b57fe..f53afb2bab 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -196,6 +196,7 @@ OBJS-$(CONFIG_ZMQ_FILTER) += f_zmq.o OBJS-$(CONFIG_CELLAUTO_FILTER) += vsrc_cellauto.o OBJS-$(CONFIG_COLOR_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_FREI0R_SRC_FILTER) += vf_frei0r.o +OBJS-$(CONFIG_HALDCLUTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o OBJS-$(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o OBJS-$(CONFIG_MPTESTSRC_FILTER) += vsrc_mptestsrc.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 0f2442dc41..075eccade4 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -193,6 +193,7 @@ void avfilter_register_all(void) REGISTER_FILTER(CELLAUTO, cellauto, vsrc); REGISTER_FILTER(COLOR, color, vsrc); REGISTER_FILTER(FREI0R, frei0r_src, vsrc); + REGISTER_FILTER(HALDCLUTSRC, haldclutsrc, vsrc); REGISTER_FILTER(LIFE, life, vsrc); REGISTER_FILTER(MANDELBROT, mandelbrot, vsrc); REGISTER_FILTER(MPTESTSRC, mptestsrc, vsrc); diff --git a/libavfilter/version.h b/libavfilter/version.h index acb53a5c1b..fa4c1ddfab 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -30,8 +30,8 @@ #include "libavutil/avutil.h" #define LIBAVFILTER_VERSION_MAJOR 3 -#define LIBAVFILTER_VERSION_MINOR 70 -#define LIBAVFILTER_VERSION_MICRO 101 +#define LIBAVFILTER_VERSION_MINOR 71 +#define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index 075026d9ef..5d79b44283 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -71,20 +71,26 @@ typedef struct { /* only used by rgbtest */ uint8_t rgba_map[4]; + + /* only used by haldclut */ + int level; } TestSourceContext; #define OFFSET(x) offsetof(TestSourceContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM -#define COMMON_OPTIONS \ +#define SIZE_OPTIONS \ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "320x240"}, 0, 0, FLAGS },\ + +#define COMMON_OPTIONS_NOSIZE \ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\ { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\ { "d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\ { "sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1}, 0, INT_MAX, FLAGS }, +#define COMMON_OPTIONS SIZE_OPTIONS COMMON_OPTIONS_NOSIZE static const AVOption options[] = { COMMON_OPTIONS @@ -269,6 +275,135 @@ AVFilter avfilter_vsrc_color = { #endif /* CONFIG_COLOR_FILTER */ +#if CONFIG_HALDCLUTSRC_FILTER + +static const AVOption haldclutsrc_options[] = { + { "level", "set level", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = 6}, 2, 8, FLAGS }, + COMMON_OPTIONS + { NULL } +}; + +AVFILTER_DEFINE_CLASS(haldclutsrc); + +static void haldclutsrc_fill_picture(AVFilterContext *ctx, AVFrame *frame) +{ + int i, j, k, x = 0, y = 0, is16bit = 0, step; + uint32_t alpha = 0; + const TestSourceContext *hc = ctx->priv; + int level = hc->level; + float scale; + const int w = frame->width; + const int h = frame->height; + const uint8_t *data = frame->data[0]; + const int linesize = frame->linesize[0]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + uint8_t rgba_map[4]; + + av_assert0(w == h && w == level*level*level); + + ff_fill_rgba_map(rgba_map, frame->format); + + switch (frame->format) { + case AV_PIX_FMT_RGB48: + case AV_PIX_FMT_BGR48: + case AV_PIX_FMT_RGBA64: + case AV_PIX_FMT_BGRA64: + is16bit = 1; + alpha = 0xffff; + break; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_ABGR: + alpha = 0xff; + break; + } + + step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit); + scale = ((float)(1 << (8*(is16bit+1))) - 1) / (level*level - 1); + +#define LOAD_CLUT(nbits) do { \ + uint##nbits##_t *dst = ((uint##nbits##_t *)(data + y*linesize)) + x*step; \ + dst[rgba_map[0]] = av_clip_uint##nbits(i * scale); \ + dst[rgba_map[1]] = av_clip_uint##nbits(j * scale); \ + dst[rgba_map[2]] = av_clip_uint##nbits(k * scale); \ + if (step == 4) \ + dst[rgba_map[3]] = alpha; \ +} while (0) + + level *= level; + for (k = 0; k < level; k++) { + for (j = 0; j < level; j++) { + for (i = 0; i < level; i++) { + if (!is16bit) + LOAD_CLUT(8); + else + LOAD_CLUT(16); + if (++x == w) { + x = 0; + y++; + } + } + } + } +} + +static av_cold int haldclutsrc_init(AVFilterContext *ctx) +{ + TestSourceContext *hc = ctx->priv; + hc->fill_picture_fn = haldclutsrc_fill_picture; + hc->draw_once = 1; + return init(ctx); +} + +static int haldclutsrc_query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, + AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, + AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, + AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, + AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, + AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_NONE, + }; + ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); + return 0; +} + +static int haldclutsrc_config_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + TestSourceContext *hc = ctx->priv; + + hc->w = hc->h = hc->level * hc->level * hc->level; + return config_props(outlink); +} + +static const AVFilterPad haldclutsrc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = request_frame, + .config_props = haldclutsrc_config_props, + }, + { NULL } +}; + +AVFilter avfilter_vsrc_haldclutsrc = { + .name = "haldclutsrc", + .description = NULL_IF_CONFIG_SMALL("Provide an identity Hald CLUT."), + .priv_class = &haldclutsrc_class, + .priv_size = sizeof(TestSourceContext), + .init = haldclutsrc_init, + .uninit = uninit, + .query_formats = haldclutsrc_query_formats, + .inputs = NULL, + .outputs = haldclutsrc_outputs, +}; +#endif /* CONFIG_HALDCLUTSRC_FILTER */ + #if CONFIG_NULLSRC_FILTER #define nullsrc_options options