diff --git a/Changelog b/Changelog index 53c89cd349..90da1856e3 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,7 @@ version - HNM version 4 demuxer and video decoder - Live HDS muxer +- setsar/setdar filters now support variables in ratio expressions version 2.1: diff --git a/doc/filters.texi b/doc/filters.texi index 57679cca5c..7f07848e65 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -6970,6 +6970,31 @@ Default value is @code{100}. @end table +The parameter @var{sar} is an expression containing +the following constants: + +@table @option +@item E, PI, PHI +the corresponding mathematical approximated values for e +(euler number), pi (greek PI), phi (golden ratio) + +@item w, h +the input width and height + +@item a +same as @var{w} / @var{h} + +@item sar +input sample aspect ratio + +@item dar +input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar} + +@item hsub, vsub +horizontal and vertical chroma subsample values. For example for the +pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1. +@end table + @subsection Examples @itemize diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c index f926ea97b1..eaece16afe 100644 --- a/libavfilter/vf_aspect.c +++ b/libavfilter/vf_aspect.c @@ -30,11 +30,38 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" +#include "libavutil/pixdesc.h" #include "avfilter.h" #include "internal.h" #include "video.h" +static const char *const var_names[] = { + "PI", + "PHI", + "E", + "w", + "h", + "a", "dar", + "sar", + "hsub", + "vsub", + NULL +}; + +enum var_name { + VAR_PI, + VAR_PHI, + VAR_E, + VAR_W, + VAR_H, + VAR_A, VAR_DAR, + VAR_SAR, + VAR_HSUB, + VAR_VSUB, + VARS_NB +}; + typedef struct { const AVClass *class; AVRational dar; @@ -43,7 +70,7 @@ typedef struct { #if FF_API_OLD_FILTER_OPTS float aspect_den; #endif - char *ratio_str; + char *ratio_expr; } AspectContext; static av_cold int init(AVFilterContext *ctx) @@ -52,28 +79,20 @@ static av_cold int init(AVFilterContext *ctx) int ret; #if FF_API_OLD_FILTER_OPTS - if (s->ratio_str && s->aspect_den > 0) { + if (s->ratio_expr && s->aspect_den > 0) { double num; av_log(ctx, AV_LOG_WARNING, "num:den syntax is deprecated, please use num/den or named options instead\n"); - ret = av_expr_parse_and_eval(&num, s->ratio_str, NULL, NULL, + ret = av_expr_parse_and_eval(&num, s->ratio_expr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, ctx); if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_str); + av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_expr); return AVERROR(EINVAL); } s->sar = s->dar = av_d2q(num / s->aspect_den, s->max); - } else -#endif - if (s->ratio_str) { - ret = av_parse_ratio(&s->sar, s->ratio_str, s->max, 0, ctx); - if (ret < 0 || s->sar.num < 0 || s->sar.den <= 0) { - av_log(ctx, AV_LOG_ERROR, - "Invalid string '%s' for aspect ratio\n", s->ratio_str); - return AVERROR(EINVAL); - } - s->dar = s->sar; } +#endif + return 0; } @@ -97,6 +116,48 @@ static inline void compute_dar(AVRational *dar, AVRational sar, int w, int h) } } +static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio) +{ + AVFilterContext *ctx = inlink->dst; + AspectContext *s = inlink->dst->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + double var_values[VARS_NB], res; + int ret; + + var_values[VAR_PI] = M_PI; + var_values[VAR_PHI] = M_PHI; + var_values[VAR_E] = M_E; + var_values[VAR_W] = inlink->w; + var_values[VAR_H] = inlink->h; + var_values[VAR_A] = (double) inlink->w / inlink->h; + var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? + (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1; + var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; + var_values[VAR_HSUB] = 1 << desc->log2_chroma_w; + var_values[VAR_VSUB] = 1 << desc->log2_chroma_h; + + /* evaluate new aspect ratio*/ + ret = av_expr_parse_and_eval(&res, s->ratio_expr, + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx); + if (ret < 0) { + ret = av_parse_ratio(aspect_ratio, s->ratio_expr, s->max, 0, ctx); + } else + *aspect_ratio = av_d2q(res, s->max); + + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, + "Error when evaluating the expression '%s'\n", s->ratio_expr); + return ret; + } + if (aspect_ratio->num < 0 || aspect_ratio->den <= 0) { + av_log(ctx, AV_LOG_ERROR, + "Invalid string '%s' for aspect ratio\n", s->ratio_expr); + return AVERROR(EINVAL); + } + return 0; +} + #if CONFIG_SETDAR_FILTER static int setdar_config_props(AVFilterLink *inlink) @@ -105,6 +166,16 @@ static int setdar_config_props(AVFilterLink *inlink) AVRational dar; AVRational old_dar; AVRational old_sar = inlink->sample_aspect_ratio; + int ret; + +#if FF_API_OLD_FILTER_OPTS + if (!(s->ratio_expr && s->aspect_den > 0)) { +#endif + if ((ret = get_aspect_ratio(inlink, &s->dar))) + return ret; +#if FF_API_OLD_FILTER_OPTS + } +#endif if (s->dar.num && s->dar.den) { av_reduce(&s->sar.num, &s->sar.den, @@ -126,9 +197,9 @@ static int setdar_config_props(AVFilterLink *inlink) } static const AVOption setdar_options[] = { - { "dar", "set display aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, - { "ratio", "set display aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, - { "r", "set display aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, + { "dar", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, + { "ratio", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, + { "r", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, #if FF_API_OLD_FILTER_OPTS { "dar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, #endif @@ -175,6 +246,16 @@ static int setsar_config_props(AVFilterLink *inlink) AspectContext *s = inlink->dst->priv; AVRational old_sar = inlink->sample_aspect_ratio; AVRational old_dar, dar; + int ret; + +#if FF_API_OLD_FILTER_OPTS + if (!(s->ratio_expr && s->aspect_den > 0)) { +#endif + if ((ret = get_aspect_ratio(inlink, &s->sar))) + return ret; +#if FF_API_OLD_FILTER_OPTS + } +#endif inlink->sample_aspect_ratio = s->sar; @@ -188,9 +269,9 @@ static int setsar_config_props(AVFilterLink *inlink) } static const AVOption setsar_options[] = { - { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, - { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, - { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags=FLAGS }, + { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, + { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, + { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, #if FF_API_OLD_FILTER_OPTS { "sar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, #endif