History

avfilter/scale_npp: add scale2ref_npp filter

Roman Arzumanyan committed 5 years ago

Commit 08a50191 parent 82e32516 files · +620 −40Browse files

Showing the changes to libavfilter (4 of 6 files). Show all

Unified · Split

4 files
  1. libavfilter/Makefile +1 −0
  2. libavfilter/allfilters.c +1 −0
  3. libavfilter/version.h +1 −1
  4. libavfilter/vf_scale_npp.c +505 −39
libavfilter/Makefile+1−0
@@ -415,6 +415,7 @@ OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_scale_qsv.o · 414 unmodified lines
415415 OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale_eval.o vaapi_vpp.o
416416 OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vf_scale_vulkan.o vulkan.o
417417 OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale_eval.o
418+OBJS-$(CONFIG_SCALE2REF_NPP_FILTER) += vf_scale_npp.o scale_eval.o
418419 OBJS-$(CONFIG_SCDET_FILTER) += vf_scdet.o
419420 OBJS-$(CONFIG_SCHARR_FILTER) += vf_convolution.o
420421 OBJS-$(CONFIG_SCROLL_FILTER) += vf_scroll.o
libavfilter/allfilters.c+1−0
@@ -396,6 +396,7 @@ extern const AVFilter ff_vf_scale_qsv; · 395 unmodified lines
396396 extern const AVFilter ff_vf_scale_vaapi;
397397 extern const AVFilter ff_vf_scale_vulkan;
398398 extern const AVFilter ff_vf_scale2ref;
399+extern const AVFilter ff_vf_scale2ref_npp;
399400 extern const AVFilter ff_vf_scdet;
400401 extern const AVFilter ff_vf_scharr;
401402 extern const AVFilter ff_vf_scroll;
libavfilter/version.h+1−1
@@ -31,7 +31,7 @@ · 30 unmodified lines
3131
3232 #define LIBAVFILTER_VERSION_MAJOR 8
3333 #define LIBAVFILTER_VERSION_MINOR 16
34−#define LIBAVFILTER_VERSION_MICRO 100
34+#define LIBAVFILTER_VERSION_MICRO 101
3535
3636
3737 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
libavfilter/vf_scale_npp.c+505−39
@@ -25,13 +25,13 @@ · 24 unmodified lines
2525 #include <stdio.h>
2626 #include <string.h>
2727
28−#include "libavutil/avstring.h"
29−#include "libavutil/common.h"
3028 #include "libavutil/hwcontext.h"
3129 #include "libavutil/hwcontext_cuda_internal.h"
3230 #include "libavutil/cuda_check.h"
3331 #include "libavutil/internal.h"
3432 #include "libavutil/opt.h"
33+#include "libavutil/parseutils.h"
34+#include "libavutil/eval.h"
3535 #include "libavutil/pixdesc.h"
3636
3737 #include "avfilter.h"
@@ -44,6 +44,7 @@ · 6 unmodified lines
4444
4545 static const enum AVPixelFormat supported_formats[] = {
4646 AV_PIX_FMT_YUV420P,
47+ AV_PIX_FMT_YUVA420P,
4748 AV_PIX_FMT_NV12,
4849 AV_PIX_FMT_YUV444P,
4950 };
@@ -67,12 +68,62 @@ typedef struct NPPScaleStageContext { · 17 unmodified lines
6768 struct {
6869 int width;
6970 int height;
70− } planes_in[3], planes_out[3];
71+ } planes_in[4], planes_out[4];
7172
7273 AVBufferRef *frames_ctx;
7374 AVFrame *frame;
7475 } NPPScaleStageContext;
7576
77+static const char *const var_names[] = {
78+ "in_w", "iw",
79+ "in_h", "ih",
80+ "out_w", "ow",
81+ "out_h", "oh",
82+ "a",
83+ "sar",
84+ "dar",
85+ "n",
86+ "t",
87+ "pos",
88+ "main_w",
89+ "main_h",
90+ "main_a",
91+ "main_sar",
92+ "main_dar", "mdar",
93+ "main_n",
94+ "main_t",
95+ "main_pos",
96+ NULL
97+};
98+
99+enum var_name {
100+ VAR_IN_W, VAR_IW,
101+ VAR_IN_H, VAR_IH,
102+ VAR_OUT_W, VAR_OW,
103+ VAR_OUT_H, VAR_OH,
104+ VAR_A,
105+ VAR_SAR,
106+ VAR_DAR,
107+ VAR_N,
108+ VAR_T,
109+ VAR_POS,
110+ VAR_S2R_MAIN_W,
111+ VAR_S2R_MAIN_H,
112+ VAR_S2R_MAIN_A,
113+ VAR_S2R_MAIN_SAR,
114+ VAR_S2R_MAIN_DAR, VAR_S2R_MDAR,
115+ VAR_S2R_MAIN_N,
116+ VAR_S2R_MAIN_T,
117+ VAR_S2R_MAIN_POS,
118+ VARS_NB
119+};
120+
121+enum EvalMode {
122+ EVAL_MODE_INIT,
123+ EVAL_MODE_FRAME,
124+ EVAL_MODE_NB
125+};
126+
76127 typedef struct NPPScaleContext {
77128 const AVClass *class;
78129
@@ -102,35 +153,269 @@ typedef struct NPPScaleContext { · 23 unmodified lines
102153 int force_divisible_by;
103154
104155 int interp_algo;
156+
157+ char* size_str;
158+
159+ AVExpr* w_pexpr;
160+ AVExpr* h_pexpr;
161+
162+ double var_values[VARS_NB];
163+
164+ int eval_mode;
105165 } NPPScaleContext;
106166
107−static int nppscale_init(AVFilterContext *ctx)
167+const AVFilter ff_vf_scale2ref_npp;
168+
169+static int config_props(AVFilterLink *outlink);
170+
171+static int check_exprs(AVFilterContext* ctx)
108172 {
109− NPPScaleContext *s = ctx->priv;
110− int i;
173+ NPPScaleContext* scale = ctx->priv;
174+ unsigned vars_w[VARS_NB] = {0}, vars_h[VARS_NB] = {0};
175+
176+ if (!scale->w_pexpr && !scale->h_pexpr)
177+ return AVERROR(EINVAL);
178+
179+ if (scale->w_pexpr)
180+ av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
181+ if (scale->h_pexpr)
182+ av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
183+
184+ if (vars_w[VAR_OUT_W] || vars_w[VAR_OW]) {
185+ av_log(ctx, AV_LOG_ERROR, "Width expression cannot be self-referencing: '%s'.\n", scale->w_expr);
186+ return AVERROR(EINVAL);
187+ }
188+
189+ if (vars_h[VAR_OUT_H] || vars_h[VAR_OH]) {
190+ av_log(ctx, AV_LOG_ERROR, "Height expression cannot be self-referencing: '%s'.\n", scale->h_expr);
191+ return AVERROR(EINVAL);
192+ }
193+
194+ if ((vars_w[VAR_OUT_H] || vars_w[VAR_OH]) &&
195+ (vars_h[VAR_OUT_W] || vars_h[VAR_OW])) {
196+ av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
197+ }
198+
199+ if (ctx->filter != &ff_vf_scale2ref_npp &&
200+ (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
201+ vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
202+ vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
203+ vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
204+ vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
205+ vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
206+ vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
207+ vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
208+ vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS])) {
209+ av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref_npp variables are not valid in scale_npp filter.\n");
210+ return AVERROR(EINVAL);
211+ }
212+
213+ if (scale->eval_mode == EVAL_MODE_INIT &&
214+ (vars_w[VAR_N] || vars_h[VAR_N] ||
215+ vars_w[VAR_T] || vars_h[VAR_T] ||
216+ vars_w[VAR_POS] || vars_h[VAR_POS] ||
217+ vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
218+ vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
219+ vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
220+ av_log(ctx, AV_LOG_ERROR, "Expressions with frame variables 'n', 't', 'pos' are not valid in init eval_mode.\n");
221+ return AVERROR(EINVAL);
222+ }
223+
224+ return 0;
225+}
226+
227+static int nppscale_parse_expr(AVFilterContext* ctx, char* str_expr,
228+ AVExpr** pexpr_ptr, const char* var,
229+ const char* args)
230+{
231+ NPPScaleContext* scale = ctx->priv;
232+ int ret, is_inited = 0;
233+ char* old_str_expr = NULL;
234+ AVExpr* old_pexpr = NULL;
235+
236+ if (str_expr) {
237+ old_str_expr = av_strdup(str_expr);
238+ if (!old_str_expr)
239+ return AVERROR(ENOMEM);
240+ av_opt_set(scale, var, args, 0);
241+ }
242+
243+ if (*pexpr_ptr) {
244+ old_pexpr = *pexpr_ptr;
245+ *pexpr_ptr = NULL;
246+ is_inited = 1;
247+ }
248+
249+ ret = av_expr_parse(pexpr_ptr, args, var_names, NULL, NULL, NULL, NULL, 0,
250+ ctx);
251+ if (ret < 0) {
252+ av_log(ctx, AV_LOG_ERROR, "Cannot parse expression for %s: '%s'\n", var,
253+ args);
254+ goto revert;
255+ }
256+
257+ ret = check_exprs(ctx);
258+ if (ret < 0)
259+ goto revert;
260+
261+ if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
262+ goto revert;
263+
264+ av_expr_free(old_pexpr);
265+ old_pexpr = NULL;
266+ av_freep(&old_str_expr);
267+
268+ return 0;
269+
270+revert:
271+ av_expr_free(*pexpr_ptr);
272+ *pexpr_ptr = NULL;
273+ if (old_str_expr) {
274+ av_opt_set(scale, var, old_str_expr, 0);
275+ av_free(old_str_expr);
276+ }
277+ if (old_pexpr)
278+ *pexpr_ptr = old_pexpr;
279+
280+ return ret;
281+}
282+
283+static av_cold int nppscale_init(AVFilterContext* ctx)
284+{
285+ NPPScaleContext* scale = ctx->priv;
286+ int i, ret;
111287
112− if (!strcmp(s->format_str, "same")) {
113− s->format = AV_PIX_FMT_NONE;
288+ if (!strcmp(scale->format_str, "same")) {
289+ scale->format = AV_PIX_FMT_NONE;
114290 } else {
115− s->format = av_get_pix_fmt(s->format_str);
116− if (s->format == AV_PIX_FMT_NONE) {
117− av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", s->format_str);
291+ scale->format = av_get_pix_fmt(scale->format_str);
292+ if (scale->format == AV_PIX_FMT_NONE) {
293+ av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", scale->format_str);
118294 return AVERROR(EINVAL);
119295 }
120296 }
121297
122− for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
123− s->stages[i].frame = av_frame_alloc();
124− if (!s->stages[i].frame)
298+ if (scale->size_str && (scale->w_expr || scale->h_expr)) {
299+ av_log(ctx, AV_LOG_ERROR,
300+ "Size and width/height exprs cannot be set at the same time.\n");
301+ return AVERROR(EINVAL);
302+ }
303+
304+ if (scale->w_expr && !scale->h_expr)
305+ FFSWAP(char*, scale->w_expr, scale->size_str);
306+
307+ if (scale->size_str) {
308+ char buf[32];
309+ ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str);
310+ if (0 > ret) {
311+ av_log(ctx, AV_LOG_ERROR, "Invalid size '%s'\n", scale->size_str);
312+ return ret;
313+ }
314+
315+ snprintf(buf, sizeof(buf) - 1, "%d", scale->w);
316+ ret = av_opt_set(scale, "w", buf, 0);
317+ if (ret < 0)
318+ return ret;
319+
320+ snprintf(buf, sizeof(buf) - 1, "%d", scale->h);
321+ ret = av_opt_set(scale, "h", buf, 0);
322+ if (ret < 0)
323+ return ret;
324+ }
325+
326+ if (!scale->w_expr) {
327+ ret = av_opt_set(scale, "w", "iw", 0);
328+ if (ret < 0)
329+ return ret;
330+ }
331+
332+ if (!scale->h_expr) {
333+ ret = av_opt_set(scale, "h", "ih", 0);
334+ if (ret < 0)
335+ return ret;
336+ }
337+
338+ ret = nppscale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
339+ if (ret < 0)
340+ return ret;
341+
342+ ret = nppscale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
343+ if (ret < 0)
344+ return ret;
345+
346+ for (i = 0; i < FF_ARRAY_ELEMS(scale->stages); i++) {
347+ scale->stages[i].frame = av_frame_alloc();
348+ if (!scale->stages[i].frame)
125349 return AVERROR(ENOMEM);
126350 }
127− s->tmp_frame = av_frame_alloc();
128− if (!s->tmp_frame)
351+ scale->tmp_frame = av_frame_alloc();
352+ if (!scale->tmp_frame)
129353 return AVERROR(ENOMEM);
130354
131355 return 0;
132356 }
133357
358+static int nppscale_eval_dimensions(AVFilterContext* ctx)
359+{
360+ NPPScaleContext* scale = ctx->priv;
361+ const char scale2ref = ctx->filter == &ff_vf_scale2ref_npp;
362+ const AVFilterLink* inlink = ctx->inputs[scale2ref ? 1 : 0];
363+ char* expr;
364+ int eval_w, eval_h;
365+ int ret;
366+ double res;
367+
368+ scale->var_values[VAR_IN_W] = scale->var_values[VAR_IW] = inlink->w;
369+ scale->var_values[VAR_IN_H] = scale->var_values[VAR_IH] = inlink->h;
370+ scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = NAN;
371+ scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = NAN;
372+ scale->var_values[VAR_A] = (double)inlink->w / inlink->h;
373+ scale->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
374+ (double)inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
375+ scale->var_values[VAR_DAR] = scale->var_values[VAR_A] * scale->var_values[VAR_SAR];
376+
377+ if (scale2ref) {
378+ const AVFilterLink* main_link = ctx->inputs[0];
379+
380+ scale->var_values[VAR_S2R_MAIN_W] = main_link->w;
381+ scale->var_values[VAR_S2R_MAIN_H] = main_link->h;
382+ scale->var_values[VAR_S2R_MAIN_A] = (double)main_link->w / main_link->h;
383+ scale->var_values[VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ?
384+ (double)main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1;
385+ scale->var_values[VAR_S2R_MAIN_DAR] = scale->var_values[VAR_S2R_MDAR] =
386+ scale->var_values[VAR_S2R_MAIN_A] * scale->var_values[VAR_S2R_MAIN_SAR];
387+ }
388+
389+ res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
390+ eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int)res == 0 ? inlink->w : (int)res;
391+
392+ res = av_expr_eval(scale->h_pexpr, scale->var_values, NULL);
393+ if (isnan(res)) {
394+ expr = scale->h_expr;
395+ ret = AVERROR(EINVAL);
396+ goto fail;
397+ }
398+ eval_h = scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = (int)res == 0 ? inlink->h : (int)res;
399+
400+ res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
401+ if (isnan(res)) {
402+ expr = scale->w_expr;
403+ ret = AVERROR(EINVAL);
404+ goto fail;
405+ }
406+ eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int)res == 0 ? inlink->w : (int)res;
407+
408+ scale->w = eval_w;
409+ scale->h = eval_h;
410+
411+ return 0;
412+
413+fail:
414+ av_log(ctx, AV_LOG_ERROR, "Error when evaluating the expression '%s'.\n",
415+ expr);
416+ return ret;
417+}
418+
134419 static void nppscale_uninit(AVFilterContext *ctx)
135420 {
136421 NPPScaleContext *s = ctx->priv;
@@ -141,6 +426,10 @@ static void nppscale_uninit(AVFilterContext *ctx) · 4 unmodified lines
141426 av_buffer_unref(&s->stages[i].frames_ctx);
142427 }
143428 av_frame_free(&s->tmp_frame);
429+
430+ av_expr_free(s->w_pexpr);
431+ av_expr_free(s->h_pexpr);
432+ s->w_pexpr = s->h_pexpr = NULL;
144433 }
145434
146435 static int init_stage(NPPScaleStageContext *stage, AVBufferRef *device_ctx)
@@ -164,6 +453,13 @@ static int init_stage(NPPScaleStageContext *stage, AVBufferRef *device_ctx) · 17 unmodified lines
164453 stage->planes_out[i].height = stage->planes_out[0].height >> out_sh;
165454 }
166455
456+ if (AV_PIX_FMT_YUVA420P == stage->in_fmt) {
457+ stage->planes_in[3].width = stage->planes_in[0].width;
458+ stage->planes_in[3].height = stage->planes_in[0].height;
459+ stage->planes_out[3].width = stage->planes_out[0].width;
460+ stage->planes_out[3].height = stage->planes_out[0].height;
461+ }
462+
167463 out_ref = av_hwframe_ctx_alloc(device_ctx);
168464 if (!out_ref)
169465 return AVERROR(ENOMEM);
@@ -326,31 +622,32 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig · 156 unmodified lines
326622 return 0;
327623 }
328624
329−static int nppscale_config_props(AVFilterLink *outlink)
625+static int config_props(AVFilterLink *outlink)
330626 {
331627 AVFilterContext *ctx = outlink->src;
332− AVFilterLink *inlink = outlink->src->inputs[0];
628+ AVFilterLink *inlink0 = outlink->src->inputs[0];
629+ AVFilterLink *inlink = ctx->filter == &ff_vf_scale2ref_npp ?
630+ outlink->src->inputs[1] :
631+ outlink->src->inputs[0];
333632 NPPScaleContext *s = ctx->priv;
334− int w, h;
335633 int ret;
336634
337− if ((ret = ff_scale_eval_dimensions(s,
338− s->w_expr, s->h_expr,
339− inlink, outlink,
340− &w, &h)) < 0)
635+ if ((ret = nppscale_eval_dimensions(ctx)) < 0)
341636 goto fail;
342637
343− ff_scale_adjust_dimensions(inlink, &w, &h,
344− s->force_original_aspect_ratio, s->force_divisible_by);
638+ ff_scale_adjust_dimensions(inlink, &s->w, &s->h,
639+ s->force_original_aspect_ratio,
640+ s->force_divisible_by);
345641
346− if (((int64_t)h * inlink->w) > INT_MAX ||
347− ((int64_t)w * inlink->h) > INT_MAX)
642+ if (s->w > INT_MAX || s->h > INT_MAX ||
643+ (s->h * inlink->w) > INT_MAX ||
644+ (s->w * inlink->h) > INT_MAX)
348645 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
349646
350− outlink->w = w;
351− outlink->h = h;
647+ outlink->w = s->w;
648+ outlink->h = s->h;
352649
353− ret = init_processing_chain(ctx, inlink->w, inlink->h, w, h);
650+ ret = init_processing_chain(ctx, inlink0->w, inlink0->h, outlink->w, outlink->h);
354651 if (ret < 0)
355652 return ret;
356653
@@ -370,6 +667,22 @@ fail: · 13 unmodified lines
370667 return ret;
371668 }
372669
670+static int config_props_ref(AVFilterLink *outlink)
671+{
672+ AVFilterLink *inlink = outlink->src->inputs[1];
673+ AVFilterContext *ctx = outlink->src;
674+
675+ outlink->w = inlink->w;
676+ outlink->h = inlink->h;
677+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
678+ outlink->time_base = inlink->time_base;
679+ outlink->frame_rate = inlink->frame_rate;
680+
681+ ctx->outputs[1]->hw_frames_ctx = av_buffer_ref(ctx->inputs[1]->hw_frames_ctx);
682+
683+ return 0;
684+}
685+
373686 static int nppscale_deinterleave(AVFilterContext *ctx, NPPScaleStageContext *stage,
374687 AVFrame *out, AVFrame *in)
375688 {
@@ -454,12 +767,71 @@ static int (*const nppscale_process[])(AVFilterContext *ctx, NPPScaleStageContex · 78 unmodified lines
454767 [STAGE_INTERLEAVE] = nppscale_interleave,
455768 };
456769
457−static int nppscale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in)
770+static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in)
458771 {
772+ AVFilterContext *ctx = link->dst;
459773 NPPScaleContext *s = ctx->priv;
774+ AVFilterLink *outlink = ctx->outputs[0];
460775 AVFrame *src = in;
776+ char buf[32];
461777 int i, ret, last_stage = -1;
778+ int frame_changed;
779+
780+ frame_changed = in->width != link->w ||
781+ in->height != link->h ||
782+ in->format != link->format ||
783+ in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
784+ in->sample_aspect_ratio.num != link->sample_aspect_ratio.num;
785+
786+ if (s->eval_mode == EVAL_MODE_FRAME || frame_changed) {
787+ unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
788+
789+ av_expr_count_vars(s->w_pexpr, vars_w, VARS_NB);
790+ av_expr_count_vars(s->h_pexpr, vars_h, VARS_NB);
791+
792+ if (s->eval_mode == EVAL_MODE_FRAME && !frame_changed && ctx->filter != &ff_vf_scale2ref_npp &&
793+ !(vars_w[VAR_N] || vars_w[VAR_T] || vars_w[VAR_POS]) &&
794+ !(vars_h[VAR_N] || vars_h[VAR_T] || vars_h[VAR_POS]) &&
795+ s->w && s->h)
796+ goto scale;
797+
798+ if (s->eval_mode == EVAL_MODE_INIT) {
799+ snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
800+ av_opt_set(s, "w", buf, 0);
801+ snprintf(buf, sizeof(buf)-1, "%d", outlink->h);
802+ av_opt_set(s, "h", buf, 0);
803+
804+ ret = nppscale_parse_expr(ctx, NULL, &s->w_pexpr, "width", s->w_expr);
805+ if (ret < 0)
806+ return ret;
807+
808+ ret = nppscale_parse_expr(ctx, NULL, &s->h_pexpr, "height", s->h_expr);
809+ if (ret < 0)
810+ return ret;
811+ }
812+
813+ if (ctx->filter == &ff_vf_scale2ref_npp) {
814+ s->var_values[VAR_S2R_MAIN_N] = link->frame_count_out;
815+ s->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
816+ s->var_values[VAR_S2R_MAIN_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
817+ } else {
818+ s->var_values[VAR_N] = link->frame_count_out;
819+ s->var_values[VAR_T] = TS2T(in->pts, link->time_base);
820+ s->var_values[VAR_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
821+ }
822+
823+ link->format = in->format;
824+ link->w = in->width;
825+ link->h = in->height;
826+
827+ link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
828+ link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
462829
830+ if ((ret = config_props(outlink)) < 0)
831+ return ret;
832+ }
833+
834+scale:
463835 for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) {
464836 if (!s->stages[i].stage_needed)
465837 continue;
@@ -516,7 +888,7 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in) · 50 unmodified lines
516888 if (ret < 0)
517889 goto fail;
518890
519− ret = nppscale_scale(ctx, out, in);
891+ ret = nppscale_scale(link, out, in);
520892
521893 CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy));
522894 if (ret < 0)
@@ -535,12 +907,54 @@ fail: · 12 unmodified lines
535907 return ret;
536908 }
537909
910+static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in)
911+{
912+ NPPScaleContext *scale = link->dst->priv;
913+ AVFilterLink *outlink = link->dst->outputs[1];
914+ int frame_changed;
915+
916+ frame_changed = in->width != link->w ||
917+ in->height != link->h ||
918+ in->format != link->format ||
919+ in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
920+ in->sample_aspect_ratio.num != link->sample_aspect_ratio.num;
921+
922+ if (frame_changed) {
923+ link->format = in->format;
924+ link->w = in->width;
925+ link->h = in->height;
926+ link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
927+ link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
928+
929+ config_props_ref(outlink);
930+ }
931+
932+ if (scale->eval_mode == EVAL_MODE_FRAME) {
933+ scale->var_values[VAR_N] = link->frame_count_out;
934+ scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
935+ scale->var_values[VAR_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
936+ }
937+
938+ return ff_filter_frame(outlink, in);
939+}
940+
941+static int request_frame(AVFilterLink *outlink)
942+{
943+ return ff_request_frame(outlink->src->inputs[0]);
944+}
945+
946+static int request_frame_ref(AVFilterLink *outlink)
947+{
948+ return ff_request_frame(outlink->src->inputs[1]);
949+}
950+
538951 #define OFFSET(x) offsetof(NPPScaleContext, x)
539952 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
540953 static const AVOption options[] = {
541− { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
542− { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
954+ { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
955+ { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
543956 { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS },
957+ { "s", "Output video size", OFFSET(size_str), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
544958
545959 { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = NPPI_INTER_CUBIC }, 0, INT_MAX, FLAGS, "interp_algo" },
546960 { "nn", "nearest neighbour", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_NN }, 0, 0, FLAGS, "interp_algo" },
@@ -551,11 +965,14 @@ static const AVOption options[] = { · 4 unmodified lines
551965 { "cubic2p_b05c03", "2-parameter cubic (B=1/2, C=3/10)", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_CUBIC2P_B05C03 }, 0, 0, FLAGS, "interp_algo" },
552966 { "super", "supersampling", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER }, 0, 0, FLAGS, "interp_algo" },
553967 { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LANCZOS }, 0, 0, FLAGS, "interp_algo" },
554− { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
968+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS, "force_oar" },
555969 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
556970 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
557971 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" },
558− { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
972+ { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS },
973+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, { .i64 = EVAL_MODE_INIT }, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
974+ { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_INIT }, 0, 0, FLAGS, "eval" },
975+ { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, { .i64 = EVAL_MODE_FRAME }, 0, 0, FLAGS, "eval" },
559976 { NULL },
560977 };
561978
@@ -564,6 +981,7 @@ static const AVClass nppscale_class = { · 2 unmodified lines
564981 .item_name = av_default_item_name,
565982 .option = options,
566983 .version = LIBAVUTIL_VERSION_INT,
984+ .category = AV_CLASS_CATEGORY_FILTER,
567985 };
568986
569987 static const AVFilterPad nppscale_inputs[] = {
@@ -571,15 +989,15 @@ static const AVFilterPad nppscale_inputs[] = { · 1 unmodified line
571989 .name = "default",
572990 .type = AVMEDIA_TYPE_VIDEO,
573991 .filter_frame = nppscale_filter_frame,
574− },
992+ }
575993 };
576994
577995 static const AVFilterPad nppscale_outputs[] = {
578996 {
579997 .name = "default",
580998 .type = AVMEDIA_TYPE_VIDEO,
581− .config_props = nppscale_config_props,
582− },
999+ .config_props = config_props,
1000+ }
5831001 };
5841002
5851003 const AVFilter ff_vf_scale_npp = {
@@ -600,3 +1018,51 @@ const AVFilter ff_vf_scale_npp = { · 14 unmodified lines
6001018
6011019 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
6021020 };
1021+
1022+static const AVFilterPad nppscale2ref_inputs[] = {
1023+ {
1024+ .name = "default",
1025+ .type = AVMEDIA_TYPE_VIDEO,
1026+ .filter_frame = nppscale_filter_frame,
1027+ },
1028+ {
1029+ .name = "ref",
1030+ .type = AVMEDIA_TYPE_VIDEO,
1031+ .filter_frame = nppscale_filter_frame_ref,
1032+ }
1033+};
1034+
1035+static const AVFilterPad nppscale2ref_outputs[] = {
1036+ {
1037+ .name = "default",
1038+ .type = AVMEDIA_TYPE_VIDEO,
1039+ .config_props = config_props,
1040+ .request_frame= request_frame,
1041+ },
1042+ {
1043+ .name = "ref",
1044+ .type = AVMEDIA_TYPE_VIDEO,
1045+ .config_props = config_props_ref,
1046+ .request_frame= request_frame_ref,
1047+ }
1048+};
1049+
1050+const AVFilter ff_vf_scale2ref_npp = {
1051+ .name = "scale2ref_npp",
1052+ .description = NULL_IF_CONFIG_SMALL("NVIDIA Performance Primitives video "
1053+ "scaling and format conversion to the "
1054+ "given reference."),
1055+
1056+ .init = nppscale_init,
1057+ .uninit = nppscale_uninit,
1058+
1059+ .priv_size = sizeof(NPPScaleContext),
1060+ .priv_class = &nppscale_class,
1061+
1062+ FILTER_INPUTS(nppscale2ref_inputs),
1063+ FILTER_OUTPUTS(nppscale2ref_outputs),
1064+
1065+ FILTER_SINGLE_PIXFMT(AV_PIX_FMT_CUDA),
1066+
1067+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
1068+};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t