| @@ -25,13 +25,13 @@ · 24 unmodified lines |
| 25 | #include <stdio.h> | 25 | #include <stdio.h> |
| 26 | #include <string.h> | 26 | #include <string.h> |
| 27 | | 27 | |
| 28 | #include "libavutil/avstring.h" | | |
| 29 | #include "libavutil/common.h" | | |
| 30 | #include "libavutil/hwcontext.h" | 28 | #include "libavutil/hwcontext.h" |
| 31 | #include "libavutil/hwcontext_cuda_internal.h" | 29 | #include "libavutil/hwcontext_cuda_internal.h" |
| 32 | #include "libavutil/cuda_check.h" | 30 | #include "libavutil/cuda_check.h" |
| 33 | #include "libavutil/internal.h" | 31 | #include "libavutil/internal.h" |
| 34 | #include "libavutil/opt.h" | 32 | #include "libavutil/opt.h" |
| | 33 | #include "libavutil/parseutils.h" |
| | 34 | #include "libavutil/eval.h" |
| 35 | #include "libavutil/pixdesc.h" | 35 | #include "libavutil/pixdesc.h" |
| 36 | | 36 | |
| 37 | #include "avfilter.h" | 37 | #include "avfilter.h" |
| @@ -44,6 +44,7 @@ · 6 unmodified lines |
| 44 | | 44 | |
| 45 | static const enum AVPixelFormat supported_formats[] = { | 45 | static const enum AVPixelFormat supported_formats[] = { |
| 46 | AV_PIX_FMT_YUV420P, | 46 | AV_PIX_FMT_YUV420P, |
| | 47 | AV_PIX_FMT_YUVA420P, |
| 47 | AV_PIX_FMT_NV12, | 48 | AV_PIX_FMT_NV12, |
| 48 | AV_PIX_FMT_YUV444P, | 49 | AV_PIX_FMT_YUV444P, |
| 49 | }; | 50 | }; |
| @@ -67,12 +68,62 @@ typedef struct NPPScaleStageContext { · 17 unmodified lines |
| 67 | struct { | 68 | struct { |
| 68 | int width; | 69 | int width; |
| 69 | int height; | 70 | int height; |
| 70 | } planes_in[3], planes_out[3]; | 71 | } planes_in[4], planes_out[4]; |
| 71 | | 72 | |
| 72 | AVBufferRef *frames_ctx; | 73 | AVBufferRef *frames_ctx; |
| 73 | AVFrame *frame; | 74 | AVFrame *frame; |
| 74 | } NPPScaleStageContext; | 75 | } NPPScaleStageContext; |
| 75 | | 76 | |
| | 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 | |
| 76 | typedef struct NPPScaleContext { | 127 | typedef struct NPPScaleContext { |
| 77 | const AVClass *class; | 128 | const AVClass *class; |
| 78 | | 129 | |
| @@ -102,35 +153,269 @@ typedef struct NPPScaleContext { · 23 unmodified lines |
| 102 | int force_divisible_by; | 153 | int force_divisible_by; |
| 103 | | 154 | |
| 104 | int interp_algo; | 155 | 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; |
| 105 | } NPPScaleContext; | 165 | } NPPScaleContext; |
| 106 | | 166 | |
| 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) |
| 108 | { | 172 | { |
| 109 | NPPScaleContext *s = ctx->priv; | 173 | NPPScaleContext* scale = ctx->priv; |
| 110 | int i; | 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; |
| 111 | | 287 | |
| 112 | if (!strcmp(s->format_str, "same")) { | 288 | if (!strcmp(scale->format_str, "same")) { |
| 113 | s->format = AV_PIX_FMT_NONE; | 289 | scale->format = AV_PIX_FMT_NONE; |
| 114 | } else { | 290 | } else { |
| 115 | s->format = av_get_pix_fmt(s->format_str); | 291 | scale->format = av_get_pix_fmt(scale->format_str); |
| 116 | if (s->format == AV_PIX_FMT_NONE) { | 292 | if (scale->format == AV_PIX_FMT_NONE) { |
| 117 | av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", s->format_str); | 293 | av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", scale->format_str); |
| 118 | return AVERROR(EINVAL); | 294 | return AVERROR(EINVAL); |
| 119 | } | 295 | } |
| 120 | } | 296 | } |
| 121 | | 297 | |
| 122 | for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { | 298 | if (scale->size_str && (scale->w_expr || scale->h_expr)) { |
| 123 | s->stages[i].frame = av_frame_alloc(); | 299 | av_log(ctx, AV_LOG_ERROR, |
| 124 | if (!s->stages[i].frame) | 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) |
| 125 | return AVERROR(ENOMEM); | 349 | return AVERROR(ENOMEM); |
| 126 | } | 350 | } |
| 127 | s->tmp_frame = av_frame_alloc(); | 351 | scale->tmp_frame = av_frame_alloc(); |
| 128 | if (!s->tmp_frame) | 352 | if (!scale->tmp_frame) |
| 129 | return AVERROR(ENOMEM); | 353 | return AVERROR(ENOMEM); |
| 130 | | 354 | |
| 131 | return 0; | 355 | return 0; |
| 132 | } | 356 | } |
| 133 | | 357 | |
| | 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 | |
| 134 | static void nppscale_uninit(AVFilterContext *ctx) | 419 | static void nppscale_uninit(AVFilterContext *ctx) |
| 135 | { | 420 | { |
| 136 | NPPScaleContext *s = ctx->priv; | 421 | NPPScaleContext *s = ctx->priv; |
| @@ -141,6 +426,10 @@ static void nppscale_uninit(AVFilterContext *ctx) · 4 unmodified lines |
| 141 | av_buffer_unref(&s->stages[i].frames_ctx); | 426 | av_buffer_unref(&s->stages[i].frames_ctx); |
| 142 | } | 427 | } |
| 143 | av_frame_free(&s->tmp_frame); | 428 | 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; |
| 144 | } | 433 | } |
| 145 | | 434 | |
| 146 | static int init_stage(NPPScaleStageContext *stage, AVBufferRef *device_ctx) | 435 | 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 |
| 164 | stage->planes_out[i].height = stage->planes_out[0].height >> out_sh; | 453 | stage->planes_out[i].height = stage->planes_out[0].height >> out_sh; |
| 165 | } | 454 | } |
| 166 | | 455 | |
| | 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 | |
| 167 | out_ref = av_hwframe_ctx_alloc(device_ctx); | 463 | out_ref = av_hwframe_ctx_alloc(device_ctx); |
| 168 | if (!out_ref) | 464 | if (!out_ref) |
| 169 | return AVERROR(ENOMEM); | 465 | return AVERROR(ENOMEM); |
| @@ -326,31 +622,32 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig · 156 unmodified lines |
| 326 | return 0; | 622 | return 0; |
| 327 | } | 623 | } |
| 328 | | 624 | |
| 329 | static int nppscale_config_props(AVFilterLink *outlink) | 625 | static int config_props(AVFilterLink *outlink) |
| 330 | { | 626 | { |
| 331 | AVFilterContext *ctx = outlink->src; | 627 | 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]; |
| 333 | NPPScaleContext *s = ctx->priv; | 632 | NPPScaleContext *s = ctx->priv; |
| 334 | int w, h; | | |
| 335 | int ret; | 633 | int ret; |
| 336 | | 634 | |
| 337 | if ((ret = ff_scale_eval_dimensions(s, | 635 | if ((ret = nppscale_eval_dimensions(ctx)) < 0) |
| 338 | s->w_expr, s->h_expr, | | |
| 339 | inlink, outlink, | | |
| 340 | &w, &h)) < 0) | | |
| 341 | goto fail; | 636 | goto fail; |
| 342 | | 637 | |
| 343 | ff_scale_adjust_dimensions(inlink, &w, &h, | 638 | ff_scale_adjust_dimensions(inlink, &s->w, &s->h, |
| 344 | s->force_original_aspect_ratio, s->force_divisible_by); | 639 | s->force_original_aspect_ratio, |
| | 640 | s->force_divisible_by); |
| 345 | | 641 | |
| 346 | if (((int64_t)h * inlink->w) > INT_MAX || | 642 | if (s->w > INT_MAX || s->h > INT_MAX || |
| 347 | ((int64_t)w * inlink->h) > INT_MAX) | 643 | (s->h * inlink->w) > INT_MAX || |
| | 644 | (s->w * inlink->h) > INT_MAX) |
| 348 | av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n"); | 645 | av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n"); |
| 349 | | 646 | |
| 350 | outlink->w = w; | 647 | outlink->w = s->w; |
| 351 | outlink->h = h; | 648 | outlink->h = s->h; |
| 352 | | 649 | |
| 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); |
| 354 | if (ret < 0) | 651 | if (ret < 0) |
| 355 | return ret; | 652 | return ret; |
| 356 | | 653 | |
| @@ -370,6 +667,22 @@ fail: · 13 unmodified lines |
| 370 | return ret; | 667 | return ret; |
| 371 | } | 668 | } |
| 372 | | 669 | |
| | 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 | |
| 373 | static int nppscale_deinterleave(AVFilterContext *ctx, NPPScaleStageContext *stage, | 686 | static int nppscale_deinterleave(AVFilterContext *ctx, NPPScaleStageContext *stage, |
| 374 | AVFrame *out, AVFrame *in) | 687 | AVFrame *out, AVFrame *in) |
| 375 | { | 688 | { |
| @@ -454,12 +767,71 @@ static int (*const nppscale_process[])(AVFilterContext *ctx, NPPScaleStageContex · 78 unmodified lines |
| 454 | [STAGE_INTERLEAVE] = nppscale_interleave, | 767 | [STAGE_INTERLEAVE] = nppscale_interleave, |
| 455 | }; | 768 | }; |
| 456 | | 769 | |
| 457 | static int nppscale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in) | 770 | static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in) |
| 458 | { | 771 | { |
| | 772 | AVFilterContext *ctx = link->dst; |
| 459 | NPPScaleContext *s = ctx->priv; | 773 | NPPScaleContext *s = ctx->priv; |
| | 774 | AVFilterLink *outlink = ctx->outputs[0]; |
| 460 | AVFrame *src = in; | 775 | AVFrame *src = in; |
| | 776 | char buf[32]; |
| 461 | int i, ret, last_stage = -1; | 777 | 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; |
| 462 | | 829 | |
| | 830 | if ((ret = config_props(outlink)) < 0) |
| | 831 | return ret; |
| | 832 | } |
| | 833 | |
| | 834 | scale: |
| 463 | for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { | 835 | for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { |
| 464 | if (!s->stages[i].stage_needed) | 836 | if (!s->stages[i].stage_needed) |
| 465 | continue; | 837 | continue; |
| @@ -516,7 +888,7 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in) · 50 unmodified lines |
| 516 | if (ret < 0) | 888 | if (ret < 0) |
| 517 | goto fail; | 889 | goto fail; |
| 518 | | 890 | |
| 519 | ret = nppscale_scale(ctx, out, in); | 891 | ret = nppscale_scale(link, out, in); |
| 520 | | 892 | |
| 521 | CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); | 893 | CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); |
| 522 | if (ret < 0) | 894 | if (ret < 0) |
| @@ -535,12 +907,54 @@ fail: · 12 unmodified lines |
| 535 | return ret; | 907 | return ret; |
| 536 | } | 908 | } |
| 537 | | 909 | |
| | 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 | |
| 538 | #define OFFSET(x) offsetof(NPPScaleContext, x) | 951 | #define OFFSET(x) offsetof(NPPScaleContext, x) |
| 539 | #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) | 952 | #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) |
| 540 | static const AVOption options[] = { | 953 | static const AVOption options[] = { |
| 541 | { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS }, | 954 | { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = FLAGS }, |
| 542 | { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS }, | 955 | { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = FLAGS }, |
| 543 | { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS }, | 956 | { "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 }, |
| 544 | | 958 | |
| 545 | { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = NPPI_INTER_CUBIC }, 0, INT_MAX, FLAGS, "interp_algo" }, | 959 | { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = NPPI_INTER_CUBIC }, 0, INT_MAX, FLAGS, "interp_algo" }, |
| 546 | { "nn", "nearest neighbour", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_NN }, 0, 0, FLAGS, "interp_algo" }, | 960 | { "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 |
| 551 | { "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" }, | 965 | { "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" }, |
| 552 | { "super", "supersampling", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER }, 0, 0, FLAGS, "interp_algo" }, | 966 | { "super", "supersampling", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_SUPER }, 0, 0, FLAGS, "interp_algo" }, |
| 553 | { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = NPPI_INTER_LANCZOS }, 0, 0, FLAGS, "interp_algo" }, | 967 | { "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" }, |
| 555 | { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" }, | 969 | { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" }, |
| 556 | { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, | 970 | { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, |
| 557 | { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, | 971 | { "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" }, |
| 559 | { NULL }, | 976 | { NULL }, |
| 560 | }; | 977 | }; |
| 561 | | 978 | |
| @@ -564,6 +981,7 @@ static const AVClass nppscale_class = { · 2 unmodified lines |
| 564 | .item_name = av_default_item_name, | 981 | .item_name = av_default_item_name, |
| 565 | .option = options, | 982 | .option = options, |
| 566 | .version = LIBAVUTIL_VERSION_INT, | 983 | .version = LIBAVUTIL_VERSION_INT, |
| | 984 | .category = AV_CLASS_CATEGORY_FILTER, |
| 567 | }; | 985 | }; |
| 568 | | 986 | |
| 569 | static const AVFilterPad nppscale_inputs[] = { | 987 | static const AVFilterPad nppscale_inputs[] = { |
| @@ -571,15 +989,15 @@ static const AVFilterPad nppscale_inputs[] = { · 1 unmodified line |
| 571 | .name = "default", | 989 | .name = "default", |
| 572 | .type = AVMEDIA_TYPE_VIDEO, | 990 | .type = AVMEDIA_TYPE_VIDEO, |
| 573 | .filter_frame = nppscale_filter_frame, | 991 | .filter_frame = nppscale_filter_frame, |
| 574 | }, | 992 | } |
| 575 | }; | 993 | }; |
| 576 | | 994 | |
| 577 | static const AVFilterPad nppscale_outputs[] = { | 995 | static const AVFilterPad nppscale_outputs[] = { |
| 578 | { | 996 | { |
| 579 | .name = "default", | 997 | .name = "default", |
| 580 | .type = AVMEDIA_TYPE_VIDEO, | 998 | .type = AVMEDIA_TYPE_VIDEO, |
| 581 | .config_props = nppscale_config_props, | 999 | .config_props = config_props, |
| 582 | }, | 1000 | } |
| 583 | }; | 1001 | }; |
| 584 | | 1002 | |
| 585 | const AVFilter ff_vf_scale_npp = { | 1003 | const AVFilter ff_vf_scale_npp = { |
| @@ -600,3 +1018,51 @@ const AVFilter ff_vf_scale_npp = { · 14 unmodified lines |
| 600 | | 1018 | |
| 601 | .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, | 1019 | .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, |
| 602 | }; | 1020 | }; |
| | 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 | }; |