Browse code

lavfi/hue: allow changing brightness

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2013/08/22 02:42:32
Showing 3 changed files
... ...
@@ -4715,12 +4715,16 @@ defaults to "1".
4715 4715
 @item H
4716 4716
 Specify the hue angle as a number of radians. It accepts an
4717 4717
 expression, and defaults to "0".
4718
+
4719
+@item b
4720
+Specify the brightness in the [-10,10] range. It accepts an expression and
4721
+defaults to "0".
4718 4722
 @end table
4719 4723
 
4720 4724
 @option{h} and @option{H} are mutually exclusive, and can't be
4721 4725
 specified at the same time.
4722 4726
 
4723
-The @option{h}, @option{H} and @option{s} option values are
4727
+The @option{b}, @option{h}, @option{H} and @option{s} option values are
4724 4728
 expressions containing the following constants:
4725 4729
 
4726 4730
 @table @option
... ...
@@ -4790,10 +4794,11 @@ hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))"
4790 4790
 
4791 4791
 This filter supports the following commands:
4792 4792
 @table @option
4793
+@item b
4793 4794
 @item s
4794 4795
 @item h
4795 4796
 @item H
4796
-Modify the hue and/or the saturation of the input video.
4797
+Modify the hue and/or the saturation and/or brightness of the input video.
4797 4798
 The command accepts the same syntax of the corresponding option.
4798 4799
 
4799 4800
 If the specified expression is not valid, it is kept at its current
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR  3
33 33
 #define LIBAVFILTER_VERSION_MINOR  82
34
-#define LIBAVFILTER_VERSION_MICRO 101
34
+#define LIBAVFILTER_VERSION_MICRO 102
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
37 37
                                                LIBAVFILTER_VERSION_MINOR, \
... ...
@@ -68,11 +68,15 @@ typedef struct {
68 68
     float    saturation;
69 69
     char     *saturation_expr;
70 70
     AVExpr   *saturation_pexpr;
71
+    float    brightness;
72
+    char     *brightness_expr;
73
+    AVExpr   *brightness_pexpr;
71 74
     int      hsub;
72 75
     int      vsub;
73 76
     int32_t hue_sin;
74 77
     int32_t hue_cos;
75 78
     double   var_values[VAR_NB];
79
+    uint8_t  lut_l[256];
76 80
     uint8_t  lut_u[256][256];
77 81
     uint8_t  lut_v[256][256];
78 82
 } HueContext;
... ...
@@ -86,6 +90,8 @@ static const AVOption hue_options[] = {
86 86
       { .str = "1" }, .flags = FLAGS },
87 87
     { "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
88 88
       { .str = NULL }, .flags = FLAGS },
89
+    { "b", "set the brightness expression", OFFSET(brightness_expr), AV_OPT_TYPE_STRING,
90
+      { .str = "0" }, .flags = FLAGS },
89 91
     { NULL }
90 92
 };
91 93
 
... ...
@@ -102,6 +108,16 @@ static inline void compute_sin_and_cos(HueContext *hue)
102 102
     hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
103 103
 }
104 104
 
105
+static inline void create_luma_lut(HueContext *h)
106
+{
107
+    const float b = h->brightness;
108
+    int i;
109
+
110
+    for (i = 0; i < 256; i++) {
111
+        h->lut_l[i] = av_clip_uint8(i + b * 25.5);
112
+    }
113
+}
114
+
105 115
 static inline void create_chrominance_lut(HueContext *h, const int32_t c,
106 116
                                           const int32_t s)
107 117
 {
... ...
@@ -181,14 +197,15 @@ static av_cold int init(AVFilterContext *ctx)
181 181
         if (ret < 0)                                                    \
182 182
             return ret;                                                 \
183 183
     } while (0)
184
+    SET_EXPR(brightness, "b");
184 185
     SET_EXPR(saturation, "s");
185 186
     SET_EXPR(hue_deg,    "h");
186 187
     SET_EXPR(hue,        "H");
187 188
 #undef SET_EXPR
188 189
 
189 190
     av_log(ctx, AV_LOG_VERBOSE,
190
-           "H_expr:%s h_deg_expr:%s s_expr:%s\n",
191
-           hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr);
191
+           "H_expr:%s h_deg_expr:%s s_expr:%s b_expr:%s\n",
192
+           hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr, hue->brightness_expr);
192 193
     compute_sin_and_cos(hue);
193 194
 
194 195
     return 0;
... ...
@@ -198,6 +215,7 @@ static av_cold void uninit(AVFilterContext *ctx)
198 198
 {
199 199
     HueContext *hue = ctx->priv;
200 200
 
201
+    av_expr_free(hue->brightness_pexpr);
201 202
     av_expr_free(hue->hue_deg_pexpr);
202 203
     av_expr_free(hue->hue_pexpr);
203 204
     av_expr_free(hue->saturation_pexpr);
... ...
@@ -235,6 +253,22 @@ static int config_props(AVFilterLink *inlink)
235 235
     return 0;
236 236
 }
237 237
 
238
+static void apply_luma_lut(HueContext *s,
239
+                           uint8_t *ldst, const int dst_linesize,
240
+                           uint8_t *lsrc, const int src_linesize,
241
+                           int w, int h)
242
+{
243
+    int i;
244
+
245
+    while (h--) {
246
+        for (i = 0; i < w; i++)
247
+            ldst[i] = s->lut_l[lsrc[i]];
248
+
249
+        lsrc += src_linesize;
250
+        ldst += dst_linesize;
251
+    }
252
+}
253
+
238 254
 static void apply_lut(HueContext *s,
239 255
                       uint8_t *udst, uint8_t *vdst, const int dst_linesize,
240 256
                       uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
... ...
@@ -267,6 +301,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
267 267
     AVFilterLink *outlink = inlink->dst->outputs[0];
268 268
     AVFrame *outpic;
269 269
     const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
270
+    const float old_brightness = hue->brightness;
270 271
     int direct = 0;
271 272
 
272 273
     if (av_frame_is_writable(inpic)) {
... ...
@@ -296,6 +331,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
296 296
         }
297 297
     }
298 298
 
299
+    if (hue->brightness_expr) {
300
+        hue->brightness = av_expr_eval(hue->brightness_pexpr, hue->var_values, NULL);
301
+
302
+        if (hue->brightness < -10 || hue->brightness > 10) {
303
+            hue->brightness = av_clipf(hue->brightness, -10, 10);
304
+            av_log(inlink->dst, AV_LOG_WARNING,
305
+                   "Brightness value not in range [%d,%d]: clipping value to %0.1f\n",
306
+                   -10, 10, hue->brightness);
307
+        }
308
+    }
309
+
299 310
     if (hue->hue_deg_expr) {
300 311
         hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL);
301 312
         hue->hue = hue->hue_deg * M_PI / 180;
... ...
@@ -305,18 +351,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
305 305
     }
306 306
 
307 307
     av_log(inlink->dst, AV_LOG_DEBUG,
308
-           "H:%0.1f*PI h:%0.1f s:%0.f t:%0.1f n:%d\n",
309
-           hue->hue/M_PI, hue->hue_deg, hue->saturation,
308
+           "H:%0.1f*PI h:%0.1f s:%0.f b:%0.f t:%0.1f n:%d\n",
309
+           hue->hue/M_PI, hue->hue_deg, hue->saturation, hue->brightness,
310 310
            hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
311 311
 
312 312
     compute_sin_and_cos(hue);
313 313
     if (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos)
314 314
         create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
315 315
 
316
+    if (old_brightness != hue->brightness && hue->brightness)
317
+        create_luma_lut(hue);
318
+
316 319
     if (!direct) {
317
-        av_image_copy_plane(outpic->data[0], outpic->linesize[0],
318
-                            inpic->data[0],  inpic->linesize[0],
319
-                            inlink->w, inlink->h);
320
+        if (!hue->brightness)
321
+            av_image_copy_plane(outpic->data[0], outpic->linesize[0],
322
+                                inpic->data[0],  inpic->linesize[0],
323
+                                inlink->w, inlink->h);
320 324
         if (inpic->data[3])
321 325
             av_image_copy_plane(outpic->data[3], outpic->linesize[3],
322 326
                                 inpic->data[3],  inpic->linesize[3],
... ...
@@ -327,6 +377,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
327 327
               inpic->data[1],  inpic->data[2],  inpic->linesize[1],
328 328
               FF_CEIL_RSHIFT(inlink->w, hue->hsub),
329 329
               FF_CEIL_RSHIFT(inlink->h, hue->vsub));
330
+    if (hue->brightness)
331
+        apply_luma_lut(hue, outpic->data[0], outpic->linesize[0],
332
+                       inpic->data[0], inpic->linesize[0], inlink->w, inlink->h);
330 333
 
331 334
     if (!direct)
332 335
         av_frame_free(&inpic);
... ...
@@ -355,6 +408,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
355 355
         av_freep(&hue->hue_deg_expr);
356 356
     } else if (!strcmp(cmd, "s")) {
357 357
         SET_EXPR(saturation, "s");
358
+    } else if (!strcmp(cmd, "b")) {
359
+        SET_EXPR(brightness, "b");
358 360
     } else
359 361
         return AVERROR(ENOSYS);
360 362