From patchwork Sun Jan 8 12:58:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 39919 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:bc95:b0:ad:ade2:bfd2 with SMTP id fx21csp2423444pzb; Sun, 8 Jan 2023 04:59:15 -0800 (PST) X-Google-Smtp-Source: AMrXdXv1QbrHbBkGbPgdIIDg1fKMq2sfeUiCEnkY2oXXQoq0JuOk6gTl37UnmFMev9KhOPN71/GU X-Received: by 2002:a17:907:874c:b0:7fc:4242:f9ec with SMTP id qo12-20020a170907874c00b007fc4242f9ecmr51404484ejc.43.1673182754910; Sun, 08 Jan 2023 04:59:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1673182754; cv=none; d=google.com; s=arc-20160816; b=qLNpthqCj+JWJLop6mnguWqV151Cenvvu4/WJKHd49m0yhFprNeQ8Vp8iUtBiQ3mqk vFg48q2JnTha2HVvxnKC3h0wv1g8mj6yZk3HE6QVHPZxSerJ+V5X9hnW8si0li+rKKGX zlpucxlCoQltLsMl1CEVJSOWV5cmREefG4rtHR0p6rEMG5GEliDA2xm+ebYOjFp3Skk/ ZCfa81e+SggN4dwR1vbCfqyWgijr4qv286BhC5VLj7S1qYW2/B1Fpkh613uyDuJPSdoW lRjbRNLLDqtGjkRNTqqs90Fsth5HxICwgVphB/Bq1oXxvBkI3ysNRCrm82PE7ZhBpQlh c1gg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :delivered-to; bh=NrCcjwXeYkOnWvULDUahdbC0OA9Fx5++RhYcna5KOZg=; b=0VMy6+D/iD9EBY7L2VXWxKta/Qj4eKGYar9tqVfZGhSexnYhzHkJML11XLGsiZapbi 3rbHC6f3Xe5d1JmsutuySEQQn5W2bZhvhfOWZksgDQUlOEBPtEpnrI2wmDDwnJDyz7B0 7bsmedATTyUWbXYXcBSUA004HIHBClQFeSzUlGStnu4ns8tW7EgPWSfoDm4zJnaKoe4F JKZSOwhOD8ueHOLfjtwR/mp6kawucsHqtOG0QjlUTvfNJWm1mmP54cOPXT/z7Iy8ONoH EDQfDKuGjhAYLmb09YQhNFaesF9K/mXoerK4Pz77QccsIJhYnqRzAeGw03VvSlLGNqsH GooA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id dr6-20020a170907720600b0084d197a89e2si6222211ejc.957.2023.01.08.04.59.14; Sun, 08 Jan 2023 04:59:14 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2D91368BC2A; Sun, 8 Jan 2023 14:58:45 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8D83468B612 for ; Sun, 8 Jan 2023 14:58:36 +0200 (EET) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 4B4052400F5 for ; Sun, 8 Jan 2023 13:58:36 +0100 (CET) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id kcnK6jBK5BgJ for ; Sun, 8 Jan 2023 13:58:35 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail0.khirnov.net (Postfix) with ESMTPS id C02E32404F7 for ; Sun, 8 Jan 2023 13:58:33 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 486193A0101 for ; Sun, 8 Jan 2023 13:58:26 +0100 (CET) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Sun, 8 Jan 2023 13:58:04 +0100 Message-Id: <20230108125811.17967-1-anton@khirnov.net> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/8] lavfi/vf_scale: allow passing options to swscale directly X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: rRhgM4m5A3B2 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. --- libavfilter/vf_scale.c | 95 +++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index b95e2e6c66..85047e3524 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -23,6 +23,7 @@ * scale video filter */ +#include #include #include @@ -107,7 +108,8 @@ typedef struct ScaleContext { const AVClass *class; struct SwsContext *sws; ///< software scaler context struct SwsContext *isws[2]; ///< software scaler context for interlaced material - AVDictionary *opts; + // context used for forwarding options to sws + struct SwsContext *sws_opts; /** * New dimensions. Special values are: @@ -117,7 +119,6 @@ typedef struct ScaleContext { */ int w, h; char *size_str; - unsigned int flags; ///sws flags double param[2]; // sws params int hsub, vsub; ///< chroma subsampling @@ -268,11 +269,29 @@ revert: return ret; } -static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts) +static av_cold int preinit(AVFilterContext *ctx) { ScaleContext *scale = ctx->priv; int ret; + scale->sws_opts = sws_alloc_context(); + if (!scale->sws_opts) + return AVERROR(ENOMEM); + + // set threads=0, so we can later check whether the user modified it + ret = av_opt_set_int(scale->sws_opts, "threads", 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold int init(AVFilterContext *ctx) +{ + ScaleContext *scale = ctx->priv; + int64_t threads; + int ret; + if (scale->size_str && (scale->w_expr || scale->h_expr)) { av_log(ctx, AV_LOG_ERROR, "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) av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n", scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced); - scale->flags = 0; - if (scale->flags_str && *scale->flags_str) { - const AVClass *class = sws_get_class(); - const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0, - AV_OPT_SEARCH_FAKE_OBJ); - int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags); + ret = av_opt_set(scale->sws_opts, "sws_flags", scale->flags_str, 0); if (ret < 0) return ret; } - scale->opts = *opts; - *opts = NULL; + + for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++) + if (scale->param[i] != DBL_MAX) { + ret = av_opt_set_double(scale->sws_opts, i ? "param1" : "param0", + scale->param[i], 0); + if (ret < 0) + return ret; + } + + // use generic thread-count if the user did not set it explicitly + ret = av_opt_get_int(scale->sws_opts, "threads", 0, &threads); + if (ret < 0) + return ret; + if (!threads) + av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0); scale->in_frame_range = AVCOL_RANGE_UNSPECIFIED; @@ -334,11 +361,11 @@ static av_cold void uninit(AVFilterContext *ctx) av_expr_free(scale->w_pexpr); av_expr_free(scale->h_pexpr); scale->w_pexpr = scale->h_pexpr = NULL; + sws_freeContext(scale->sws_opts); sws_freeContext(scale->sws); sws_freeContext(scale->isws[0]); sws_freeContext(scale->isws[1]); scale->sws = NULL; - av_dict_free(&scale->opts); } static int query_formats(AVFilterContext *ctx) @@ -486,6 +513,7 @@ static int config_props(AVFilterLink *outlink) enum AVPixelFormat outfmt = outlink->format; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); ScaleContext *scale = ctx->priv; + uint8_t *flags_val = NULL; int ret; if ((ret = scale_eval_dimensions(ctx)) < 0) @@ -534,16 +562,16 @@ static int config_props(AVFilterLink *outlink) return AVERROR(ENOMEM); *swscs[i] = s; + ret = av_opt_copy(s, scale->sws_opts); + if (ret < 0) + return ret; + av_opt_set_int(s, "srcw", inlink0 ->w, 0); av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0); av_opt_set_int(s, "src_format", inlink0->format, 0); av_opt_set_int(s, "dstw", outlink->w, 0); av_opt_set_int(s, "dsth", outlink->h >> !!i, 0); av_opt_set_int(s, "dst_format", outfmt, 0); - av_opt_set_int(s, "sws_flags", scale->flags, 0); - av_opt_set_int(s, "param0", scale->param[0], 0); - av_opt_set_int(s, "param1", scale->param[1], 0); - av_opt_set_int(s, "threads", ff_filter_get_nb_threads(ctx), 0); if (scale->in_range != AVCOL_RANGE_UNSPECIFIED) av_opt_set_int(s, "src_range", scale->in_range == AVCOL_RANGE_JPEG, 0); @@ -554,13 +582,6 @@ static int config_props(AVFilterLink *outlink) av_opt_set_int(s, "dst_range", scale->out_range == AVCOL_RANGE_JPEG, 0); - if (scale->opts) { - const AVDictionaryEntry *e = NULL; - while ((e = av_dict_iterate(scale->opts, e))) { - if ((ret = av_opt_set(s, e->key, e->value, 0)) < 0) - return ret; - } - } /* Override YUV420P default settings to have the correct (MPEG-2) chroma positions * MPEG-2 chroma positions are used by convention * XXX: support other 4:2:0 pixel formats */ @@ -589,12 +610,17 @@ static int config_props(AVFilterLink *outlink) } else outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; - 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", + if (scale->sws) + av_opt_get(scale->sws, "sws_flags", 0, &flags_val); + + 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", inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format), inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format), outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, - scale->flags); + flags_val); + av_freep(&flags_val); + return 0; fail: @@ -927,6 +953,14 @@ static const AVClass *child_class_iterate(void **iter) return c; } +static void *child_next(void *obj, void *prev) +{ + ScaleContext *s = obj; + if (!prev) + return s->sws_opts; + return NULL; +} + #define OFFSET(x) offsetof(ScaleContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #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[] = { { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, { "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 }, - { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, - { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, FLAGS }, + { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, + { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" }, { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" }, { "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 = { .version = LIBAVUTIL_VERSION_INT, .category = AV_CLASS_CATEGORY_FILTER, .child_class_iterate = child_class_iterate, + .child_next = child_next, }; static const AVFilterPad avfilter_vf_scale_inputs[] = { @@ -1005,7 +1040,8 @@ static const AVFilterPad avfilter_vf_scale_outputs[] = { const AVFilter ff_vf_scale = { .name = "scale", .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."), - .init_dict = init_dict, + .preinit = preinit, + .init = init, .uninit = uninit, .priv_size = sizeof(ScaleContext), .priv_class = &scale_class, @@ -1046,7 +1082,8 @@ static const AVFilterPad avfilter_vf_scale2ref_outputs[] = { const AVFilter ff_vf_scale2ref = { .name = "scale2ref", .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."), - .init_dict = init_dict, + .preinit = preinit, + .init = init, .uninit = uninit, .priv_size = sizeof(ScaleContext), .priv_class = &scale_class,