Browse Source

avfilter/vf_curves: add commands support

tags/n4.4
Paul B Mahol 4 years ago
parent
commit
d7cb8c51f0
2 changed files with 63 additions and 15 deletions
  1. +4
    -0
      doc/filters.texi
  2. +59
    -15
      libavfilter/vf_curves.c

+ 4
- 0
doc/filters.texi View File

@@ -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 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 ...}. defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}.


@subsection Commands

This filter supports same @ref{commands} as options.

@subsection Examples @subsection Examples


@itemize @itemize


+ 59
- 15
libavfilter/vf_curves.c View File

@@ -69,8 +69,10 @@ typedef struct CurvesContext {
uint8_t rgba_map[4]; uint8_t rgba_map[4];
int step; int step;
char *plot_filename; char *plot_filename;
int saved_plot;
int is_16bit; int is_16bit;
int depth; int depth;
int parsed_psfile;


int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
} CurvesContext; } CurvesContext;
@@ -80,20 +82,20 @@ typedef struct ThreadData {
} ThreadData; } ThreadData;


#define OFFSET(x) offsetof(CurvesContext, x) #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[] = { 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" }, { "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 }, { "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 }, { "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 }, { "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); ret = parse_psfile(ctx, curves->psfile);
if (ret < 0) if (ret < 0)
return ret; return ret;
curves->parsed_psfile = 1;
} }


if (curves->preset != PRESET_NONE) { 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(1, g);
SET_COMP_IF_NOT_SET(2, b); SET_COMP_IF_NOT_SET(2, b);
SET_COMP_IF_NOT_SET(3, master); SET_COMP_IF_NOT_SET(3, master);
curves->preset = PRESET_NONE;
} }


return 0; 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; curves->filter_slice = desc->flags & AV_PIX_FMT_FLAG_PLANAR ? filter_slice_planar : filter_slice_packed;


for (i = 0; i < NB_COMP + 1; i++) { 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]) if (!curves->graph[i])
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); 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); dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size);
curves->saved_plot = 1;
}


for (i = 0; i < NB_COMP + 1; i++) { for (i = 0; i < NB_COMP + 1; i++) {
struct keypoint *point = comp_points[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); 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) static av_cold void curves_uninit(AVFilterContext *ctx)
{ {
int i; int i;
@@ -781,4 +824,5 @@ AVFilter ff_vf_curves = {
.outputs = curves_outputs, .outputs = curves_outputs,
.priv_class = &curves_class, .priv_class = &curves_class,
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
.process_command = process_command,
}; };

Loading…
Cancel
Save