From patchwork Thu Oct 24 10:25:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 52467 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:612c:1c41:b0:48e:c0f8:d0de with SMTP id im1csp231308vqb; Thu, 24 Oct 2024 03:28:58 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXzw77HCZB1KAeNVUu1dwMkWWG0PWvTXJIJnZ9W9Ptmq8s82czb6O/UgYvSMnwy4uBoD+i5x8wvySEmWVD/HjIp@gmail.com X-Google-Smtp-Source: AGHT+IGoSbSpHpoDf7gDJjUO81Ly1HUhlw6TXfIlS4LCg46Zw/0CXrR8K/efeHDcQ4LhioJjYoo4 X-Received: by 2002:a17:907:9620:b0:a9a:825:4c46 with SMTP id a640c23a62f3a-a9ad275d4d7mr131200666b.28.1729765738300; Thu, 24 Oct 2024 03:28:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1729765738; cv=none; d=google.com; s=arc-20240605; b=T0Q3FD1sbMFGwA0QLQCIcFMDRu+IHDNCBVtdqRBI1XptReidLVJo1ePytOAKStY+qx TFOPz+Kjq4RN/mYvJebMJPpngmVsGRPOuhHo9/oHA/21ioKtWsztVk9AIxL8/YU0WpMS ratcHjZtMbRgoHYMKzhRQxfgEzJ4DBGn2VC/VwAZBF57VaXxXw0T311m25Q6tjF9/wHl noVQ9pDoe6uBPmApMbh4+gGuDyDEK50iu6VPc6oBUliWiPgGf5rw2w0wGE6sPhYZ04+C WKQzieQ/1hhS8gAJeAfbONHc6K5AqM6rVr/43eRsB8BhvTaIA8zaCwDL3nIHXfrqgMpl RPig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=rWzhvR8NVZ/x1IW4zEHNTLzWIWdbbC8Nzt98yomFj9Q=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=NR/xp6Kq2kZiwn+U3T1WYmZknb06FQgVARGkqTSPvBo3mvbzzkP853BPYmALFnbmse jcIbsQdWHg+Bs/o8fmObLH6j5hZ8zPcqRojtH2mywqe3bErdeSyXCR7jins6ZD6x2Wot csVYL3qCJVW5dVmH2sdlCoF5bq5vY44WMiBOzuEI0PjDB8ReSfOhT4RNW4ipy0G87Fuv W10Vhg0gHKEdaP4B5OoBeiKXXNMC0fkxM3VpRnqMbn+T3y0OdEcVfwseZBwxY1D/8nXb LhCDupmcarvOPtMk0hnqc3H0Ez6Oqzqf5pOmvO123M24IUpRbDFm8uVODNzNLrrl9lAL p7Jw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=bfBgYYO9; 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 a640c23a62f3a-a9a9134deaesi739613266b.690.2024.10.24.03.28.57; Thu, 24 Oct 2024 03:28:58 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=bfBgYYO9; 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 235FA68DDC4; Thu, 24 Oct 2024 13:27:59 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E9AA868DCFC for ; Thu, 24 Oct 2024 13:27:47 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1729765663; bh=R+nSP+8+5TtgxWe6jcYuoOEUKHFE6P1p5tMIgd3B6Ek=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bfBgYYO9wrjXXuAHrLECNfbAi2Gc4OXOncwi+zVimaPOo7EsjtmDFXGfVIQnH7OT9 E9CRxQu2mmw3+NGjdsfewjaBkht4UhkyUT6FXw12rX4rCIT8iY/FUFE+ZItEoYvP8U e29k/OYmAptbRi3UyklLzgIdksv3sz9N+yz5iWCU= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 6BC1B481BF; Thu, 24 Oct 2024 12:27:43 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Thu, 24 Oct 2024 12:25:15 +0200 Message-ID: <20241024102737.792421-6-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.46.1 In-Reply-To: <20241024102737.792421-1-ffmpeg@haasn.xyz> References: <20241024102737.792421-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v4 05/13] swscale: expose SwsContext publicly 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: r0i24dN/XRqh From: Niklas Haas Following in the footsteps of the work in the previous commit, it's now relatively straightforward to expose the options struct publicly as SwsContext. This is a step towards making this more user friendly, as well as following API conventions established elsewhere. Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas --- libswscale/swscale.h | 93 +++++++++++++++++++++++-- libswscale/swscale_internal.h | 45 +------------ libswscale/utils.c | 123 +++++++++++++++------------------- 3 files changed, 144 insertions(+), 117 deletions(-) diff --git a/libswscale/swscale.h b/libswscale/swscale.h index 50c705ae06..4baef532b6 100644 --- a/libswscale/swscale.h +++ b/libswscale/swscale.h @@ -42,8 +42,6 @@ #include "version.h" #endif -typedef struct SwsContext SwsContext; - /** * @defgroup libsws libswscale * Color conversion and scaling library. @@ -65,17 +63,98 @@ const char *swscale_configuration(void); const char *swscale_license(void); /** - * Get the AVClass for swsContext. It can be used in combination with + * Get the AVClass for SwsContext. It can be used in combination with * AV_OPT_SEARCH_FAKE_OBJ for examining options. * * @see av_opt_find(). */ const AVClass *sws_get_class(void); -/** - * Allocate an empty SwsContext. This must be filled and passed to - * sws_init_context(). For filling see AVOptions, options.c and - * sws_setColorspaceDetails(). +/****************************** + * Flags and quality settings * + ******************************/ + +typedef enum SwsDither { + SWS_DITHER_NONE = 0, /* disable dithering */ + SWS_DITHER_AUTO, /* auto-select from preset */ + SWS_DITHER_BAYER, /* ordered dither matrix */ + SWS_DITHER_ED, /* error diffusion */ + SWS_DITHER_A_DITHER, /* arithmetic addition */ + SWS_DITHER_X_DITHER, /* arithmetic xor */ + SWS_DITHER_NB, /* not part of the ABI */ +} SwsDither; + +typedef enum SwsAlphaBlend { + SWS_ALPHA_BLEND_NONE = 0, + SWS_ALPHA_BLEND_UNIFORM, + SWS_ALPHA_BLEND_CHECKERBOARD, + SWS_ALPHA_BLEND_NB, /* not part of the ABI */ +} SwsAlphaBlend; + +/*********************************** + * Context creation and management * + ***********************************/ + +/** + * Main external API structure. New fields can be added to the end with + * minor version bumps. Removal, reordering and changes to existing fields + * require a major version bump. sizeof(SwsContext) is not part of the ABI. + */ +typedef struct SwsContext { + const AVClass *av_class; + + /** + * Private data of the user, can be used to carry app specific stuff. + */ + void *opaque; + + /** + * Bitmask of SWS_*. + */ + unsigned flags; + + /** + * Extra parameters for fine-tuning certain scalers. + */ + double scaler_params[2]; + + /** + * How many threads to use for processing, or 0 for automatic selection. + */ + int threads; + + /** + * Dither mode. + */ + SwsDither dither; + + /** + * Alpha blending mode. See `SwsAlphaBlend` for details. + */ + SwsAlphaBlend alpha_blend; + + /** + * Use gamma correct scaling. + */ + int gamma_flag; + + /** + * Frame property overrides. + */ + int src_w, src_h; ///< Width and height of the source frame + int dst_w, dst_h; ///< Width and height of the destination frame + int src_format; ///< Source pixel format + int dst_format; ///< Destination pixel format + int src_range; ///< Source is full range + int dst_range; ///< Destination is full range + int src_v_chr_pos; ///< Source vertical chroma position in luma grid / 256 + int src_h_chr_pos; ///< Source horizontal chroma position + int dst_v_chr_pos; ///< Destination vertical chroma position + int dst_h_chr_pos; ///< Destination horizontal chroma position +} SwsContext; + +/** + * Allocate an empty SwsContext and set its fields to default values. */ SwsContext *sws_alloc_context(void); diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index d459b79af3..12fa406e2c 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -73,23 +73,6 @@ static inline SwsInternal *sws_internal(const SwsContext *sws) return (SwsInternal *) sws; } -typedef enum SwsDither { - SWS_DITHER_NONE = 0, - SWS_DITHER_AUTO, - SWS_DITHER_BAYER, - SWS_DITHER_ED, - SWS_DITHER_A_DITHER, - SWS_DITHER_X_DITHER, - SWS_DITHER_NB, -} SwsDither; - -typedef enum SwsAlphaBlend { - SWS_ALPHA_BLEND_NONE = 0, - SWS_ALPHA_BLEND_UNIFORM, - SWS_ALPHA_BLEND_CHECKERBOARD, - SWS_ALPHA_BLEND_NB, -} SwsAlphaBlend; - typedef struct Range { unsigned int start; unsigned int len; @@ -329,32 +312,10 @@ struct SwsFilterDescriptor; /* This struct should be aligned on at least a 32-byte boundary. */ struct SwsInternal { - /* Currently active user-facing options. */ - struct { - const AVClass *av_class; - - double scaler_params[2]; ///< Input parameters for scaling algorithms that need them. - int flags; ///< Flags passed by the user to select scaler algorithm, optimizations, subsampling, etc... - int threads; ///< Number of threads used for scaling - - int src_w; ///< Width of source luma/alpha planes. - int src_h; ///< Height of source luma/alpha planes. - int dst_w; ///< Width of destination luma/alpha planes. - int dst_h; ///< Height of destination luma/alpha planes. - enum AVPixelFormat src_format; ///< Source pixel format. - enum AVPixelFormat dst_format; ///< Destination pixel format. - int src_range; ///< 0 = MPG YUV range, 1 = JPG YUV range (source image). - int dst_range; ///< 0 = MPG YUV range, 1 = JPG YUV range (destination image). - int src_h_chr_pos; - int dst_h_chr_pos; - int src_v_chr_pos; - int dst_v_chr_pos; - int gamma_flag; - - SwsDither dither; - SwsAlphaBlend alpha_blend; - } opts; + /* Currently active user-facing options. Also contains AVClass */ + SwsContext opts; + /* Parent context (for slice contexts) */ SwsContext *parent; AVSliceThread *slicethread; diff --git a/libswscale/utils.c b/libswscale/utils.c index 4bddcb43d8..aee1153d4e 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -291,22 +291,20 @@ static SwsContext *alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcForm int flags, const double *param) { SwsContext *sws = sws_alloc_context(); - SwsInternal *c = sws_internal(sws); - - if (!c) + if (!sws) return NULL; - c->opts.flags = flags; - c->opts.src_w = srcW; - c->opts.src_h = srcH; - c->opts.dst_w = dstW; - c->opts.dst_h = dstH; - c->opts.src_format = srcFormat; - c->opts.dst_format = dstFormat; + sws->flags = flags; + sws->src_w = srcW; + sws->src_h = srcH; + sws->dst_w = dstW; + sws->dst_h = dstH; + sws->src_format = srcFormat; + sws->dst_format = dstFormat; if (param) { - c->opts.scaler_params[0] = param[0]; - c->opts.scaler_params[1] = param[1]; + sws->scaler_params[0] = param[0]; + sws->scaler_params[1] = param[1]; } return sws; @@ -1234,16 +1232,16 @@ int sws_getColorspaceDetails(SwsContext *sws, int **inv_table, SwsContext *sws_alloc_context(void) { - SwsInternal *c = av_mallocz(sizeof(SwsInternal)); + SwsInternal *c = (SwsInternal *) av_mallocz(sizeof(SwsInternal)); + if (!c) + return NULL; - if (c) { - c->opts.av_class = &ff_sws_context_class; - av_opt_set_defaults(c); - atomic_init(&c->stride_unaligned_warned, 0); - atomic_init(&c->data_unaligned_warned, 0); - } + c->opts.av_class = &ff_sws_context_class; + av_opt_set_defaults(c); + atomic_init(&c->stride_unaligned_warned, 0); + atomic_init(&c->data_unaligned_warned, 0); - return (SwsContext *) c; + return &c->opts; } static uint16_t * alloc_gamma_tbl(double e) @@ -2527,7 +2525,7 @@ void sws_freeContext(SwsContext *sws) ff_free_filters(c); - av_free(sws); + av_free(c); } void sws_free_context(SwsContext **pctx) @@ -2540,7 +2538,7 @@ void sws_free_context(SwsContext **pctx) *pctx = NULL; } -SwsContext *sws_getCachedContext(SwsContext *sws, int srcW, +SwsContext *sws_getCachedContext(SwsContext *prev, int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, @@ -2548,59 +2546,48 @@ SwsContext *sws_getCachedContext(SwsContext *sws, int srcW, SwsFilter *dstFilter, const double *param) { - SwsInternal *context; - + SwsContext *sws; static const double default_param[2] = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT }; - int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513, - src_v_chr_pos = -513, dst_v_chr_pos = -513; if (!param) param = default_param; - if ((context = sws_internal(sws)) && - (context->opts.src_w != srcW || - context->opts.src_h != srcH || - context->opts.src_format != srcFormat || - context->opts.dst_w != dstW || - context->opts.dst_h != dstH || - context->opts.dst_format != dstFormat || - context->opts.flags != flags || - context->opts.scaler_params[0] != param[0] || - context->opts.scaler_params[1] != param[1])) { - - av_opt_get_int(context, "src_h_chr_pos", 0, &src_h_chr_pos); - av_opt_get_int(context, "src_v_chr_pos", 0, &src_v_chr_pos); - av_opt_get_int(context, "dst_h_chr_pos", 0, &dst_h_chr_pos); - av_opt_get_int(context, "dst_v_chr_pos", 0, &dst_v_chr_pos); - sws_freeContext(sws); - sws = NULL; - } - - if (!sws) { - if (!(sws = sws_alloc_context())) - return NULL; - context = sws_internal(sws); - context->opts.src_w = srcW; - context->opts.src_h = srcH; - context->opts.src_format = srcFormat; - context->opts.dst_w = dstW; - context->opts.dst_h = dstH; - context->opts.dst_format = dstFormat; - context->opts.flags = flags; - context->opts.scaler_params[0] = param[0]; - context->opts.scaler_params[1] = param[1]; - - av_opt_set_int(context, "src_h_chr_pos", src_h_chr_pos, 0); - av_opt_set_int(context, "src_v_chr_pos", src_v_chr_pos, 0); - av_opt_set_int(context, "dst_h_chr_pos", dst_h_chr_pos, 0); - av_opt_set_int(context, "dst_v_chr_pos", dst_v_chr_pos, 0); - - if (sws_init_context(sws, srcFilter, dstFilter) < 0) { - sws_freeContext(sws); - return NULL; - } + if (prev && (prev->src_w == srcW || + prev->src_h == srcH || + prev->src_format == srcFormat || + prev->dst_w == dstW || + prev->dst_h == dstH || + prev->dst_format == dstFormat || + prev->flags == flags || + prev->scaler_params[0] == param[0] || + prev->scaler_params[1] == param[1])) { + return prev; } + + if (!(sws = sws_alloc_context())) { + sws_free_context(&prev); + return NULL; + } + + if (prev) { + av_opt_copy(sws, prev); + sws_free_context(&prev); + } + + sws->src_w = srcW; + sws->src_h = srcH; + sws->src_format = srcFormat; + sws->dst_w = dstW; + sws->dst_h = dstH; + sws->dst_format = dstFormat; + sws->flags = flags; + sws->scaler_params[0] = param[0]; + sws->scaler_params[1] = param[1]; + + if (sws_init_context(sws, srcFilter, dstFilter) < 0) + sws_free_context(&sws); + return sws; }