... | ... |
@@ -2330,6 +2330,11 @@ Available presets are: |
2330 | 2330 |
@item vintage |
2331 | 2331 |
@end table |
2332 | 2332 |
Default is @code{none}. |
2333 |
+@item master, m |
|
2334 |
+Set the master key points. These points will define a second pass mapping. It |
|
2335 |
+is sometimes called a "luminance" or "value" mapping. It can be used with |
|
2336 |
+@option{r}, @option{g}, @option{b} or @option{all} since it acts like a |
|
2337 |
+post-processing LUT. |
|
2333 | 2338 |
@item red, r |
2334 | 2339 |
Set the key points for the red component. |
2335 | 2340 |
@item green, g |
... | ... |
@@ -2337,7 +2342,7 @@ Set the key points for the green component. |
2337 | 2337 |
@item blue, b |
2338 | 2338 |
Set the key points for the blue component. |
2339 | 2339 |
@item all |
2340 |
-Set the key points for all components. |
|
2340 |
+Set the key points for all components (not including master). |
|
2341 | 2341 |
Can be used in addition to the other key points component |
2342 | 2342 |
options. In this case, the unset component(s) will fallback on this |
2343 | 2343 |
@option{all} setting. |
... | ... |
@@ -51,9 +51,9 @@ enum preset { |
51 | 51 |
typedef struct { |
52 | 52 |
const AVClass *class; |
53 | 53 |
enum preset preset; |
54 |
- char *comp_points_str[NB_COMP]; |
|
54 |
+ char *comp_points_str[NB_COMP + 1]; |
|
55 | 55 |
char *comp_points_str_all; |
56 |
- uint8_t graph[NB_COMP][256]; |
|
56 |
+ uint8_t graph[NB_COMP + 1][256]; |
|
57 | 57 |
} CurvesContext; |
58 | 58 |
|
59 | 59 |
#define OFFSET(x) offsetof(CurvesContext, x) |
... | ... |
@@ -71,6 +71,8 @@ static const AVOption curves_options[] = { |
71 | 71 |
{ "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, |
72 | 72 |
{ "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, |
73 | 73 |
{ "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, INT_MIN, INT_MAX, FLAGS, "preset_name" }, |
74 |
+ { "master","set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
|
75 |
+ { "m", "set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
|
74 | 76 |
{ "red", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
75 | 77 |
{ "r", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
76 | 78 |
{ "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 { |
87 | 87 |
const char *r; |
88 | 88 |
const char *g; |
89 | 89 |
const char *b; |
90 |
- const char *all; |
|
90 |
+ const char *master; |
|
91 | 91 |
} curves_presets[] = { |
92 | 92 |
[PRESET_COLOR_NEGATIVE] = { |
93 | 93 |
"0/1 0.129/1 0.466/0.498 0.725/0 1/0", |
... | ... |
@@ -99,13 +101,13 @@ static const struct { |
99 | 99 |
"0.25/0.188 0.38/0.501 0.745/0.815 1/0.815", |
100 | 100 |
"0.231/0.094 0.709/0.874", |
101 | 101 |
}, |
102 |
- [PRESET_DARKER] = { .all = "0.5/0.4" }, |
|
103 |
- [PRESET_INCREASE_CONTRAST] = { .all = "0.149/0.066 0.831/0.905 0.905/0.98" }, |
|
104 |
- [PRESET_LIGHTER] = { .all = "0.4/0.5" }, |
|
105 |
- [PRESET_LINEAR_CONTRAST] = { .all = "0.305/0.286 0.694/0.713" }, |
|
106 |
- [PRESET_MEDIUM_CONTRAST] = { .all = "0.286/0.219 0.639/0.643" }, |
|
107 |
- [PRESET_NEGATIVE] = { .all = "0/1 1/0" }, |
|
108 |
- [PRESET_STRONG_CONTRAST] = { .all = "0.301/0.196 0.592/0.6 0.686/0.737" }, |
|
102 |
+ [PRESET_DARKER] = { .master = "0.5/0.4" }, |
|
103 |
+ [PRESET_INCREASE_CONTRAST] = { .master = "0.149/0.066 0.831/0.905 0.905/0.98" }, |
|
104 |
+ [PRESET_LIGHTER] = { .master = "0.4/0.5" }, |
|
105 |
+ [PRESET_LINEAR_CONTRAST] = { .master = "0.305/0.286 0.694/0.713" }, |
|
106 |
+ [PRESET_MEDIUM_CONTRAST] = { .master = "0.286/0.219 0.639/0.643" }, |
|
107 |
+ [PRESET_NEGATIVE] = { .master = "0/1 1/0" }, |
|
108 |
+ [PRESET_STRONG_CONTRAST] = { .master = "0.301/0.196 0.592/0.6 0.686/0.737" }, |
|
109 | 109 |
[PRESET_VINTAGE] = { |
110 | 110 |
"0/0.11 0.42/0.51 1/0.95", |
111 | 111 |
"0.50/0.48", |
... | ... |
@@ -299,12 +301,12 @@ static av_cold int init(AVFilterContext *ctx) |
299 | 299 |
{ |
300 | 300 |
int i, j, ret; |
301 | 301 |
CurvesContext *curves = ctx->priv; |
302 |
- struct keypoint *comp_points[NB_COMP] = {0}; |
|
302 |
+ struct keypoint *comp_points[NB_COMP + 1] = {0}; |
|
303 | 303 |
char **pts = curves->comp_points_str; |
304 | 304 |
const char *allp = curves->comp_points_str_all; |
305 | 305 |
|
306 |
- if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all) |
|
307 |
- allp = curves_presets[curves->preset].all; |
|
306 |
+ //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all) |
|
307 |
+ // allp = curves_presets[curves->preset].all; |
|
308 | 308 |
|
309 | 309 |
if (allp) { |
310 | 310 |
for (i = 0; i < NB_COMP; i++) { |
... | ... |
@@ -316,14 +318,20 @@ static av_cold int init(AVFilterContext *ctx) |
316 | 316 |
} |
317 | 317 |
|
318 | 318 |
if (curves->preset != PRESET_NONE) { |
319 |
- if (!pts[0]) pts[0] = av_strdup(curves_presets[curves->preset].r); |
|
320 |
- if (!pts[1]) pts[1] = av_strdup(curves_presets[curves->preset].g); |
|
321 |
- if (!pts[2]) pts[2] = av_strdup(curves_presets[curves->preset].b); |
|
322 |
- if (!pts[0] || !pts[1] || !pts[2]) |
|
323 |
- return AVERROR(ENOMEM); |
|
319 |
+#define SET_COMP_IF_NOT_SET(n, name) do { \ |
|
320 |
+ if (!pts[n] && curves_presets[curves->preset].name) { \ |
|
321 |
+ pts[n] = av_strdup(curves_presets[curves->preset].name); \ |
|
322 |
+ if (!pts[n]) \ |
|
323 |
+ return AVERROR(ENOMEM); \ |
|
324 |
+ } \ |
|
325 |
+} while (0) |
|
326 |
+ SET_COMP_IF_NOT_SET(0, r); |
|
327 |
+ SET_COMP_IF_NOT_SET(1, g); |
|
328 |
+ SET_COMP_IF_NOT_SET(2, b); |
|
329 |
+ SET_COMP_IF_NOT_SET(3, master); |
|
324 | 330 |
} |
325 | 331 |
|
326 |
- for (i = 0; i < NB_COMP; i++) { |
|
332 |
+ for (i = 0; i < NB_COMP + 1; i++) { |
|
327 | 333 |
ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i]); |
328 | 334 |
if (ret < 0) |
329 | 335 |
return ret; |
... | ... |
@@ -332,6 +340,12 @@ static av_cold int init(AVFilterContext *ctx) |
332 | 332 |
return ret; |
333 | 333 |
} |
334 | 334 |
|
335 |
+ if (pts[NB_COMP]) { |
|
336 |
+ for (i = 0; i < NB_COMP; i++) |
|
337 |
+ for (j = 0; j < 256; j++) |
|
338 |
+ curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]]; |
|
339 |
+ } |
|
340 |
+ |
|
335 | 341 |
if (av_log_get_level() >= AV_LOG_VERBOSE) { |
336 | 342 |
for (i = 0; i < NB_COMP; i++) { |
337 | 343 |
struct keypoint *point = comp_points[i]; |