[FFmpeg-devel] [PATCH] avfilter/vf_perspective: Add support for commands
Simon Binder
oss at simonbinder.eu
Thu Mar 31 23:54:42 EEST 2022
Store expressions to avoid parsing them for each change.
Support a command re-assigning all corners for the perspective.
Signed-off-by: Simon Binder <oss at simonbinder.eu>
---
doc/filters.texi | 13 ++++
libavfilter/vf_perspective.c | 114 ++++++++++++++++++++++++++++-------
2 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 1d56d24819..4fe4dc04d9 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -17201,6 +17201,19 @@ evaluate expressions for each incoming frame
Default value is @samp{init}.
@end table
+ at subsection Commands
+
+This filter supports the following command:
+
+ at table @option
+ at item dims
+Updates all eight coordinate values from one colon-separated parameter.
+ at example
+0.0 [enter] perspective dims 0:0:300:0:0:300:300:300;
+5.0 [enter] perspective dims 0:0:300:50:0:300:300:350;
+ at end example
+ at end table
+
@section phase
Delay interlaced video by one field time so that the field order changes.
diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c
index da720dcb54..e81234c7d6 100644
--- a/libavfilter/vf_perspective.c
+++ b/libavfilter/vf_perspective.c
@@ -19,13 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
+#include <libavutil/avstring.h>
#include "libavutil/avassert.h"
#include "libavutil/eval.h"
#include "libavutil/imgutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
#include "avfilter.h"
-#include "formats.h"
#include "internal.h"
#include "video.h"
@@ -36,9 +36,13 @@
#define LINEAR 0
#define CUBIC 1
+static const char *const var_names[] = { "W", "H", "in",
"on", NULL };
+enum { VAR_W, VAR_H, VAR_IN, VAR_ON,
VAR_VARS_NB };
+
typedef struct PerspectiveContext {
const AVClass *class;
char *expr_str[4][2];
+ AVExpr* expr[4][2];
double ref[4][2];
int32_t (*pv)[2];
int32_t coeff[SUB_PIXELS][4];
@@ -49,6 +53,7 @@ typedef struct PerspectiveContext {
int nb_planes;
int sense;
int eval_mode;
+ double var_values[VAR_VARS_NB];
int (*perspective)(AVFilterContext *ctx,
void *arg, int job, int nb_jobs);
@@ -117,34 +122,31 @@ static inline double get_coeff(double d)
return coeff;
}
-static const char *const var_names[] = { "W", "H", "in",
"on", NULL };
-enum { VAR_W, VAR_H, VAR_IN, VAR_ON,
VAR_VARS_NB };
-
-static int calc_persp_luts(AVFilterContext *ctx, AVFilterLink *inlink)
+static void set_variables_for_link(AVFilterContext *ctx, AVFilterLink
*inlink)
{
PerspectiveContext *s = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
+
+ s->var_values[VAR_W] = inlink->w;
+ s->var_values[VAR_H] = inlink->h;
+ s->var_values[VAR_IN] = inlink->frame_count_out + 1;
+ s->var_values[VAR_ON] = outlink->frame_count_in + 1;
+}
+
+static int calc_persp_luts(AVFilterContext *ctx)
+{
+ PerspectiveContext *s = ctx->priv;
double (*ref)[2] = s->ref;
- double values[VAR_VARS_NB] = { [VAR_W] = inlink->w, [VAR_H] =
inlink->h,
- [VAR_IN] = inlink->frame_count_out + 1,
- [VAR_ON] = outlink->frame_count_in +
1 };
- const int h = values[VAR_H];
- const int w = values[VAR_W];
+ const int h = s->var_values[VAR_H];
+ const int w = s->var_values[VAR_W];
double x0, x1, x2, x3, x4, x5, x6, x7, x8, q;
double t0, t1, t2, t3;
- int x, y, i, j, ret;
+ int x, y, i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 2; j++) {
- if (!s->expr_str[i][j])
- return AVERROR(EINVAL);
- ret = av_expr_parse_and_eval(&s->ref[i][j], s->expr_str[i][j],
- var_names, &values[0],
- NULL, NULL, NULL, NULL,
- 0, 0, ctx);
- if (ret < 0)
- return ret;
+ s->ref[i][j] = av_expr_eval(s->expr[i][j], s->var_values, s);
}
}
@@ -238,8 +240,27 @@ static int config_input(AVFilterLink *inlink)
if (!s->pv)
return AVERROR(ENOMEM);
+ // Parse coordinate expressions
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 2; j++) {
+ av_expr_free(s->expr[i][j]);
+ s->expr[i][j] = NULL;
+
+ if (!s->expr_str[i][j])
+ return AVERROR(EINVAL);
+
+ if ((ret = av_expr_parse(&s->expr[i][j], s->expr_str[i][j],
var_names,
+ NULL, NULL, NULL, NULL, 0, ctx)) <
0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Error occurred parsing coordinate '%s'\n",
s->expr_str[i][j]);
+ return ret;
+ }
+ }
+ }
+
if (s->eval_mode == EVAL_MODE_INIT) {
- if ((ret = calc_persp_luts(ctx, inlink)) < 0) {
+ set_variables_for_link(ctx, inlink);
+ if ((ret = calc_persp_luts(ctx)) < 0) {
return ret;
}
}
@@ -437,6 +458,49 @@ static av_cold int init(AVFilterContext *ctx)
return 0;
}
+static int process_command(AVFilterContext *ctx, const char *cmd,
const char *arg,
+ char *res, int res_len, int flags)
+{
+ PerspectiveContext *s = ctx->priv;
+ int ret;
+ char *token;
+ AVExpr *old;
+
+ if (!strcmp(cmd, "dims")) {
+ // Expect arg to be an 8-token argument containing the new
coordinates
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 2; j++) {
+ if (!*arg) {
+ av_log(ctx, AV_LOG_ERROR,"Expected 8 expressions
for the new coordinates\n");
+ return AVERROR(EINVAL);
+ }
+
+ token = av_get_token(&arg, ":");
+ if (!token)
+ return AVERROR(ENOMEM);
+ arg++;
+
+ old = s->expr[i][j];
+
+ if ((ret = av_expr_parse(&s->expr[i][j], token, var_names,
+ NULL, NULL, NULL, NULL, 0,
ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Error occurred parsing coordinate '%s'\n",
token);
+ av_free(token);
+ return ret;
+ }
+ av_free(token);
+ av_expr_free(old);
+ }
+ }
+
+ ret = calc_persp_luts(ctx);
+ } else
+ ret = AVERROR(ENOSYS);
+
+ return ret;
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
@@ -454,7 +518,8 @@ static int filter_frame(AVFilterLink *inlink,
AVFrame *frame)
av_frame_copy_props(out, frame);
if (s->eval_mode == EVAL_MODE_FRAME) {
- if ((ret = calc_persp_luts(ctx, inlink)) < 0) {
+ set_variables_for_link(ctx, inlink);
+ if ((ret = calc_persp_luts(ctx)) < 0) {
av_frame_free(&out);
return ret;
}
@@ -484,6 +549,12 @@ static av_cold void uninit(AVFilterContext *ctx)
PerspectiveContext *s = ctx->priv;
av_freep(&s->pv);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 2; j++) {
+ av_expr_free(s->expr[i][j]);
+ s->expr[i][j] = NULL;
+ }
+ }
}
static const AVFilterPad perspective_inputs[] = {
@@ -508,6 +579,7 @@ const AVFilter ff_vf_perspective = {
.priv_size = sizeof(PerspectiveContext),
.init = init,
.uninit = uninit,
+ .process_command = &process_command,
FILTER_INPUTS(perspective_inputs),
FILTER_OUTPUTS(perspective_outputs),
FILTER_PIXFMTS_ARRAY(pix_fmts),
--
2.35.1
More information about the ffmpeg-devel
mailing list