|
|
|
@@ -27,11 +27,6 @@ |
|
|
|
* very simple video equalizer |
|
|
|
*/ |
|
|
|
|
|
|
|
/** |
|
|
|
* TODO: |
|
|
|
* - Add support to process_command |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "libavfilter/internal.h" |
|
|
|
#include "libavutil/common.h" |
|
|
|
#include "libavutil/imgutils.h" |
|
|
|
@@ -111,16 +106,16 @@ static void check_values(EQParameters *param, 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->param[0].contrast = eq->var_values[VAR_CONTRAST]; |
|
|
|
eq->contrast = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq), -2.0, 2.0); |
|
|
|
eq->param[0].contrast = eq->contrast; |
|
|
|
eq->param[0].lut_clean = 0; |
|
|
|
check_values(&eq->param[0], 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->param[0].brightness = eq->var_values[VAR_BRIGHTNESS]; |
|
|
|
eq->brightness = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0); |
|
|
|
eq->param[0].brightness = eq->brightness; |
|
|
|
eq->param[0].lut_clean = 0; |
|
|
|
check_values(&eq->param[0], eq); |
|
|
|
} |
|
|
|
@@ -129,18 +124,18 @@ static void set_gamma(EQContext *eq) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
eq->var_values[VAR_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->var_values[VAR_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->var_values[VAR_GAMMA_WEIGHT] = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0); |
|
|
|
eq->gamma = av_clipf(av_expr_eval(eq->gamma_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->gamma_g = av_clipf(av_expr_eval(eq->gamma_g_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->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[1].gamma = sqrt(eq->var_values[VAR_GAMMA_B] / eq->var_values[VAR_GAMMA_G]); |
|
|
|
eq->param[2].gamma = sqrt(eq->var_values[VAR_GAMMA_R] / eq->var_values[VAR_GAMMA_G]); |
|
|
|
eq->param[0].gamma = eq->gamma * eq->gamma_g; |
|
|
|
eq->param[1].gamma = sqrt(eq->gamma_b / eq->gamma_g); |
|
|
|
eq->param[2].gamma = sqrt(eq->gamma_r / eq->gamma_g); |
|
|
|
|
|
|
|
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; |
|
|
|
check_values(&eq->param[i], eq); |
|
|
|
} |
|
|
|
@@ -150,10 +145,10 @@ static void set_saturation(EQContext *eq) |
|
|
|
{ |
|
|
|
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++) { |
|
|
|
eq->param[i].contrast = eq->var_values[VAR_SATURATION]; |
|
|
|
eq->param[i].contrast = eq->saturation; |
|
|
|
eq->param[i].lut_clean = 0; |
|
|
|
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) |
|
|
|
old = *pexpr; |
|
|
|
ret = av_expr_parse(pexpr, expr, var_names, |
|
|
|
NULL, NULL, NULL, NULL, 0, log_ctx); |
|
|
|
ret = av_expr_parse(pexpr, expr, var_names, NULL, NULL, NULL, NULL, 0, log_ctx); |
|
|
|
if (ret < 0) { |
|
|
|
av_log(log_ctx, AV_LOG_ERROR, |
|
|
|
"Error when parsing the expression '%s' for %s\n", |
|
|
|
@@ -200,10 +194,12 @@ static int initialize(AVFilterContext *ctx) |
|
|
|
if (ARCH_X86) |
|
|
|
ff_eq_init_x86(eq); |
|
|
|
|
|
|
|
set_gamma(eq); |
|
|
|
set_contrast(eq); |
|
|
|
set_brightness(eq); |
|
|
|
set_saturation(eq); |
|
|
|
if (eq->eval_mode == EVAL_MODE_INIT) { |
|
|
|
set_gamma(eq); |
|
|
|
set_contrast(eq); |
|
|
|
set_brightness(eq); |
|
|
|
set_saturation(eq); |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
@@ -222,6 +218,17 @@ static void uninit(AVFilterContext *ctx) |
|
|
|
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 const enum AVPixelFormat pixel_fmts_eq[] = { |
|
|
|
@@ -239,12 +246,15 @@ static int query_formats(AVFilterContext *ctx) |
|
|
|
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) |
|
|
|
{ |
|
|
|
AVFilterContext *ctx = inlink->dst; |
|
|
|
AVFilterLink *outlink = inlink->dst->outputs[0]; |
|
|
|
EQContext *eq = ctx->priv; |
|
|
|
AVFrame *out; |
|
|
|
int64_t pos = av_frame_get_pkt_pos(in); |
|
|
|
const AVPixFmtDescriptor *desc; |
|
|
|
int i; |
|
|
|
|
|
|
|
@@ -255,6 +265,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
|
|
av_frame_copy_props(out, in); |
|
|
|
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++) { |
|
|
|
int w = inlink->w; |
|
|
|
int h = inlink->h; |
|
|
|
@@ -283,7 +304,8 @@ static inline int set_param(AVExpr **pexpr, const char *args, const char *cmd, |
|
|
|
int ret; |
|
|
|
if ((ret = set_expr(pexpr, args, cmd, ctx)) < 0) |
|
|
|
return ret; |
|
|
|
set_fn(eq); |
|
|
|
if (eq->eval_mode == EVAL_MODE_INIT) |
|
|
|
set_fn(eq); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -311,6 +333,7 @@ static const AVFilterPad eq_inputs[] = { |
|
|
|
.name = "default", |
|
|
|
.type = AVMEDIA_TYPE_VIDEO, |
|
|
|
.filter_frame = filter_frame, |
|
|
|
.config_props = config_props, |
|
|
|
}, |
|
|
|
{ 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 }, |
|
|
|
{ "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 }, |
|
|
|
{ "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 } |
|
|
|
}; |
|
|
|
|
|
|
|
|