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>
pull/125/head
arwa arif 10 years ago committed by Stefano Sabatini
parent e6547cce72
commit 9015ca359f
  1. 70
      doc/filters.texi
  2. 2
      libavfilter/version.h
  3. 80
      libavfilter/vf_eq.c
  4. 39
      libavfilter/vf_eq.h

@ -4366,40 +4366,72 @@ The filter accepts the following options:
@table @option @table @option
@item contrast @item contrast
Set the contrast value. It accepts a float value in range @code{-2.0} to Set the contrast expression. The value must be a float value in range
@code{2.0}. The default value is @code{0.0}. @code{-2.0} to @code{2.0}. The default value is "0".
@item brightness @item brightness
Set the brightness value. It accepts a float value in range @code{-1.0} to Set the brightness expression. The value must be a float value in
@code{1.0}. The default value is @code{0.0}. range @code{-1.0} to @code{1.0}. The default value is "0".
@item saturation @item saturation
Set the saturation value. It accepts a float value in range @code{0.0} to Set the saturation expression. The value must be a float in
@code{3.0}. The default value is @code{1.0}. range @code{0.0} to @code{3.0}. The default value is "1".
@item gamma @item gamma
Set the gamma value. It accepts a float value in range @code{0.1} to @code{10.0}. Set the gamma expression. The value must be a float in range
The default value is @code{1.0}. @code{0.1} to @code{10.0}. The default value is "1".
@item gamma_r @item gamma_r
Set the gamma value for red. It accepts a float value in range Set the gamma expression for red. The value must be a float in
@code{0.1} to @code{10.0}. The default value is @code{1.0}. range @code{0.1} to @code{10.0}. The default value is "1".
@item gamma_g @item gamma_g
Set the gamma value for green. It accepts a float value in range Set the gamma expression for green. The value must be a float in range
@code{0.1} to @code{10.0}. The default value is @code{1.0}. @code{0.1} to @code{10.0}. The default value is "1".
@item gamma_b @item gamma_b
Set the gamma value for blue. It accepts a float value in range Set the gamma expression for blue. The value must be a float in range
@code{0.1} to @code{10.0}. The default value is @code{1.0}. @code{0.1} to @code{10.0}. The default value is "1".
@item gamma_weight @item gamma_weight
Can be used to reduce the effect of a high gamma value on bright image areas, Set the gamma weight expression. It can be used to reduce the effect
e.g. keep them from getting overamplified and just plain white. It accepts a of a high gamma value on bright image areas, e.g. keep them from
float value in range @code{0.0} to @code{1.0}.A value of @code{0.0} turns the getting overamplified and just plain white. The value must be a float
gamma correction all the way down while @code{1.0} leaves it at its full strength. in range @code{0.0} to @code{1.0}. A value of @code{0.0} turns the
Default is @code{1.0}. gamma correction all the way down while @code{1.0} leaves it at its
full strength. Default is "1".
@item eval
Set when the expressions for brightness, contrast, saturation and
gamma expressions are evaluated.
It accepts the following values:
@table @samp
@item init
only evaluate expressions once during the filter initialization or
when a command is processed
@item frame
evaluate expressions for each incoming frame
@end table
Default value is @samp{init}.
@end table
The expressions accept the following parameters:
@table @option
@item n
frame count of the input frame starting from 0
@item pos
byte position of the corresponding packet in the input file, NAN if
unspecified
@item r
frame rate of the input video, NAN if the input frame rate is unknown
@item t
timestamp expressed in seconds, NAN if the input timestamp is unknown
@end table @end table
@subsection Commands @subsection Commands

@ -31,7 +31,7 @@
#define LIBAVFILTER_VERSION_MAJOR 5 #define LIBAVFILTER_VERSION_MAJOR 5
#define LIBAVFILTER_VERSION_MINOR 13 #define LIBAVFILTER_VERSION_MINOR 13
#define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_MICRO 101
#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, \

@ -27,11 +27,6 @@
* very simple video equalizer * very simple video equalizer
*/ */
/**
* TODO:
* - Add support to process_command
*/
#include "libavfilter/internal.h" #include "libavfilter/internal.h"
#include "libavutil/common.h" #include "libavutil/common.h"
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
@ -111,16 +106,16 @@ static void check_values(EQParameters *param, EQContext *eq)
static void set_contrast(EQContext *eq) static void set_contrast(EQContext *eq)
{ {
eq->var_values[VAR_CONTRAST] = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq),-2.0, 2.0); eq->contrast = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq), -2.0, 2.0);
eq->param[0].contrast = eq->var_values[VAR_CONTRAST]; eq->param[0].contrast = eq->contrast;
eq->param[0].lut_clean = 0; eq->param[0].lut_clean = 0;
check_values(&eq->param[0], eq); check_values(&eq->param[0], eq);
} }
static void set_brightness(EQContext *eq) static void set_brightness(EQContext *eq)
{ {
eq->var_values[VAR_BRIGHTNESS] = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0); eq->brightness = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0);
eq->param[0].brightness = eq->var_values[VAR_BRIGHTNESS]; eq->param[0].brightness = eq->brightness;
eq->param[0].lut_clean = 0; eq->param[0].lut_clean = 0;
check_values(&eq->param[0], eq); check_values(&eq->param[0], eq);
} }
@ -129,18 +124,18 @@ static void set_gamma(EQContext *eq)
{ {
int i; int i;
eq->var_values[VAR_GAMMA] = av_clipf(av_expr_eval(eq->gamma_pexpr, eq->var_values, eq), 0.1, 10.0); eq->gamma = av_clipf(av_expr_eval(eq->gamma_pexpr, eq->var_values, eq), 0.1, 10.0);
eq->var_values[VAR_GAMMA_R] = av_clipf(av_expr_eval(eq->gamma_r_pexpr, eq->var_values, eq), 0.1, 10.0); eq->gamma_r = av_clipf(av_expr_eval(eq->gamma_r_pexpr, eq->var_values, eq), 0.1, 10.0);
eq->var_values[VAR_GAMMA_G] = av_clipf(av_expr_eval(eq->gamma_g_pexpr, eq->var_values, eq), 0.1, 10.0); eq->gamma_g = av_clipf(av_expr_eval(eq->gamma_g_pexpr, eq->var_values, eq), 0.1, 10.0);
eq->var_values[VAR_GAMMA_B] = av_clipf(av_expr_eval(eq->gamma_b_pexpr, eq->var_values, eq), 0.1, 10.0); eq->gamma_b = av_clipf(av_expr_eval(eq->gamma_b_pexpr, eq->var_values, eq), 0.1, 10.0);
eq->var_values[VAR_GAMMA_WEIGHT] = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0); eq->gamma_weight = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0);
eq->param[0].gamma = eq->var_values[VAR_GAMMA] * eq->var_values[VAR_GAMMA_G]; eq->param[0].gamma = eq->gamma * eq->gamma_g;
eq->param[1].gamma = sqrt(eq->var_values[VAR_GAMMA_B] / eq->var_values[VAR_GAMMA_G]); eq->param[1].gamma = sqrt(eq->gamma_b / eq->gamma_g);
eq->param[2].gamma = sqrt(eq->var_values[VAR_GAMMA_R] / eq->var_values[VAR_GAMMA_G]); eq->param[2].gamma = sqrt(eq->gamma_r / eq->gamma_g);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
eq->param[i].gamma_weight = eq->var_values[VAR_GAMMA_WEIGHT]; eq->param[i].gamma_weight = eq->gamma_weight;
eq->param[i].lut_clean = 0; eq->param[i].lut_clean = 0;
check_values(&eq->param[i], eq); check_values(&eq->param[i], eq);
} }
@ -150,10 +145,10 @@ static void set_saturation(EQContext *eq)
{ {
int i; int i;
eq->var_values[VAR_SATURATION] = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0); eq->saturation = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0);
for (i = 1; i < 3; i++) { for (i = 1; i < 3; i++) {
eq->param[i].contrast = eq->var_values[VAR_SATURATION]; eq->param[i].contrast = eq->saturation;
eq->param[i].lut_clean = 0; eq->param[i].lut_clean = 0;
check_values(&eq->param[i], eq); check_values(&eq->param[i], eq);
} }
@ -166,8 +161,7 @@ static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *
if (*pexpr) if (*pexpr)
old = *pexpr; old = *pexpr;
ret = av_expr_parse(pexpr, expr, var_names, ret = av_expr_parse(pexpr, expr, var_names, NULL, NULL, NULL, NULL, 0, log_ctx);
NULL, NULL, NULL, NULL, 0, log_ctx);
if (ret < 0) { if (ret < 0) {
av_log(log_ctx, AV_LOG_ERROR, av_log(log_ctx, AV_LOG_ERROR,
"Error when parsing the expression '%s' for %s\n", "Error when parsing the expression '%s' for %s\n",
@ -200,10 +194,12 @@ static int initialize(AVFilterContext *ctx)
if (ARCH_X86) if (ARCH_X86)
ff_eq_init_x86(eq); ff_eq_init_x86(eq);
set_gamma(eq); if (eq->eval_mode == EVAL_MODE_INIT) {
set_contrast(eq); set_gamma(eq);
set_brightness(eq); set_contrast(eq);
set_saturation(eq); set_brightness(eq);
set_saturation(eq);
}
return 0; return 0;
} }
@ -222,6 +218,17 @@ static void uninit(AVFilterContext *ctx)
av_expr_free(eq->gamma_b_pexpr); eq->gamma_b_pexpr = NULL; av_expr_free(eq->gamma_b_pexpr); eq->gamma_b_pexpr = NULL;
} }
static int config_props(AVFilterLink *inlink)
{
EQContext *eq = inlink->dst->priv;
eq->var_values[VAR_N] = 0;
eq->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ?
NAN : av_q2d(inlink->frame_rate);
return 0;
}
static int query_formats(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx)
{ {
static const enum AVPixelFormat pixel_fmts_eq[] = { static const enum AVPixelFormat pixel_fmts_eq[] = {
@ -239,12 +246,15 @@ static int query_formats(AVFilterContext *ctx)
return ff_set_common_formats(ctx, fmts_list); return ff_set_common_formats(ctx, fmts_list);
} }
#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
static int filter_frame(AVFilterLink *inlink, AVFrame *in) static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{ {
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = inlink->dst->outputs[0]; AVFilterLink *outlink = inlink->dst->outputs[0];
EQContext *eq = ctx->priv; EQContext *eq = ctx->priv;
AVFrame *out; AVFrame *out;
int64_t pos = av_frame_get_pkt_pos(in);
const AVPixFmtDescriptor *desc; const AVPixFmtDescriptor *desc;
int i; int i;
@ -255,6 +265,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_copy_props(out, in); av_frame_copy_props(out, in);
desc = av_pix_fmt_desc_get(inlink->format); desc = av_pix_fmt_desc_get(inlink->format);
eq->var_values[VAR_N] = inlink->frame_count;
eq->var_values[VAR_POS] = pos == -1 ? NAN : pos;
eq->var_values[VAR_T] = TS2T(in->pts, inlink->time_base);
if (eq->eval_mode == EVAL_MODE_FRAME) {
set_gamma(eq);
set_contrast(eq);
set_brightness(eq);
set_saturation(eq);
}
for (i = 0; i < desc->nb_components; i++) { for (i = 0; i < desc->nb_components; i++) {
int w = inlink->w; int w = inlink->w;
int h = inlink->h; int h = inlink->h;
@ -283,7 +304,8 @@ static inline int set_param(AVExpr **pexpr, const char *args, const char *cmd,
int ret; int ret;
if ((ret = set_expr(pexpr, args, cmd, ctx)) < 0) if ((ret = set_expr(pexpr, args, cmd, ctx)) < 0)
return ret; return ret;
set_fn(eq); if (eq->eval_mode == EVAL_MODE_INIT)
set_fn(eq);
return 0; return 0;
} }
@ -311,6 +333,7 @@ static const AVFilterPad eq_inputs[] = {
.name = "default", .name = "default",
.type = AVMEDIA_TYPE_VIDEO, .type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame, .filter_frame = filter_frame,
.config_props = config_props,
}, },
{ NULL } { NULL }
}; };
@ -343,6 +366,9 @@ static const AVOption eq_options[] = {
OFFSET(gamma_b_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS }, OFFSET(gamma_b_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "gamma_weight", "set the gamma weight which reduces the effect of gamma on bright areas", { "gamma_weight", "set the gamma weight which reduces the effect of gamma on bright areas",
OFFSET(gamma_weight_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS }, OFFSET(gamma_weight_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
{ "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
{ "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
{ NULL } { NULL }
}; };

@ -28,28 +28,20 @@
#include "avfilter.h" #include "avfilter.h"
#include "libavutil/eval.h" #include "libavutil/eval.h"
static const char * const var_names[] = { static const char *const var_names[] = {
"contrast", "n", // frame count
"brightness", "pos", // frame position
"saturation", "r", // frame rate
"gamma", "t", // timestamp expressed in seconds
"gamma_weight",
"gamma_r",
"gamma_g",
"gamma_b",
NULL NULL
}; };
enum var_name { enum var_name {
VAR_CONTRAST , VAR_N,
VAR_BRIGHTNESS , VAR_POS,
VAR_SATURATION , VAR_R,
VAR_GAMMA , VAR_T,
VAR_GAMMA_WEIGHT , VAR_NB
VAR_GAMMA_R ,
VAR_GAMMA_G ,
VAR_GAMMA_B ,
VAR_VARS_NB ,
}; };
typedef struct EQParameters { typedef struct EQParameters {
@ -70,33 +62,42 @@ typedef struct {
char *contrast_expr; char *contrast_expr;
AVExpr *contrast_pexpr; AVExpr *contrast_pexpr;
double contrast;
char *brightness_expr; char *brightness_expr;
AVExpr *brightness_pexpr; AVExpr *brightness_pexpr;
double brightness;
char *saturation_expr; char *saturation_expr;
AVExpr *saturation_pexpr; AVExpr *saturation_pexpr;
double saturation;
char *gamma_expr; char *gamma_expr;
AVExpr *gamma_pexpr; AVExpr *gamma_pexpr;
double gamma;
char *gamma_weight_expr; char *gamma_weight_expr;
AVExpr *gamma_weight_pexpr; AVExpr *gamma_weight_pexpr;
double gamma_weight;
char *gamma_r_expr; char *gamma_r_expr;
AVExpr *gamma_r_pexpr; AVExpr *gamma_r_pexpr;
double gamma_r;
char *gamma_g_expr; char *gamma_g_expr;
AVExpr *gamma_g_pexpr; AVExpr *gamma_g_pexpr;
double gamma_g;
char *gamma_b_expr; char *gamma_b_expr;
AVExpr *gamma_b_pexpr; AVExpr *gamma_b_pexpr;
double gamma_b;
double var_values[VAR_VARS_NB]; double var_values[VAR_NB];
void (*process)(struct EQParameters *par, uint8_t *dst, int dst_stride, void (*process)(struct EQParameters *par, uint8_t *dst, int dst_stride,
const uint8_t *src, int src_stride, int w, int h); const uint8_t *src, int src_stride, int w, int h);
enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, EVAL_MODE_NB } eval_mode;
} EQContext; } EQContext;
void ff_eq_init_x86(EQContext *eq); void ff_eq_init_x86(EQContext *eq);

Loading…
Cancel
Save