lavfi/hue: allow changing brightness
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
6e643239d9
commit
b1e276f8df
@ -4715,12 +4715,16 @@ defaults to "1".
|
||||
@item H
|
||||
Specify the hue angle as a number of radians. It accepts an
|
||||
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
|
||||
|
||||
@option{h} and @option{H} are mutually exclusive, and can't be
|
||||
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:
|
||||
|
||||
@table @option
|
||||
@ -4790,10 +4794,11 @@ hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))"
|
||||
|
||||
This filter supports the following commands:
|
||||
@table @option
|
||||
@item b
|
||||
@item s
|
||||
@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.
|
||||
|
||||
If the specified expression is not valid, it is kept at its current
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
#define LIBAVFILTER_VERSION_MAJOR 3
|
||||
#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, \
|
||||
LIBAVFILTER_VERSION_MINOR, \
|
||||
|
@ -68,11 +68,15 @@ typedef struct {
|
||||
float saturation;
|
||||
char *saturation_expr;
|
||||
AVExpr *saturation_pexpr;
|
||||
float brightness;
|
||||
char *brightness_expr;
|
||||
AVExpr *brightness_pexpr;
|
||||
int hsub;
|
||||
int vsub;
|
||||
int32_t hue_sin;
|
||||
int32_t hue_cos;
|
||||
double var_values[VAR_NB];
|
||||
uint8_t lut_l[256];
|
||||
uint8_t lut_u[256][256];
|
||||
uint8_t lut_v[256][256];
|
||||
} HueContext;
|
||||
@ -86,6 +90,8 @@ static const AVOption hue_options[] = {
|
||||
{ .str = "1" }, .flags = FLAGS },
|
||||
{ "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
|
||||
{ .str = NULL }, .flags = FLAGS },
|
||||
{ "b", "set the brightness expression", OFFSET(brightness_expr), AV_OPT_TYPE_STRING,
|
||||
{ .str = "0" }, .flags = FLAGS },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -102,6 +108,16 @@ static inline void compute_sin_and_cos(HueContext *hue)
|
||||
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,
|
||||
const int32_t s)
|
||||
{
|
||||
@ -181,14 +197,15 @@ static av_cold int init(AVFilterContext *ctx)
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
} while (0)
|
||||
SET_EXPR(brightness, "b");
|
||||
SET_EXPR(saturation, "s");
|
||||
SET_EXPR(hue_deg, "h");
|
||||
SET_EXPR(hue, "H");
|
||||
#undef SET_EXPR
|
||||
|
||||
av_log(ctx, AV_LOG_VERBOSE,
|
||||
"H_expr:%s h_deg_expr:%s s_expr:%s\n",
|
||||
hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr);
|
||||
"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->brightness_expr);
|
||||
compute_sin_and_cos(hue);
|
||||
|
||||
return 0;
|
||||
@ -198,6 +215,7 @@ static av_cold void uninit(AVFilterContext *ctx)
|
||||
{
|
||||
HueContext *hue = ctx->priv;
|
||||
|
||||
av_expr_free(hue->brightness_pexpr);
|
||||
av_expr_free(hue->hue_deg_pexpr);
|
||||
av_expr_free(hue->hue_pexpr);
|
||||
av_expr_free(hue->saturation_pexpr);
|
||||
@ -235,6 +253,22 @@ static int config_props(AVFilterLink *inlink)
|
||||
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,
|
||||
uint8_t *udst, uint8_t *vdst, const int dst_linesize,
|
||||
uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
|
||||
@ -267,6 +301,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
||||
AVFilterLink *outlink = inlink->dst->outputs[0];
|
||||
AVFrame *outpic;
|
||||
const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
|
||||
const float old_brightness = hue->brightness;
|
||||
int direct = 0;
|
||||
|
||||
if (av_frame_is_writable(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) {
|
||||
hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL);
|
||||
hue->hue = hue->hue_deg * M_PI / 180;
|
||||
@ -305,18 +351,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
||||
}
|
||||
|
||||
av_log(inlink->dst, AV_LOG_DEBUG,
|
||||
"H:%0.1f*PI h:%0.1f s:%0.f t:%0.1f n:%d\n",
|
||||
hue->hue/M_PI, hue->hue_deg, hue->saturation,
|
||||
"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->brightness,
|
||||
hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
|
||||
|
||||
compute_sin_and_cos(hue);
|
||||
if (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos)
|
||||
create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
|
||||
|
||||
if (old_brightness != hue->brightness && hue->brightness)
|
||||
create_luma_lut(hue);
|
||||
|
||||
if (!direct) {
|
||||
av_image_copy_plane(outpic->data[0], outpic->linesize[0],
|
||||
inpic->data[0], inpic->linesize[0],
|
||||
inlink->w, inlink->h);
|
||||
if (!hue->brightness)
|
||||
av_image_copy_plane(outpic->data[0], outpic->linesize[0],
|
||||
inpic->data[0], inpic->linesize[0],
|
||||
inlink->w, inlink->h);
|
||||
if (inpic->data[3])
|
||||
av_image_copy_plane(outpic->data[3], outpic->linesize[3],
|
||||
inpic->data[3], inpic->linesize[3],
|
||||
@ -327,6 +377,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
||||
inpic->data[1], inpic->data[2], inpic->linesize[1],
|
||||
FF_CEIL_RSHIFT(inlink->w, hue->hsub),
|
||||
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)
|
||||
av_frame_free(&inpic);
|
||||
@ -355,6 +408,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
|
||||
av_freep(&hue->hue_deg_expr);
|
||||
} else if (!strcmp(cmd, "s")) {
|
||||
SET_EXPR(saturation, "s");
|
||||
} else if (!strcmp(cmd, "b")) {
|
||||
SET_EXPR(brightness, "b");
|
||||
} else
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user