From d7cb8c51f05a2a73e899d88348d92c0f5f72d2fd Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 9 Feb 2021 18:08:16 +0100 Subject: [PATCH] avfilter/vf_curves: add commands support --- doc/filters.texi | 4 +++ libavfilter/vf_curves.c | 74 ++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index aeb20bc955..079bba9a1e 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -9257,6 +9257,10 @@ Save Gnuplot script of the curves in specified file. To avoid some filtergraph syntax conflicts, each key points list need to be defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}. +@subsection Commands + +This filter supports same @ref{commands} as options. + @subsection Examples @itemize diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 883cc1c90c..3524fef1ad 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -69,8 +69,10 @@ typedef struct CurvesContext { uint8_t rgba_map[4]; int step; char *plot_filename; + int saved_plot; int is_16bit; int depth; + int parsed_psfile; int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } CurvesContext; @@ -80,20 +82,20 @@ typedef struct ThreadData { } ThreadData; #define OFFSET(x) offsetof(CurvesContext, x) -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM static const AVOption curves_options[] = { { "preset", "select a color curves preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64=PRESET_NONE}, PRESET_NONE, NB_PRESETS-1, FLAGS, "preset_name" }, - { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NONE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "color_negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_COLOR_NEGATIVE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "cross_process", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_CROSS_PROCESS}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "darker", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_DARKER}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "increase_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_INCREASE_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "lighter", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LIGHTER}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "linear_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LINEAR_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "medium_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_MEDIUM_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, - { "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NONE}, 0, 0, FLAGS, "preset_name" }, + { "color_negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_COLOR_NEGATIVE}, 0, 0, FLAGS, "preset_name" }, + { "cross_process", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_CROSS_PROCESS}, 0, 0, FLAGS, "preset_name" }, + { "darker", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_DARKER}, 0, 0, FLAGS, "preset_name" }, + { "increase_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_INCREASE_CONTRAST}, 0, 0, FLAGS, "preset_name" }, + { "lighter", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LIGHTER}, 0, 0, FLAGS, "preset_name" }, + { "linear_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LINEAR_CONTRAST}, 0, 0, FLAGS, "preset_name" }, + { "medium_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_MEDIUM_CONTRAST}, 0, 0, FLAGS, "preset_name" }, + { "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, 0, 0, FLAGS, "preset_name" }, + { "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, 0, 0, FLAGS, "preset_name" }, + { "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, 0, 0, FLAGS, "preset_name" }, { "master","set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, { "m", "set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, { "red", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, @@ -486,10 +488,11 @@ static av_cold int curves_init(AVFilterContext *ctx) } } - if (curves->psfile) { + if (curves->psfile && !curves->parsed_psfile) { ret = parse_psfile(ctx, curves->psfile); if (ret < 0) return ret; + curves->parsed_psfile = 1; } if (curves->preset != PRESET_NONE) { @@ -504,6 +507,7 @@ static av_cold int curves_init(AVFilterContext *ctx) SET_COMP_IF_NOT_SET(1, g); SET_COMP_IF_NOT_SET(2, b); SET_COMP_IF_NOT_SET(3, master); + curves->preset = PRESET_NONE; } return 0; @@ -664,7 +668,8 @@ static int config_input(AVFilterLink *inlink) curves->filter_slice = desc->flags & AV_PIX_FMT_FLAG_PLANAR ? filter_slice_planar : filter_slice_packed; for (i = 0; i < NB_COMP + 1; i++) { - curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); + if (!curves->graph[i]) + curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); if (!curves->graph[i]) return AVERROR(ENOMEM); ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); @@ -699,8 +704,10 @@ static int config_input(AVFilterLink *inlink) } } - if (curves->plot_filename) + if (curves->plot_filename && !curves->saved_plot) { dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size); + curves->saved_plot = 1; + } for (i = 0; i < NB_COMP + 1; i++) { struct keypoint *point = comp_points[i]; @@ -743,6 +750,42 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + CurvesContext *curves = ctx->priv; + int ret; + + if (!strcmp(cmd, "plot")) { + curves->saved_plot = 0; + } else if (!strcmp(cmd, "all") || !strcmp(cmd, "preset") || !strcmp(cmd, "psfile")) { + if (!strcmp(cmd, "psfile")) + curves->parsed_psfile = 0; + av_freep(&curves->comp_points_str_all); + av_freep(&curves->comp_points_str[0]); + av_freep(&curves->comp_points_str[1]); + av_freep(&curves->comp_points_str[2]); + av_freep(&curves->comp_points_str[NB_COMP]); + } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) { + av_freep(&curves->comp_points_str[0]); + } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) { + av_freep(&curves->comp_points_str[1]); + } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) { + av_freep(&curves->comp_points_str[2]); + } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) { + av_freep(&curves->comp_points_str[NB_COMP]); + } + + ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); + if (ret < 0) + return ret; + + ret = curves_init(ctx); + if (ret < 0) + return ret; + return config_input(ctx->inputs[0]); +} + static av_cold void curves_uninit(AVFilterContext *ctx) { int i; @@ -781,4 +824,5 @@ AVFilter ff_vf_curves = { .outputs = curves_outputs, .priv_class = &curves_class, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, + .process_command = process_command, };