AV_OPT_TYPE_VIDEO_RATE AVOption types are parsed as expressions, but in a limited way. For example, name constants can only be parsed alone and not as part of a longer expression. This change allows usage like ffmpeg -i IN -vf fps="if(eq(source_fps\,film)\,ntsc_film\,source_fps)" OUT
Showing the changes to libavfilter (1 of 1 file). Show all
Unified · Split
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include <stdint.h> |
| 31 | 31 | |
| 32 | 32 | #include "libavutil/avassert.h" |
| 33 | +#include "libavutil/eval.h" | |
| 33 | 34 | #include "libavutil/mathematics.h" |
| 34 | 35 | #include "libavutil/opt.h" |
| 35 | 36 | #include "avfilter.h" |
| @@ -42,12 +43,47 @@ enum EOFAction { · 6 unmodified lines | ||
| 42 | 43 | EOF_ACTION_NB |
| 43 | 44 | }; |
| 44 | 45 | |
| 46 | +static const char *const var_names[] = { | |
| 47 | + "source_fps", | |
| 48 | + "ntsc", | |
| 49 | + "pal", | |
| 50 | + "qntsc", | |
| 51 | + "qpal", | |
| 52 | + "sntsc", | |
| 53 | + "spal", | |
| 54 | + "film", | |
| 55 | + "ntsc_film", | |
| 56 | + NULL | |
| 57 | +}; | |
| 58 | + | |
| 59 | +enum var_name { | |
| 60 | + VAR_SOURCE_FPS, | |
| 61 | + VAR_FPS_NTSC, | |
| 62 | + VAR_FPS_PAL, | |
| 63 | + VAR_FPS_QNTSC, | |
| 64 | + VAR_FPS_QPAL, | |
| 65 | + VAR_FPS_SNTSC, | |
| 66 | + VAR_FPS_SPAL, | |
| 67 | + VAR_FPS_FILM, | |
| 68 | + VAR_FPS_NTSC_FILM, | |
| 69 | + VARS_NB | |
| 70 | +}; | |
| 71 | + | |
| 72 | +static const double ntsc_fps = 30000.0 / 1001.0; | |
| 73 | +static const double pal_fps = 25.0; | |
| 74 | +static const double qntsc_fps = 30000.0 / 1001.0; | |
| 75 | +static const double qpal_fps = 25.0; | |
| 76 | +static const double sntsc_fps = 30000.0 / 1001.0; | |
| 77 | +static const double spal_fps = 25.0; | |
| 78 | +static const double film_fps = 24.0; | |
| 79 | +static const double ntsc_film_fps = 24000.0 / 1001.0; | |
| 80 | + | |
| 45 | 81 | typedef struct FPSContext { |
| 46 | 82 | const AVClass *class; |
| 47 | 83 | |
| 48 | 84 | double start_time; ///< pts, in seconds, of the expected first frame |
| 49 | 85 | |
| 50 | − AVRational framerate; ///< target framerate | |
| 86 | + char *framerate; ///< expression that defines the target framerate | |
| 51 | 87 | int rounding; ///< AVRounding method for timestamps |
| 52 | 88 | int eof_action; ///< action performed for last frame in FIFO |
| 53 | 89 | |
| @@ -76,7 +112,7 @@ typedef struct FPSContext { · 22 unmodified lines | ||
| 76 | 112 | #define V AV_OPT_FLAG_VIDEO_PARAM |
| 77 | 113 | #define F AV_OPT_FLAG_FILTERING_PARAM |
| 78 | 114 | static const AVOption fps_options[] = { |
| 79 | − { "fps", "A string describing desired output framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, V|F }, | |
| 115 | + { "fps", "A string describing desired output framerate", OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = "25" }, 0, 0, V|F }, | |
| 80 | 116 | { "start_time", "Assume the first PTS should be this value.", OFFSET(start_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX}, -DBL_MAX, DBL_MAX, V|F }, |
| 81 | 117 | { "round", "set rounding method for timestamps", OFFSET(rounding), AV_OPT_TYPE_INT, { .i64 = AV_ROUND_NEAR_INF }, 0, 5, V|F, "round" }, |
| 82 | 118 | { "zero", "round towards 0", 0, AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_ZERO }, 0, 0, V|F, "round" }, |
| @@ -99,7 +135,6 @@ static av_cold int init(AVFilterContext *ctx) · 16 unmodified lines | ||
| 99 | 135 | s->status_pts = AV_NOPTS_VALUE; |
| 100 | 136 | s->next_pts = AV_NOPTS_VALUE; |
| 101 | 137 | |
| 102 | − av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", s->framerate.num, s->framerate.den); | |
| 103 | 138 | return 0; |
| 104 | 139 | } |
| 105 | 140 | |
| @@ -153,8 +188,26 @@ static int config_props(AVFilterLink* outlink) · 47 unmodified lines | ||
| 153 | 188 | AVFilterLink *inlink = ctx->inputs[0]; |
| 154 | 189 | FPSContext *s = ctx->priv; |
| 155 | 190 | |
| 156 | − outlink->time_base = av_inv_q(s->framerate); | |
| 157 | − outlink->frame_rate = s->framerate; | |
| 191 | + double var_values[VARS_NB], res; | |
| 192 | + int ret; | |
| 193 | + | |
| 194 | + var_values[VAR_SOURCE_FPS] = av_q2d(inlink->frame_rate); | |
| 195 | + var_values[VAR_FPS_NTSC] = ntsc_fps; | |
| 196 | + var_values[VAR_FPS_PAL] = pal_fps; | |
| 197 | + var_values[VAR_FPS_QNTSC] = qntsc_fps; | |
| 198 | + var_values[VAR_FPS_QPAL] = qpal_fps; | |
| 199 | + var_values[VAR_FPS_SNTSC] = sntsc_fps; | |
| 200 | + var_values[VAR_FPS_SPAL] = spal_fps; | |
| 201 | + var_values[VAR_FPS_FILM] = film_fps; | |
| 202 | + var_values[VAR_FPS_NTSC_FILM] = ntsc_film_fps; | |
| 203 | + ret = av_expr_parse_and_eval(&res, s->framerate, | |
| 204 | + var_names, var_values, | |
| 205 | + NULL, NULL, NULL, NULL, NULL, 0, ctx); | |
| 206 | + if (ret < 0) | |
| 207 | + return ret; | |
| 208 | + | |
| 209 | + outlink->frame_rate = av_d2q(res, INT_MAX); | |
| 210 | + outlink->time_base = av_inv_q(outlink->frame_rate); | |
| 158 | 211 | |
| 159 | 212 | /* Calculate the input and output pts offsets for start_time */ |
| 160 | 213 | if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) { |
| @@ -173,6 +226,8 @@ static int config_props(AVFilterLink* outlink) · 12 unmodified lines | ||
| 173 | 226 | s->in_pts_off, s->out_pts_off, s->start_time); |
| 174 | 227 | } |
| 175 | 228 | |
| 229 | + av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", outlink->frame_rate.num, outlink->frame_rate.den); | |
| 230 | + | |
| 176 | 231 | return 0; |
| 177 | 232 | } |
| 178 | 233 | |