In particular, add support for t, pos, n, r parameters, and add an eval
mode option.
Also, partially reword option documentation.
With several major edit by Stefano Sabatini.
Signed-off-by: Stefano Sabatini <stefasab@gmail.com>
... | ... |
@@ -4366,40 +4366,72 @@ The filter accepts the following options: |
4366 | 4366 |
|
4367 | 4367 |
@table @option |
4368 | 4368 |
@item contrast |
4369 |
-Set the contrast value. It accepts a float value in range @code{-2.0} to |
|
4370 |
-@code{2.0}. The default value is @code{0.0}. |
|
4369 |
+Set the contrast expression. The value must be a float value in range |
|
4370 |
+@code{-2.0} to @code{2.0}. The default value is "0". |
|
4371 | 4371 |
|
4372 | 4372 |
@item brightness |
4373 |
-Set the brightness value. It accepts a float value in range @code{-1.0} to |
|
4374 |
-@code{1.0}. The default value is @code{0.0}. |
|
4373 |
+Set the brightness expression. The value must be a float value in |
|
4374 |
+range @code{-1.0} to @code{1.0}. The default value is "0". |
|
4375 | 4375 |
|
4376 | 4376 |
@item saturation |
4377 |
-Set the saturation value. It accepts a float value in range @code{0.0} to |
|
4378 |
-@code{3.0}. The default value is @code{1.0}. |
|
4377 |
+Set the saturation expression. The value must be a float in |
|
4378 |
+range @code{0.0} to @code{3.0}. The default value is "1". |
|
4379 | 4379 |
|
4380 | 4380 |
@item gamma |
4381 |
-Set the gamma value. It accepts a float value in range @code{0.1} to @code{10.0}. |
|
4382 |
-The default value is @code{1.0}. |
|
4381 |
+Set the gamma expression. The value must be a float in range |
|
4382 |
+@code{0.1} to @code{10.0}. The default value is "1". |
|
4383 | 4383 |
|
4384 | 4384 |
@item gamma_r |
4385 |
-Set the gamma value for red. It accepts a float value in range |
|
4386 |
-@code{0.1} to @code{10.0}. The default value is @code{1.0}. |
|
4385 |
+Set the gamma expression for red. The value must be a float in |
|
4386 |
+range @code{0.1} to @code{10.0}. The default value is "1". |
|
4387 | 4387 |
|
4388 | 4388 |
@item gamma_g |
4389 |
-Set the gamma value for green. It accepts a float value in range |
|
4390 |
-@code{0.1} to @code{10.0}. The default value is @code{1.0}. |
|
4389 |
+Set the gamma expression for green. The value must be a float in range |
|
4390 |
+@code{0.1} to @code{10.0}. The default value is "1". |
|
4391 | 4391 |
|
4392 | 4392 |
@item gamma_b |
4393 |
-Set the gamma value for blue. It accepts a float value in range |
|
4394 |
-@code{0.1} to @code{10.0}. The default value is @code{1.0}. |
|
4393 |
+Set the gamma expression for blue. The value must be a float in range |
|
4394 |
+@code{0.1} to @code{10.0}. The default value is "1". |
|
4395 | 4395 |
|
4396 | 4396 |
@item gamma_weight |
4397 |
-Can be used to reduce the effect of a high gamma value on bright image areas, |
|
4398 |
-e.g. keep them from getting overamplified and just plain white. It accepts a |
|
4399 |
-float value in range @code{0.0} to @code{1.0}.A value of @code{0.0} turns the |
|
4400 |
-gamma correction all the way down while @code{1.0} leaves it at its full strength. |
|
4401 |
-Default is @code{1.0}. |
|
4397 |
+Set the gamma weight expression. It can be used to reduce the effect |
|
4398 |
+of a high gamma value on bright image areas, e.g. keep them from |
|
4399 |
+getting overamplified and just plain white. The value must be a float |
|
4400 |
+in range @code{0.0} to @code{1.0}. A value of @code{0.0} turns the |
|
4401 |
+gamma correction all the way down while @code{1.0} leaves it at its |
|
4402 |
+full strength. Default is "1". |
|
4402 | 4403 |
|
4404 |
+@item eval |
|
4405 |
+Set when the expressions for brightness, contrast, saturation and |
|
4406 |
+gamma expressions are evaluated. |
|
4407 |
+ |
|
4408 |
+It accepts the following values: |
|
4409 |
+@table @samp |
|
4410 |
+@item init |
|
4411 |
+only evaluate expressions once during the filter initialization or |
|
4412 |
+when a command is processed |
|
4413 |
+ |
|
4414 |
+@item frame |
|
4415 |
+evaluate expressions for each incoming frame |
|
4416 |
+@end table |
|
4417 |
+ |
|
4418 |
+Default value is @samp{init}. |
|
4419 |
+@end table |
|
4420 |
+ |
|
4421 |
+The expressions accept the following parameters: |
|
4422 |
+@table @option |
|
4423 |
+@item n |
|
4424 |
+frame count of the input frame starting from 0 |
|
4425 |
+ |
|
4426 |
+@item pos |
|
4427 |
+byte position of the corresponding packet in the input file, NAN if |
|
4428 |
+unspecified |
|
4429 |
+ |
|
4430 |
+@item r |
|
4431 |
+frame rate of the input video, NAN if the input frame rate is unknown |
|
4432 |
+ |
|
4433 |
+@item t |
|
4434 |
+timestamp expressed in seconds, NAN if the input timestamp is unknown |
|
4403 | 4435 |
@end table |
4404 | 4436 |
|
4405 | 4437 |
@subsection Commands |
... | ... |
@@ -31,7 +31,7 @@ |
31 | 31 |
|
32 | 32 |
#define LIBAVFILTER_VERSION_MAJOR 5 |
33 | 33 |
#define LIBAVFILTER_VERSION_MINOR 13 |
34 |
-#define LIBAVFILTER_VERSION_MICRO 100 |
|
34 |
+#define LIBAVFILTER_VERSION_MICRO 101 |
|
35 | 35 |
|
36 | 36 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
37 | 37 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -27,11 +27,6 @@ |
27 | 27 |
* very simple video equalizer |
28 | 28 |
*/ |
29 | 29 |
|
30 |
-/** |
|
31 |
- * TODO: |
|
32 |
- * - Add support to process_command |
|
33 |
- */ |
|
34 |
- |
|
35 | 30 |
#include "libavfilter/internal.h" |
36 | 31 |
#include "libavutil/common.h" |
37 | 32 |
#include "libavutil/imgutils.h" |
... | ... |
@@ -111,16 +106,16 @@ static void check_values(EQParameters *param, EQContext *eq) |
111 | 111 |
|
112 | 112 |
static void set_contrast(EQContext *eq) |
113 | 113 |
{ |
114 |
- eq->var_values[VAR_CONTRAST] = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq),-2.0, 2.0); |
|
115 |
- eq->param[0].contrast = eq->var_values[VAR_CONTRAST]; |
|
114 |
+ eq->contrast = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq), -2.0, 2.0); |
|
115 |
+ eq->param[0].contrast = eq->contrast; |
|
116 | 116 |
eq->param[0].lut_clean = 0; |
117 | 117 |
check_values(&eq->param[0], eq); |
118 | 118 |
} |
119 | 119 |
|
120 | 120 |
static void set_brightness(EQContext *eq) |
121 | 121 |
{ |
122 |
- eq->var_values[VAR_BRIGHTNESS] = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0); |
|
123 |
- eq->param[0].brightness = eq->var_values[VAR_BRIGHTNESS]; |
|
122 |
+ eq->brightness = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0); |
|
123 |
+ eq->param[0].brightness = eq->brightness; |
|
124 | 124 |
eq->param[0].lut_clean = 0; |
125 | 125 |
check_values(&eq->param[0], eq); |
126 | 126 |
} |
... | ... |
@@ -129,18 +124,18 @@ static void set_gamma(EQContext *eq) |
129 | 129 |
{ |
130 | 130 |
int i; |
131 | 131 |
|
132 |
- eq->var_values[VAR_GAMMA] = av_clipf(av_expr_eval(eq->gamma_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
133 |
- eq->var_values[VAR_GAMMA_R] = av_clipf(av_expr_eval(eq->gamma_r_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
134 |
- eq->var_values[VAR_GAMMA_G] = av_clipf(av_expr_eval(eq->gamma_g_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
135 |
- eq->var_values[VAR_GAMMA_B] = av_clipf(av_expr_eval(eq->gamma_b_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
136 |
- eq->var_values[VAR_GAMMA_WEIGHT] = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0); |
|
132 |
+ eq->gamma = av_clipf(av_expr_eval(eq->gamma_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
133 |
+ eq->gamma_r = av_clipf(av_expr_eval(eq->gamma_r_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
134 |
+ eq->gamma_g = av_clipf(av_expr_eval(eq->gamma_g_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
135 |
+ eq->gamma_b = av_clipf(av_expr_eval(eq->gamma_b_pexpr, eq->var_values, eq), 0.1, 10.0); |
|
136 |
+ eq->gamma_weight = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0); |
|
137 | 137 |
|
138 |
- eq->param[0].gamma = eq->var_values[VAR_GAMMA] * eq->var_values[VAR_GAMMA_G]; |
|
139 |
- eq->param[1].gamma = sqrt(eq->var_values[VAR_GAMMA_B] / eq->var_values[VAR_GAMMA_G]); |
|
140 |
- eq->param[2].gamma = sqrt(eq->var_values[VAR_GAMMA_R] / eq->var_values[VAR_GAMMA_G]); |
|
138 |
+ eq->param[0].gamma = eq->gamma * eq->gamma_g; |
|
139 |
+ eq->param[1].gamma = sqrt(eq->gamma_b / eq->gamma_g); |
|
140 |
+ eq->param[2].gamma = sqrt(eq->gamma_r / eq->gamma_g); |
|
141 | 141 |
|
142 | 142 |
for (i = 0; i < 3; i++) { |
143 |
- eq->param[i].gamma_weight = eq->var_values[VAR_GAMMA_WEIGHT]; |
|
143 |
+ eq->param[i].gamma_weight = eq->gamma_weight; |
|
144 | 144 |
eq->param[i].lut_clean = 0; |
145 | 145 |
check_values(&eq->param[i], eq); |
146 | 146 |
} |
... | ... |
@@ -150,10 +145,10 @@ static void set_saturation(EQContext *eq) |
150 | 150 |
{ |
151 | 151 |
int i; |
152 | 152 |
|
153 |
- eq->var_values[VAR_SATURATION] = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0); |
|
153 |
+ eq->saturation = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0); |
|
154 | 154 |
|
155 | 155 |
for (i = 1; i < 3; i++) { |
156 |
- eq->param[i].contrast = eq->var_values[VAR_SATURATION]; |
|
156 |
+ eq->param[i].contrast = eq->saturation; |
|
157 | 157 |
eq->param[i].lut_clean = 0; |
158 | 158 |
check_values(&eq->param[i], eq); |
159 | 159 |
} |
... | ... |
@@ -166,8 +161,7 @@ static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void * |
166 | 166 |
|
167 | 167 |
if (*pexpr) |
168 | 168 |
old = *pexpr; |
169 |
- ret = av_expr_parse(pexpr, expr, var_names, |
|
170 |
- NULL, NULL, NULL, NULL, 0, log_ctx); |
|
169 |
+ ret = av_expr_parse(pexpr, expr, var_names, NULL, NULL, NULL, NULL, 0, log_ctx); |
|
171 | 170 |
if (ret < 0) { |
172 | 171 |
av_log(log_ctx, AV_LOG_ERROR, |
173 | 172 |
"Error when parsing the expression '%s' for %s\n", |
... | ... |
@@ -200,10 +194,12 @@ static int initialize(AVFilterContext *ctx) |
200 | 200 |
if (ARCH_X86) |
201 | 201 |
ff_eq_init_x86(eq); |
202 | 202 |
|
203 |
- set_gamma(eq); |
|
204 |
- set_contrast(eq); |
|
205 |
- set_brightness(eq); |
|
206 |
- set_saturation(eq); |
|
203 |
+ if (eq->eval_mode == EVAL_MODE_INIT) { |
|
204 |
+ set_gamma(eq); |
|
205 |
+ set_contrast(eq); |
|
206 |
+ set_brightness(eq); |
|
207 |
+ set_saturation(eq); |
|
208 |
+ } |
|
207 | 209 |
|
208 | 210 |
return 0; |
209 | 211 |
} |
... | ... |
@@ -222,6 +218,17 @@ static void uninit(AVFilterContext *ctx) |
222 | 222 |
av_expr_free(eq->gamma_b_pexpr); eq->gamma_b_pexpr = NULL; |
223 | 223 |
} |
224 | 224 |
|
225 |
+static int config_props(AVFilterLink *inlink) |
|
226 |
+{ |
|
227 |
+ EQContext *eq = inlink->dst->priv; |
|
228 |
+ |
|
229 |
+ eq->var_values[VAR_N] = 0; |
|
230 |
+ eq->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ? |
|
231 |
+ NAN : av_q2d(inlink->frame_rate); |
|
232 |
+ |
|
233 |
+ return 0; |
|
234 |
+} |
|
235 |
+ |
|
225 | 236 |
static int query_formats(AVFilterContext *ctx) |
226 | 237 |
{ |
227 | 238 |
static const enum AVPixelFormat pixel_fmts_eq[] = { |
... | ... |
@@ -239,12 +246,15 @@ static int query_formats(AVFilterContext *ctx) |
239 | 239 |
return ff_set_common_formats(ctx, fmts_list); |
240 | 240 |
} |
241 | 241 |
|
242 |
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb)) |
|
243 |
+ |
|
242 | 244 |
static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
243 | 245 |
{ |
244 | 246 |
AVFilterContext *ctx = inlink->dst; |
245 | 247 |
AVFilterLink *outlink = inlink->dst->outputs[0]; |
246 | 248 |
EQContext *eq = ctx->priv; |
247 | 249 |
AVFrame *out; |
250 |
+ int64_t pos = av_frame_get_pkt_pos(in); |
|
248 | 251 |
const AVPixFmtDescriptor *desc; |
249 | 252 |
int i; |
250 | 253 |
|
... | ... |
@@ -255,6 +265,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
255 | 255 |
av_frame_copy_props(out, in); |
256 | 256 |
desc = av_pix_fmt_desc_get(inlink->format); |
257 | 257 |
|
258 |
+ eq->var_values[VAR_N] = inlink->frame_count; |
|
259 |
+ eq->var_values[VAR_POS] = pos == -1 ? NAN : pos; |
|
260 |
+ eq->var_values[VAR_T] = TS2T(in->pts, inlink->time_base); |
|
261 |
+ |
|
262 |
+ if (eq->eval_mode == EVAL_MODE_FRAME) { |
|
263 |
+ set_gamma(eq); |
|
264 |
+ set_contrast(eq); |
|
265 |
+ set_brightness(eq); |
|
266 |
+ set_saturation(eq); |
|
267 |
+ } |
|
268 |
+ |
|
258 | 269 |
for (i = 0; i < desc->nb_components; i++) { |
259 | 270 |
int w = inlink->w; |
260 | 271 |
int h = inlink->h; |
... | ... |
@@ -283,7 +304,8 @@ static inline int set_param(AVExpr **pexpr, const char *args, const char *cmd, |
283 | 283 |
int ret; |
284 | 284 |
if ((ret = set_expr(pexpr, args, cmd, ctx)) < 0) |
285 | 285 |
return ret; |
286 |
- set_fn(eq); |
|
286 |
+ if (eq->eval_mode == EVAL_MODE_INIT) |
|
287 |
+ set_fn(eq); |
|
287 | 288 |
return 0; |
288 | 289 |
} |
289 | 290 |
|
... | ... |
@@ -311,6 +333,7 @@ static const AVFilterPad eq_inputs[] = { |
311 | 311 |
.name = "default", |
312 | 312 |
.type = AVMEDIA_TYPE_VIDEO, |
313 | 313 |
.filter_frame = filter_frame, |
314 |
+ .config_props = config_props, |
|
314 | 315 |
}, |
315 | 316 |
{ NULL } |
316 | 317 |
}; |
... | ... |
@@ -343,6 +366,9 @@ static const AVOption eq_options[] = { |
343 | 343 |
OFFSET(gamma_b_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS }, |
344 | 344 |
{ "gamma_weight", "set the gamma weight which reduces the effect of gamma on bright areas", |
345 | 345 |
OFFSET(gamma_weight_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS }, |
346 |
+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" }, |
|
347 |
+ { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" }, |
|
348 |
+ { "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" }, |
|
346 | 349 |
{ NULL } |
347 | 350 |
}; |
348 | 351 |
|
... | ... |
@@ -28,28 +28,20 @@ |
28 | 28 |
#include "avfilter.h" |
29 | 29 |
#include "libavutil/eval.h" |
30 | 30 |
|
31 |
-static const char * const var_names[] = { |
|
32 |
- "contrast", |
|
33 |
- "brightness", |
|
34 |
- "saturation", |
|
35 |
- "gamma", |
|
36 |
- "gamma_weight", |
|
37 |
- "gamma_r", |
|
38 |
- "gamma_g", |
|
39 |
- "gamma_b", |
|
31 |
+static const char *const var_names[] = { |
|
32 |
+ "n", // frame count |
|
33 |
+ "pos", // frame position |
|
34 |
+ "r", // frame rate |
|
35 |
+ "t", // timestamp expressed in seconds |
|
40 | 36 |
NULL |
41 | 37 |
}; |
42 | 38 |
|
43 | 39 |
enum var_name { |
44 |
- VAR_CONTRAST , |
|
45 |
- VAR_BRIGHTNESS , |
|
46 |
- VAR_SATURATION , |
|
47 |
- VAR_GAMMA , |
|
48 |
- VAR_GAMMA_WEIGHT , |
|
49 |
- VAR_GAMMA_R , |
|
50 |
- VAR_GAMMA_G , |
|
51 |
- VAR_GAMMA_B , |
|
52 |
- VAR_VARS_NB , |
|
40 |
+ VAR_N, |
|
41 |
+ VAR_POS, |
|
42 |
+ VAR_R, |
|
43 |
+ VAR_T, |
|
44 |
+ VAR_NB |
|
53 | 45 |
}; |
54 | 46 |
|
55 | 47 |
typedef struct EQParameters { |
... | ... |
@@ -70,33 +62,42 @@ typedef struct { |
70 | 70 |
|
71 | 71 |
char *contrast_expr; |
72 | 72 |
AVExpr *contrast_pexpr; |
73 |
+ double contrast; |
|
73 | 74 |
|
74 | 75 |
char *brightness_expr; |
75 | 76 |
AVExpr *brightness_pexpr; |
77 |
+ double brightness; |
|
76 | 78 |
|
77 | 79 |
char *saturation_expr; |
78 | 80 |
AVExpr *saturation_pexpr; |
81 |
+ double saturation; |
|
79 | 82 |
|
80 | 83 |
char *gamma_expr; |
81 | 84 |
AVExpr *gamma_pexpr; |
85 |
+ double gamma; |
|
82 | 86 |
|
83 | 87 |
char *gamma_weight_expr; |
84 | 88 |
AVExpr *gamma_weight_pexpr; |
89 |
+ double gamma_weight; |
|
85 | 90 |
|
86 | 91 |
char *gamma_r_expr; |
87 | 92 |
AVExpr *gamma_r_pexpr; |
93 |
+ double gamma_r; |
|
88 | 94 |
|
89 | 95 |
char *gamma_g_expr; |
90 | 96 |
AVExpr *gamma_g_pexpr; |
97 |
+ double gamma_g; |
|
91 | 98 |
|
92 | 99 |
char *gamma_b_expr; |
93 | 100 |
AVExpr *gamma_b_pexpr; |
101 |
+ double gamma_b; |
|
94 | 102 |
|
95 |
- double var_values[VAR_VARS_NB]; |
|
103 |
+ double var_values[VAR_NB]; |
|
96 | 104 |
|
97 | 105 |
void (*process)(struct EQParameters *par, uint8_t *dst, int dst_stride, |
98 | 106 |
const uint8_t *src, int src_stride, int w, int h); |
99 | 107 |
|
108 |
+ enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, EVAL_MODE_NB } eval_mode; |
|
100 | 109 |
} EQContext; |
101 | 110 |
|
102 | 111 |
void ff_eq_init_x86(EQContext *eq); |