Avoid using the dictionary mechanism, which is non-introspectable. As this is the only user of AVFilter.init_dict(), this callback can now be removed.
Unified · Split
| @@ -23,6 +23,7 @@ · 22 unmodified lines | ||
| 23 | 23 | * scale video filter |
| 24 | 24 | */ |
| 25 | 25 | |
| 26 | +#include <float.h> | |
| 26 | 27 | #include <stdio.h> |
| 27 | 28 | #include <string.h> |
| 28 | 29 | |
| @@ -107,7 +108,8 @@ typedef struct ScaleContext { · 78 unmodified lines | ||
| 107 | 108 | const AVClass *class; |
| 108 | 109 | struct SwsContext *sws; ///< software scaler context |
| 109 | 110 | struct SwsContext *isws[2]; ///< software scaler context for interlaced material |
| 110 | − AVDictionary *opts; | |
| 111 | + // context used for forwarding options to sws | |
| 112 | + struct SwsContext *sws_opts; | |
| 111 | 113 | |
| 112 | 114 | /** |
| 113 | 115 | * New dimensions. Special values are: |
| @@ -117,7 +119,6 @@ typedef struct ScaleContext { · 3 unmodified lines | ||
| 117 | 119 | */ |
| 118 | 120 | int w, h; |
| 119 | 121 | char *size_str; |
| 120 | − unsigned int flags; ///sws flags | |
| 121 | 122 | double param[2]; // sws params |
| 122 | 123 | |
| 123 | 124 | int hsub, vsub; ///< chroma subsampling |
| @@ -268,11 +269,29 @@ revert: · 144 unmodified lines | ||
| 268 | 269 | return ret; |
| 269 | 270 | } |
| 270 | 271 | |
| 271 | −static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts) | |
| 272 | +static av_cold int preinit(AVFilterContext *ctx) | |
| 272 | 273 | { |
| 273 | 274 | ScaleContext *scale = ctx->priv; |
| 274 | 275 | int ret; |
| 275 | 276 | |
| 277 | + scale->sws_opts = sws_alloc_context(); | |
| 278 | + if (!scale->sws_opts) | |
| 279 | + return AVERROR(ENOMEM); | |
| 280 | + | |
| 281 | + // set threads=0, so we can later check whether the user modified it | |
| 282 | + ret = av_opt_set_int(scale->sws_opts, "threads", 0, 0); | |
| 283 | + if (ret < 0) | |
| 284 | + return ret; | |
| 285 | + | |
| 286 | + return 0; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static av_cold int init(AVFilterContext *ctx) | |
| 290 | +{ | |
| 291 | + ScaleContext *scale = ctx->priv; | |
| 292 | + int64_t threads; | |
| 293 | + int ret; | |
| 294 | + | |
| 276 | 295 | if (scale->size_str && (scale->w_expr || scale->h_expr)) { |
| 277 | 296 | av_log(ctx, AV_LOG_ERROR, |
| 278 | 297 | "Size and width/height expressions cannot be set at the same time.\n"); |
| @@ -310,18 +329,26 @@ static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts) · 31 unmodified lines | ||
| 310 | 329 | av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n", |
| 311 | 330 | scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced); |
| 312 | 331 | |
| 313 | − scale->flags = 0; | |
| 314 | − | |
| 315 | 332 | if (scale->flags_str && *scale->flags_str) { |
| 316 | − const AVClass *class = sws_get_class(); | |
| 317 | − const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0, | |
| 318 | − AV_OPT_SEARCH_FAKE_OBJ); | |
| 319 | − int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags); | |
| 333 | + ret = av_opt_set(scale->sws_opts, "sws_flags", scale->flags_str, 0); | |
| 320 | 334 | if (ret < 0) |
| 321 | 335 | return ret; |
| 322 | 336 | } |
| 323 | − scale->opts = *opts; | |
| 324 | − *opts = NULL; | |
| 337 | + | |
| 338 | + for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++) | |
| 339 | + if (scale->param[i] != DBL_MAX) { | |
| 340 | + ret = av_opt_set_double(scale->sws_opts, i ? "param1" : "param0", | |
| 341 | + scale->param[i], 0); | |
| 342 | + if (ret < 0) | |
| 343 | + return ret; | |
| 344 | + } | |
| 345 | + | |
| 346 | + // use generic thread-count if the user did not set it explicitly | |
| 347 | + ret = av_opt_get_int(scale->sws_opts, "threads", 0, &threads); | |
| 348 | + if (ret < 0) | |
| 349 | + return ret; | |
| 350 | + if (!threads) | |
| 351 | + av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0); | |
| 325 | 352 | |
| 326 | 353 | scale->in_frame_range = AVCOL_RANGE_UNSPECIFIED; |
| 327 | 354 | |
| @@ -334,11 +361,11 @@ static av_cold void uninit(AVFilterContext *ctx) · 6 unmodified lines | ||
| 334 | 361 | av_expr_free(scale->w_pexpr); |
| 335 | 362 | av_expr_free(scale->h_pexpr); |
| 336 | 363 | scale->w_pexpr = scale->h_pexpr = NULL; |
| 364 | + sws_freeContext(scale->sws_opts); | |
| 337 | 365 | sws_freeContext(scale->sws); |
| 338 | 366 | sws_freeContext(scale->isws[0]); |
| 339 | 367 | sws_freeContext(scale->isws[1]); |
| 340 | 368 | scale->sws = NULL; |
| 341 | − av_dict_free(&scale->opts); | |
| 342 | 369 | } |
| 343 | 370 | |
| 344 | 371 | static int query_formats(AVFilterContext *ctx) |
| @@ -486,6 +513,7 @@ static int config_props(AVFilterLink *outlink) · 141 unmodified lines | ||
| 486 | 513 | enum AVPixelFormat outfmt = outlink->format; |
| 487 | 514 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
| 488 | 515 | ScaleContext *scale = ctx->priv; |
| 516 | + uint8_t *flags_val = NULL; | |
| 489 | 517 | int ret; |
| 490 | 518 | |
| 491 | 519 | if ((ret = scale_eval_dimensions(ctx)) < 0) |
| @@ -534,16 +562,16 @@ static int config_props(AVFilterLink *outlink) · 42 unmodified lines | ||
| 534 | 562 | return AVERROR(ENOMEM); |
| 535 | 563 | *swscs[i] = s; |
| 536 | 564 | |
| 565 | + ret = av_opt_copy(s, scale->sws_opts); | |
| 566 | + if (ret < 0) | |
| 567 | + return ret; | |
| 568 | + | |
| 537 | 569 | av_opt_set_int(s, "srcw", inlink0 ->w, 0); |
| 538 | 570 | av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0); |
| 539 | 571 | av_opt_set_int(s, "src_format", inlink0->format, 0); |
| 540 | 572 | av_opt_set_int(s, "dstw", outlink->w, 0); |
| 541 | 573 | av_opt_set_int(s, "dsth", outlink->h >> !!i, 0); |
| 542 | 574 | av_opt_set_int(s, "dst_format", outfmt, 0); |
| 543 | − av_opt_set_int(s, "sws_flags", scale->flags, 0); | |
| 544 | − av_opt_set_int(s, "param0", scale->param[0], 0); | |
| 545 | − av_opt_set_int(s, "param1", scale->param[1], 0); | |
| 546 | − av_opt_set_int(s, "threads", ff_filter_get_nb_threads(ctx), 0); | |
| 547 | 575 | if (scale->in_range != AVCOL_RANGE_UNSPECIFIED) |
| 548 | 576 | av_opt_set_int(s, "src_range", |
| 549 | 577 | scale->in_range == AVCOL_RANGE_JPEG, 0); |
| @@ -554,13 +582,6 @@ static int config_props(AVFilterLink *outlink) · 4 unmodified lines | ||
| 554 | 582 | av_opt_set_int(s, "dst_range", |
| 555 | 583 | scale->out_range == AVCOL_RANGE_JPEG, 0); |
| 556 | 584 | |
| 557 | − if (scale->opts) { | |
| 558 | − const AVDictionaryEntry *e = NULL; | |
| 559 | − while ((e = av_dict_iterate(scale->opts, e))) { | |
| 560 | − if ((ret = av_opt_set(s, e->key, e->value, 0)) < 0) | |
| 561 | − return ret; | |
| 562 | − } | |
| 563 | − } | |
| 564 | 585 | /* Override YUV420P default settings to have the correct (MPEG-2) chroma positions |
| 565 | 586 | * MPEG-2 chroma positions are used by convention |
| 566 | 587 | * XXX: support other 4:2:0 pixel formats */ |
| @@ -589,12 +610,17 @@ static int config_props(AVFilterLink *outlink) · 22 unmodified lines | ||
| 589 | 610 | } else |
| 590 | 611 | outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; |
| 591 | 612 | |
| 592 | − av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n", | |
| 613 | + if (scale->sws) | |
| 614 | + av_opt_get(scale->sws, "sws_flags", 0, &flags_val); | |
| 615 | + | |
| 616 | + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:%s\n", | |
| 593 | 617 | inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format), |
| 594 | 618 | inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, |
| 595 | 619 | outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format), |
| 596 | 620 | outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, |
| 597 | − scale->flags); | |
| 621 | + flags_val); | |
| 622 | + av_freep(&flags_val); | |
| 623 | + | |
| 598 | 624 | return 0; |
| 599 | 625 | |
| 600 | 626 | fail: |
| @@ -927,6 +953,14 @@ static const AVClass *child_class_iterate(void **iter) · 326 unmodified lines | ||
| 927 | 953 | return c; |
| 928 | 954 | } |
| 929 | 955 | |
| 956 | +static void *child_next(void *obj, void *prev) | |
| 957 | +{ | |
| 958 | + ScaleContext *s = obj; | |
| 959 | + if (!prev) | |
| 960 | + return s->sws_opts; | |
| 961 | + return NULL; | |
| 962 | +} | |
| 963 | + | |
| 930 | 964 | #define OFFSET(x) offsetof(ScaleContext, x) |
| 931 | 965 | #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
| 932 | 966 | #define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM |
| @@ -969,8 +1003,8 @@ static const AVOption scale_options[] = { · 36 unmodified lines | ||
| 969 | 1003 | { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, |
| 970 | 1004 | { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, |
| 971 | 1005 | { "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 | − { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, | |
| 973 | − { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, | |
| 1006 | + { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, | |
| 1007 | + { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, | |
| 974 | 1008 | { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" }, |
| 975 | 1009 | { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" }, |
| 976 | 1010 | { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" }, |
| @@ -984,6 +1018,7 @@ static const AVClass scale_class = { · 7 unmodified lines | ||
| 984 | 1018 | .version = LIBAVUTIL_VERSION_INT, |
| 985 | 1019 | .category = AV_CLASS_CATEGORY_FILTER, |
| 986 | 1020 | .child_class_iterate = child_class_iterate, |
| 1021 | + .child_next = child_next, | |
| 987 | 1022 | }; |
| 988 | 1023 | |
| 989 | 1024 | static const AVFilterPad avfilter_vf_scale_inputs[] = { |
| @@ -1005,7 +1040,8 @@ static const AVFilterPad avfilter_vf_scale_outputs[] = { · 15 unmodified lines | ||
| 1005 | 1040 | const AVFilter ff_vf_scale = { |
| 1006 | 1041 | .name = "scale", |
| 1007 | 1042 | .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."), |
| 1008 | − .init_dict = init_dict, | |
| 1043 | + .preinit = preinit, | |
| 1044 | + .init = init, | |
| 1009 | 1045 | .uninit = uninit, |
| 1010 | 1046 | .priv_size = sizeof(ScaleContext), |
| 1011 | 1047 | .priv_class = &scale_class, |
| @@ -1046,7 +1082,8 @@ static const AVFilterPad avfilter_vf_scale2ref_outputs[] = { · 34 unmodified lines | ||
| 1046 | 1082 | const AVFilter ff_vf_scale2ref = { |
| 1047 | 1083 | .name = "scale2ref", |
| 1048 | 1084 | .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."), |
| 1049 | − .init_dict = init_dict, | |
| 1085 | + .preinit = preinit, | |
| 1086 | + .init = init, | |
| 1050 | 1087 | .uninit = uninit, |
| 1051 | 1088 | .priv_size = sizeof(ScaleContext), |
| 1052 | 1089 | .priv_class = &scale_class, |