Commit b1e276f8 authored by Paul B Mahol's avatar Paul B Mahol

lavfi/hue: allow changing brightness

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent 6e643239
...@@ -4715,12 +4715,16 @@ defaults to "1". ...@@ -4715,12 +4715,16 @@ defaults to "1".
@item H @item H
Specify the hue angle as a number of radians. It accepts an Specify the hue angle as a number of radians. It accepts an
expression, and defaults to "0". expression, and defaults to "0".
@item b
Specify the brightness in the [-10,10] range. It accepts an expression and
defaults to "0".
@end table @end table
@option{h} and @option{H} are mutually exclusive, and can't be @option{h} and @option{H} are mutually exclusive, and can't be
specified at the same time. specified at the same time.
The @option{h}, @option{H} and @option{s} option values are The @option{b}, @option{h}, @option{H} and @option{s} option values are
expressions containing the following constants: expressions containing the following constants:
@table @option @table @option
...@@ -4790,10 +4794,11 @@ hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))" ...@@ -4790,10 +4794,11 @@ hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))"
This filter supports the following commands: This filter supports the following commands:
@table @option @table @option
@item b
@item s @item s
@item h @item h
@item H @item H
Modify the hue and/or the saturation of the input video. Modify the hue and/or the saturation and/or brightness of the input video.
The command accepts the same syntax of the corresponding option. The command accepts the same syntax of the corresponding option.
If the specified expression is not valid, it is kept at its current If the specified expression is not valid, it is kept at its current
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define LIBAVFILTER_VERSION_MAJOR 3 #define LIBAVFILTER_VERSION_MAJOR 3
#define LIBAVFILTER_VERSION_MINOR 82 #define LIBAVFILTER_VERSION_MINOR 82
#define LIBAVFILTER_VERSION_MICRO 101 #define LIBAVFILTER_VERSION_MICRO 102
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \ LIBAVFILTER_VERSION_MINOR, \
......
...@@ -68,11 +68,15 @@ typedef struct { ...@@ -68,11 +68,15 @@ typedef struct {
float saturation; float saturation;
char *saturation_expr; char *saturation_expr;
AVExpr *saturation_pexpr; AVExpr *saturation_pexpr;
float brightness;
char *brightness_expr;
AVExpr *brightness_pexpr;
int hsub; int hsub;
int vsub; int vsub;
int32_t hue_sin; int32_t hue_sin;
int32_t hue_cos; int32_t hue_cos;
double var_values[VAR_NB]; double var_values[VAR_NB];
uint8_t lut_l[256];
uint8_t lut_u[256][256]; uint8_t lut_u[256][256];
uint8_t lut_v[256][256]; uint8_t lut_v[256][256];
} HueContext; } HueContext;
...@@ -86,6 +90,8 @@ static const AVOption hue_options[] = { ...@@ -86,6 +90,8 @@ static const AVOption hue_options[] = {
{ .str = "1" }, .flags = FLAGS }, { .str = "1" }, .flags = FLAGS },
{ "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING, { "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
{ .str = NULL }, .flags = FLAGS }, { .str = NULL }, .flags = FLAGS },
{ "b", "set the brightness expression", OFFSET(brightness_expr), AV_OPT_TYPE_STRING,
{ .str = "0" }, .flags = FLAGS },
{ NULL } { NULL }
}; };
...@@ -102,6 +108,16 @@ static inline void compute_sin_and_cos(HueContext *hue) ...@@ -102,6 +108,16 @@ static inline void compute_sin_and_cos(HueContext *hue)
hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation); hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
} }
static inline void create_luma_lut(HueContext *h)
{
const float b = h->brightness;
int i;
for (i = 0; i < 256; i++) {
h->lut_l[i] = av_clip_uint8(i + b * 25.5);
}
}
static inline void create_chrominance_lut(HueContext *h, const int32_t c, static inline void create_chrominance_lut(HueContext *h, const int32_t c,
const int32_t s) const int32_t s)
{ {
...@@ -181,14 +197,15 @@ static av_cold int init(AVFilterContext *ctx) ...@@ -181,14 +197,15 @@ static av_cold int init(AVFilterContext *ctx)
if (ret < 0) \ if (ret < 0) \
return ret; \ return ret; \
} while (0) } while (0)
SET_EXPR(brightness, "b");
SET_EXPR(saturation, "s"); SET_EXPR(saturation, "s");
SET_EXPR(hue_deg, "h"); SET_EXPR(hue_deg, "h");
SET_EXPR(hue, "H"); SET_EXPR(hue, "H");
#undef SET_EXPR #undef SET_EXPR
av_log(ctx, AV_LOG_VERBOSE, av_log(ctx, AV_LOG_VERBOSE,
"H_expr:%s h_deg_expr:%s s_expr:%s\n", "H_expr:%s h_deg_expr:%s s_expr:%s b_expr:%s\n",
hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr); hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr, hue->brightness_expr);
compute_sin_and_cos(hue); compute_sin_and_cos(hue);
return 0; return 0;
...@@ -198,6 +215,7 @@ static av_cold void uninit(AVFilterContext *ctx) ...@@ -198,6 +215,7 @@ static av_cold void uninit(AVFilterContext *ctx)
{ {
HueContext *hue = ctx->priv; HueContext *hue = ctx->priv;
av_expr_free(hue->brightness_pexpr);
av_expr_free(hue->hue_deg_pexpr); av_expr_free(hue->hue_deg_pexpr);
av_expr_free(hue->hue_pexpr); av_expr_free(hue->hue_pexpr);
av_expr_free(hue->saturation_pexpr); av_expr_free(hue->saturation_pexpr);
...@@ -235,6 +253,22 @@ static int config_props(AVFilterLink *inlink) ...@@ -235,6 +253,22 @@ static int config_props(AVFilterLink *inlink)
return 0; return 0;
} }
static void apply_luma_lut(HueContext *s,
uint8_t *ldst, const int dst_linesize,
uint8_t *lsrc, const int src_linesize,
int w, int h)
{
int i;
while (h--) {
for (i = 0; i < w; i++)
ldst[i] = s->lut_l[lsrc[i]];
lsrc += src_linesize;
ldst += dst_linesize;
}
}
static void apply_lut(HueContext *s, static void apply_lut(HueContext *s,
uint8_t *udst, uint8_t *vdst, const int dst_linesize, uint8_t *udst, uint8_t *vdst, const int dst_linesize,
uint8_t *usrc, uint8_t *vsrc, const int src_linesize, uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
...@@ -267,6 +301,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) ...@@ -267,6 +301,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
AVFilterLink *outlink = inlink->dst->outputs[0]; AVFilterLink *outlink = inlink->dst->outputs[0];
AVFrame *outpic; AVFrame *outpic;
const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos; const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
const float old_brightness = hue->brightness;
int direct = 0; int direct = 0;
if (av_frame_is_writable(inpic)) { if (av_frame_is_writable(inpic)) {
...@@ -296,6 +331,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) ...@@ -296,6 +331,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
} }
} }
if (hue->brightness_expr) {
hue->brightness = av_expr_eval(hue->brightness_pexpr, hue->var_values, NULL);
if (hue->brightness < -10 || hue->brightness > 10) {
hue->brightness = av_clipf(hue->brightness, -10, 10);
av_log(inlink->dst, AV_LOG_WARNING,
"Brightness value not in range [%d,%d]: clipping value to %0.1f\n",
-10, 10, hue->brightness);
}
}
if (hue->hue_deg_expr) { if (hue->hue_deg_expr) {
hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL); hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL);
hue->hue = hue->hue_deg * M_PI / 180; hue->hue = hue->hue_deg * M_PI / 180;
...@@ -305,18 +351,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) ...@@ -305,18 +351,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
} }
av_log(inlink->dst, AV_LOG_DEBUG, av_log(inlink->dst, AV_LOG_DEBUG,
"H:%0.1f*PI h:%0.1f s:%0.f t:%0.1f n:%d\n", "H:%0.1f*PI h:%0.1f s:%0.f b:%0.f t:%0.1f n:%d\n",
hue->hue/M_PI, hue->hue_deg, hue->saturation, hue->hue/M_PI, hue->hue_deg, hue->saturation, hue->brightness,
hue->var_values[VAR_T], (int)hue->var_values[VAR_N]); hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
compute_sin_and_cos(hue); compute_sin_and_cos(hue);
if (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos) if (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos)
create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin); create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
if (old_brightness != hue->brightness && hue->brightness)
create_luma_lut(hue);
if (!direct) { if (!direct) {
av_image_copy_plane(outpic->data[0], outpic->linesize[0], if (!hue->brightness)
inpic->data[0], inpic->linesize[0], av_image_copy_plane(outpic->data[0], outpic->linesize[0],
inlink->w, inlink->h); inpic->data[0], inpic->linesize[0],
inlink->w, inlink->h);
if (inpic->data[3]) if (inpic->data[3])
av_image_copy_plane(outpic->data[3], outpic->linesize[3], av_image_copy_plane(outpic->data[3], outpic->linesize[3],
inpic->data[3], inpic->linesize[3], inpic->data[3], inpic->linesize[3],
...@@ -327,6 +377,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) ...@@ -327,6 +377,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
inpic->data[1], inpic->data[2], inpic->linesize[1], inpic->data[1], inpic->data[2], inpic->linesize[1],
FF_CEIL_RSHIFT(inlink->w, hue->hsub), FF_CEIL_RSHIFT(inlink->w, hue->hsub),
FF_CEIL_RSHIFT(inlink->h, hue->vsub)); FF_CEIL_RSHIFT(inlink->h, hue->vsub));
if (hue->brightness)
apply_luma_lut(hue, outpic->data[0], outpic->linesize[0],
inpic->data[0], inpic->linesize[0], inlink->w, inlink->h);
if (!direct) if (!direct)
av_frame_free(&inpic); av_frame_free(&inpic);
...@@ -355,6 +408,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar ...@@ -355,6 +408,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
av_freep(&hue->hue_deg_expr); av_freep(&hue->hue_deg_expr);
} else if (!strcmp(cmd, "s")) { } else if (!strcmp(cmd, "s")) {
SET_EXPR(saturation, "s"); SET_EXPR(saturation, "s");
} else if (!strcmp(cmd, "b")) {
SET_EXPR(brightness, "b");
} else } else
return AVERROR(ENOSYS); return AVERROR(ENOSYS);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment