Browse code

lavfi/eq: rework expression evaluation

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>

arwa arif authored on 2015/03/13 15:16:42
Showing 4 changed files
... ...
@@ -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);