lavfi/hue: apply major simplifications, and switch to AVOption-based system
This also drops support for "flat syntax" and "reinit" command. "reinit" command is not very robust and complicates the logic more than necessary, since requires to reset all the options in the command. *This is a syntax break*.
This commit is contained in:
parent
c36ab01cd2
commit
e4fd58f472
@ -3653,24 +3653,27 @@ a float number which specifies chroma temporal strength, defaults to
|
|||||||
|
|
||||||
Modify the hue and/or the saturation of the input.
|
Modify the hue and/or the saturation of the input.
|
||||||
|
|
||||||
This filter accepts the following optional named options:
|
This filter accepts the following options:
|
||||||
|
|
||||||
@table @option
|
@table @option
|
||||||
@item h
|
@item h
|
||||||
Specify the hue angle as a number of degrees. It accepts a float
|
Specify the hue angle as a number of degrees. It accepts an expression,
|
||||||
number or an expression, and defaults to 0.0.
|
and defaults to "0".
|
||||||
|
|
||||||
@item H
|
|
||||||
Specify the hue angle as a number of radians. It accepts a float
|
|
||||||
number or an expression, and defaults to 0.0.
|
|
||||||
|
|
||||||
@item s
|
@item s
|
||||||
Specify the saturation in the [-10,10] range. It accepts a float number and
|
Specify the saturation in the [-10,10] range. It accepts a float number and
|
||||||
defaults to 1.0.
|
defaults to "1".
|
||||||
|
|
||||||
|
@item H
|
||||||
|
Specify the hue angle as a number of radians. It accepts a float
|
||||||
|
number or an expression, and defaults to "0".
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
The @var{h}, @var{H} and @var{s} parameters are expressions containing the
|
@option{h} and @option{H} are mutually exclusive, and can't be
|
||||||
following constants:
|
specified at the same time.
|
||||||
|
|
||||||
|
The @option{h}, @option{H} and @option{s} option values are
|
||||||
|
expressions containing the following constants:
|
||||||
|
|
||||||
@table @option
|
@table @option
|
||||||
@item n
|
@item n
|
||||||
@ -3689,10 +3692,6 @@ timestamp expressed in seconds, NAN if the input timestamp is unknown
|
|||||||
time base of the input video
|
time base of the input video
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
The options can also be set using the syntax: @var{hue}:@var{saturation}
|
|
||||||
|
|
||||||
In this case @var{hue} is expressed in degrees.
|
|
||||||
|
|
||||||
@subsection Examples
|
@subsection Examples
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@ -3708,19 +3707,6 @@ Same command but expressing the hue in radians:
|
|||||||
hue=H=PI/2:s=1
|
hue=H=PI/2:s=1
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@item
|
|
||||||
Same command without named options, hue must be expressed in degrees:
|
|
||||||
@example
|
|
||||||
hue=90:1
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@item
|
|
||||||
Note that "h:s" syntax does not support expressions for the values of
|
|
||||||
h and s, so the following example will issue an error:
|
|
||||||
@example
|
|
||||||
hue=PI/2:1
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Rotate hue and make the saturation swing between 0
|
Rotate hue and make the saturation swing between 0
|
||||||
and 2 over a period of 1 second:
|
and 2 over a period of 1 second:
|
||||||
@ -3756,12 +3742,15 @@ hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))"
|
|||||||
|
|
||||||
This filter supports the following command:
|
This filter supports the following command:
|
||||||
@table @option
|
@table @option
|
||||||
@item reinit
|
@item s
|
||||||
|
@item h
|
||||||
|
@item H
|
||||||
Modify the hue and/or the saturation of the input video.
|
Modify the hue and/or the saturation of the input video.
|
||||||
The command accepts the same named options and syntax than when calling the
|
The command accepts the same options and syntax of the corresponding
|
||||||
filter from the command-line.
|
options.
|
||||||
|
|
||||||
If a parameter is omitted, it is kept at its current value.
|
If the specified expression is not valid, it is kept at its current
|
||||||
|
value.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@section idet
|
@section idet
|
||||||
|
@ -679,7 +679,6 @@ static const char *const filters_left_to_update[] = {
|
|||||||
"atempo",
|
"atempo",
|
||||||
"buffer",
|
"buffer",
|
||||||
"flite",
|
"flite",
|
||||||
"hue",
|
|
||||||
"mp",
|
"mp",
|
||||||
"pan",
|
"pan",
|
||||||
"scale",
|
"scale",
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#define LIBAVFILTER_VERSION_MAJOR 3
|
#define LIBAVFILTER_VERSION_MAJOR 3
|
||||||
#define LIBAVFILTER_VERSION_MINOR 52
|
#define LIBAVFILTER_VERSION_MINOR 52
|
||||||
#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, \
|
||||||
|
@ -36,12 +36,6 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "video.h"
|
#include "video.h"
|
||||||
|
|
||||||
#define HUE_DEFAULT_VAL 0
|
|
||||||
#define SAT_DEFAULT_VAL 1
|
|
||||||
|
|
||||||
#define HUE_DEFAULT_VAL_STRING AV_STRINGIFY(HUE_DEFAULT_VAL)
|
|
||||||
#define SAT_DEFAULT_VAL_STRING AV_STRINGIFY(SAT_DEFAULT_VAL)
|
|
||||||
|
|
||||||
#define SAT_MIN_VAL -10
|
#define SAT_MIN_VAL -10
|
||||||
#define SAT_MAX_VAL 10
|
#define SAT_MAX_VAL 10
|
||||||
|
|
||||||
@ -78,7 +72,6 @@ typedef struct {
|
|||||||
int vsub;
|
int vsub;
|
||||||
int32_t hue_sin;
|
int32_t hue_sin;
|
||||||
int32_t hue_cos;
|
int32_t hue_cos;
|
||||||
int flat_syntax;
|
|
||||||
double var_values[VAR_NB];
|
double var_values[VAR_NB];
|
||||||
} HueContext;
|
} HueContext;
|
||||||
|
|
||||||
@ -87,9 +80,9 @@ typedef struct {
|
|||||||
static const AVOption hue_options[] = {
|
static const AVOption hue_options[] = {
|
||||||
{ "h", "set the hue angle degrees expression", OFFSET(hue_deg_expr), AV_OPT_TYPE_STRING,
|
{ "h", "set the hue angle degrees expression", OFFSET(hue_deg_expr), AV_OPT_TYPE_STRING,
|
||||||
{ .str = NULL }, .flags = FLAGS },
|
{ .str = NULL }, .flags = FLAGS },
|
||||||
{ "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
|
|
||||||
{ .str = NULL }, .flags = FLAGS },
|
|
||||||
{ "s", "set the saturation expression", OFFSET(saturation_expr), AV_OPT_TYPE_STRING,
|
{ "s", "set the saturation expression", OFFSET(saturation_expr), AV_OPT_TYPE_STRING,
|
||||||
|
{ .str = "1" }, .flags = FLAGS },
|
||||||
|
{ "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
|
||||||
{ .str = NULL }, .flags = FLAGS },
|
{ .str = NULL }, .flags = FLAGS },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
@ -107,99 +100,62 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SET_EXPRESSION(attr, name) do { \
|
static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
|
||||||
if (hue->attr##_expr) { \
|
|
||||||
if ((ret = av_expr_parse(&hue->attr##_pexpr, hue->attr##_expr, var_names, \
|
|
||||||
NULL, NULL, NULL, NULL, 0, ctx)) < 0) { \
|
|
||||||
av_log(ctx, AV_LOG_ERROR, \
|
|
||||||
"Parsing failed for expression " #name "='%s'", \
|
|
||||||
hue->attr##_expr); \
|
|
||||||
hue->attr##_expr = old_##attr##_expr; \
|
|
||||||
hue->attr##_pexpr = old_##attr##_pexpr; \
|
|
||||||
return AVERROR(EINVAL); \
|
|
||||||
} else if (old_##attr##_pexpr) { \
|
|
||||||
av_freep(&old_##attr##_expr); \
|
|
||||||
av_expr_free(old_##attr##_pexpr); \
|
|
||||||
old_##attr##_pexpr = NULL; \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
hue->attr##_expr = old_##attr##_expr; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static inline int set_options(AVFilterContext *ctx, const char *args)
|
|
||||||
{
|
{
|
||||||
HueContext *hue = ctx->priv;
|
|
||||||
int ret;
|
int ret;
|
||||||
char *old_hue_expr, *old_hue_deg_expr, *old_saturation_expr;
|
AVExpr *old = NULL;
|
||||||
AVExpr *old_hue_pexpr, *old_hue_deg_pexpr, *old_saturation_pexpr;
|
|
||||||
static const char *shorthand[] = { "h", "s", NULL };
|
|
||||||
old_hue_expr = hue->hue_expr;
|
|
||||||
old_hue_deg_expr = hue->hue_deg_expr;
|
|
||||||
old_saturation_expr = hue->saturation_expr;
|
|
||||||
|
|
||||||
old_hue_pexpr = hue->hue_pexpr;
|
if (*pexpr)
|
||||||
old_hue_deg_pexpr = hue->hue_deg_pexpr;
|
old = *pexpr;
|
||||||
old_saturation_pexpr = hue->saturation_pexpr;
|
ret = av_expr_parse(pexpr, expr, var_names,
|
||||||
|
NULL, NULL, NULL, NULL, 0, log_ctx);
|
||||||
hue->hue_expr = NULL;
|
if (ret < 0) {
|
||||||
hue->hue_deg_expr = NULL;
|
av_log(log_ctx, AV_LOG_ERROR,
|
||||||
hue->saturation_expr = NULL;
|
"Error when evaluating the expression '%s' for %s\n",
|
||||||
|
expr, option);
|
||||||
if ((ret = av_opt_set_from_string(hue, args, shorthand, "=", ":")) < 0)
|
*pexpr = old;
|
||||||
return ret;
|
return ret;
|
||||||
if (hue->hue_expr && hue->hue_deg_expr) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR,
|
|
||||||
"H and h options are incompatible and cannot be specified "
|
|
||||||
"at the same time\n");
|
|
||||||
hue->hue_expr = old_hue_expr;
|
|
||||||
hue->hue_deg_expr = old_hue_deg_expr;
|
|
||||||
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
}
|
||||||
|
av_expr_free(old);
|
||||||
SET_EXPRESSION(hue_deg, h);
|
|
||||||
SET_EXPRESSION(hue, H);
|
|
||||||
SET_EXPRESSION(saturation, s);
|
|
||||||
|
|
||||||
hue->flat_syntax = 0;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
compute_sin_and_cos(hue);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static av_cold int init(AVFilterContext *ctx, const char *args)
|
static av_cold int init(AVFilterContext *ctx, const char *args)
|
||||||
{
|
{
|
||||||
HueContext *hue = ctx->priv;
|
HueContext *hue = ctx->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
hue->class = &hue_class;
|
if (hue->hue_expr && hue->hue_deg_expr) {
|
||||||
av_opt_set_defaults(hue);
|
av_log(ctx, AV_LOG_ERROR,
|
||||||
|
"H and h options are incompatible and cannot be specified "
|
||||||
|
"at the same time\n");
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
hue->saturation = SAT_DEFAULT_VAL;
|
#define SET_EXPR(expr, option) \
|
||||||
hue->hue = HUE_DEFAULT_VAL;
|
if (hue->expr##_expr) do { \
|
||||||
hue->hue_deg_pexpr = NULL;
|
ret = set_expr(&hue->expr##_pexpr, hue->expr##_expr, option, ctx); \
|
||||||
hue->hue_pexpr = NULL;
|
if (ret < 0) \
|
||||||
hue->flat_syntax = 1;
|
return ret; \
|
||||||
|
} while (0)
|
||||||
|
SET_EXPR(saturation, "s");
|
||||||
|
SET_EXPR(hue_deg, "h");
|
||||||
|
SET_EXPR(hue, "H");
|
||||||
|
|
||||||
return set_options(ctx, args);
|
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);
|
||||||
|
compute_sin_and_cos(hue);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static av_cold void uninit(AVFilterContext *ctx)
|
static av_cold void uninit(AVFilterContext *ctx)
|
||||||
{
|
{
|
||||||
HueContext *hue = ctx->priv;
|
HueContext *hue = ctx->priv;
|
||||||
|
|
||||||
av_opt_free(hue);
|
|
||||||
|
|
||||||
av_free(hue->hue_deg_expr);
|
|
||||||
av_expr_free(hue->hue_deg_pexpr);
|
av_expr_free(hue->hue_deg_pexpr);
|
||||||
av_free(hue->hue_expr);
|
|
||||||
av_expr_free(hue->hue_pexpr);
|
av_expr_free(hue->hue_pexpr);
|
||||||
av_free(hue->saturation_expr);
|
|
||||||
av_expr_free(hue->saturation_pexpr);
|
av_expr_free(hue->saturation_pexpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +251,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
av_frame_copy_props(outpic, inpic);
|
av_frame_copy_props(outpic, inpic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hue->flat_syntax) {
|
/* todo: reindent */
|
||||||
hue->var_values[VAR_T] = TS2T(inpic->pts, inlink->time_base);
|
hue->var_values[VAR_T] = TS2T(inpic->pts, inlink->time_base);
|
||||||
hue->var_values[VAR_PTS] = TS2D(inpic->pts);
|
hue->var_values[VAR_PTS] = TS2D(inpic->pts);
|
||||||
|
|
||||||
@ -323,7 +279,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
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);
|
||||||
}
|
|
||||||
|
|
||||||
hue->var_values[VAR_N] += 1;
|
hue->var_values[VAR_N] += 1;
|
||||||
|
|
||||||
@ -345,10 +300,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
|
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
|
||||||
char *res, int res_len, int flags)
|
char *res, int res_len, int flags)
|
||||||
{
|
{
|
||||||
if (!strcmp(cmd, "reinit"))
|
HueContext *hue = ctx->priv;
|
||||||
return set_options(ctx, args);
|
|
||||||
else
|
#define SET_CMD(expr, option) \
|
||||||
return AVERROR(ENOSYS);
|
if (!strcmp(cmd, option)) do { \
|
||||||
|
return set_expr(&hue->expr##_pexpr, args, cmd, ctx); \
|
||||||
|
} while (0)
|
||||||
|
SET_CMD(hue_deg, "h");
|
||||||
|
SET_CMD(hue, "H");
|
||||||
|
SET_CMD(saturation, "s");
|
||||||
|
|
||||||
|
return AVERROR(ENOSYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AVFilterPad hue_inputs[] = {
|
static const AVFilterPad hue_inputs[] = {
|
||||||
|
Loading…
Reference in New Issue
Block a user