From 99dac3933916507fb728b9c6d9aafb11c7d2f228 Mon Sep 17 00:00:00 2001 From: Clément Bœsch Date: Mon, 15 Apr 2013 10:53:54 +0200 Subject: lavfi/curves: add support for master component. --- doc/filters.texi | 7 ++++++- libavfilter/vf_curves.c | 52 +++++++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index b766985e3e..8df1a88611 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2330,6 +2330,11 @@ Available presets are: @item vintage @end table Default is @code{none}. +@item master, m +Set the master key points. These points will define a second pass mapping. It +is sometimes called a "luminance" or "value" mapping. It can be used with +@option{r}, @option{g}, @option{b} or @option{all} since it acts like a +post-processing LUT. @item red, r Set the key points for the red component. @item green, g @@ -2337,7 +2342,7 @@ Set the key points for the green component. @item blue, b Set the key points for the blue component. @item all -Set the key points for all components. +Set the key points for all components (not including master). Can be used in addition to the other key points component options. In this case, the unset component(s) will fallback on this @option{all} setting. diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 2bb1c5e65c..35a5af3946 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -51,9 +51,9 @@ enum preset { typedef struct { const AVClass *class; enum preset preset; - char *comp_points_str[NB_COMP]; + char *comp_points_str[NB_COMP + 1]; char *comp_points_str_all; - uint8_t graph[NB_COMP][256]; + uint8_t graph[NB_COMP + 1][256]; } CurvesContext; #define OFFSET(x) offsetof(CurvesContext, x) @@ -71,6 +71,8 @@ static const AVOption curves_options[] = { { "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" }, + { "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 }, { "r", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, { "green", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, @@ -87,7 +89,7 @@ static const struct { const char *r; const char *g; const char *b; - const char *all; + const char *master; } curves_presets[] = { [PRESET_COLOR_NEGATIVE] = { "0/1 0.129/1 0.466/0.498 0.725/0 1/0", @@ -99,13 +101,13 @@ static const struct { "0.25/0.188 0.38/0.501 0.745/0.815 1/0.815", "0.231/0.094 0.709/0.874", }, - [PRESET_DARKER] = { .all = "0.5/0.4" }, - [PRESET_INCREASE_CONTRAST] = { .all = "0.149/0.066 0.831/0.905 0.905/0.98" }, - [PRESET_LIGHTER] = { .all = "0.4/0.5" }, - [PRESET_LINEAR_CONTRAST] = { .all = "0.305/0.286 0.694/0.713" }, - [PRESET_MEDIUM_CONTRAST] = { .all = "0.286/0.219 0.639/0.643" }, - [PRESET_NEGATIVE] = { .all = "0/1 1/0" }, - [PRESET_STRONG_CONTRAST] = { .all = "0.301/0.196 0.592/0.6 0.686/0.737" }, + [PRESET_DARKER] = { .master = "0.5/0.4" }, + [PRESET_INCREASE_CONTRAST] = { .master = "0.149/0.066 0.831/0.905 0.905/0.98" }, + [PRESET_LIGHTER] = { .master = "0.4/0.5" }, + [PRESET_LINEAR_CONTRAST] = { .master = "0.305/0.286 0.694/0.713" }, + [PRESET_MEDIUM_CONTRAST] = { .master = "0.286/0.219 0.639/0.643" }, + [PRESET_NEGATIVE] = { .master = "0/1 1/0" }, + [PRESET_STRONG_CONTRAST] = { .master = "0.301/0.196 0.592/0.6 0.686/0.737" }, [PRESET_VINTAGE] = { "0/0.11 0.42/0.51 1/0.95", "0.50/0.48", @@ -299,12 +301,12 @@ static av_cold int init(AVFilterContext *ctx) { int i, j, ret; CurvesContext *curves = ctx->priv; - struct keypoint *comp_points[NB_COMP] = {0}; + struct keypoint *comp_points[NB_COMP + 1] = {0}; char **pts = curves->comp_points_str; const char *allp = curves->comp_points_str_all; - if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all) - allp = curves_presets[curves->preset].all; + //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all) + // allp = curves_presets[curves->preset].all; if (allp) { for (i = 0; i < NB_COMP; i++) { @@ -316,14 +318,20 @@ static av_cold int init(AVFilterContext *ctx) } if (curves->preset != PRESET_NONE) { - if (!pts[0]) pts[0] = av_strdup(curves_presets[curves->preset].r); - if (!pts[1]) pts[1] = av_strdup(curves_presets[curves->preset].g); - if (!pts[2]) pts[2] = av_strdup(curves_presets[curves->preset].b); - if (!pts[0] || !pts[1] || !pts[2]) - return AVERROR(ENOMEM); +#define SET_COMP_IF_NOT_SET(n, name) do { \ + if (!pts[n] && curves_presets[curves->preset].name) { \ + pts[n] = av_strdup(curves_presets[curves->preset].name); \ + if (!pts[n]) \ + return AVERROR(ENOMEM); \ + } \ +} while (0) + SET_COMP_IF_NOT_SET(0, r); + SET_COMP_IF_NOT_SET(1, g); + SET_COMP_IF_NOT_SET(2, b); + SET_COMP_IF_NOT_SET(3, master); } - for (i = 0; i < NB_COMP; i++) { + for (i = 0; i < NB_COMP + 1; i++) { ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i]); if (ret < 0) return ret; @@ -332,6 +340,12 @@ static av_cold int init(AVFilterContext *ctx) return ret; } + if (pts[NB_COMP]) { + for (i = 0; i < NB_COMP; i++) + for (j = 0; j < 256; j++) + curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]]; + } + if (av_log_get_level() >= AV_LOG_VERBOSE) { for (i = 0; i < NB_COMP; i++) { struct keypoint *point = comp_points[i]; -- cgit v1.2.3