From: Niklas Haas <g...@haasn.dev> 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 <g...@haasn.dev> --- libswscale/options.c | 3 +- libswscale/swscale.c | 2 +- libswscale/swscale.h | 102 +++++++++++++++++++-- libswscale/swscale_internal.h | 49 ++-------- libswscale/utils.c | 165 +++++++++++++++++----------------- libswscale/x86/output.asm | 2 +- tests/checkasm/sw_scale.c | 8 +- 7 files changed, 187 insertions(+), 144 deletions(-) diff --git a/libswscale/options.c b/libswscale/options.c index 6248e5f4b5..4ce7d8a36a 100644 --- a/libswscale/options.c +++ b/libswscale/options.c @@ -27,7 +27,7 @@ static const char *sws_context_to_name(void *ptr) return "swscaler"; } -#define OFFSET(x) offsetof(SwsInternal, opts.x) +#define OFFSET(x) offsetof(SwsContext, x) #define DEFAULT 0 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM @@ -91,7 +91,6 @@ const AVClass ff_sws_context_class = { .class_name = "SWScaler", .item_name = sws_context_to_name, .option = swscale_options, - .parent_log_context_offset = offsetof(SwsInternal, parent), .category = AV_CLASS_CATEGORY_SWSCALER, .version = LIBAVUTIL_VERSION_INT, }; diff --git a/libswscale/swscale.c b/libswscale/swscale.c index ea4c7b00d1..d5be07193d 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -1252,7 +1252,7 @@ int attribute_align_arg sws_scale(SwsContext *sws, void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads) { - SwsInternal *parent = priv; + SwsInternal *parent = sws_internal(priv); SwsContext *sws = parent->slice_ctx[threadnr]; SwsInternal *c = sws_internal(sws); diff --git a/libswscale/swscale.h b/libswscale/swscale.h index f544387769..20f6b23368 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,103 @@ 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 context used for internal data. + */ + struct SwsInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + */ + void *opaque; + + /** + * Bitmask of SWS_*. + */ + int64_t 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); @@ -255,7 +339,9 @@ int sws_isSupportedOutput(enum AVPixelFormat pix_fmt); int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt); /** - * Initialize the swscaler context sws_context. + * Initialize the swscaler context sws_context. This function fixes the + * values of any options set in the SwsContext; further adjustments will + * not affect the scaling process. * * @return zero or positive value on success, a negative value on * error diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index d3359eb837..d3871a9641 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -70,26 +70,9 @@ typedef struct SwsInternal SwsInternal; static inline SwsInternal *sws_internal(const SwsContext *sws) { - return (SwsInternal *) sws; + return sws ? sws->internal : NULL; } -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; + /* Shallow copy of the main scaler context, contains currently active options */ + SwsContext opts; + /* Parent context (for cascaded/sliced contexts) */ SwsContext *parent; AVSliceThread *slicethread; @@ -713,7 +674,7 @@ static_assert(offsetof(SwsInternal, redDither) + DITHER32_INT == offsetof(SwsInt #if ARCH_X86 /* x86 yuv2gbrp uses the SwsInternal for yuv coefficients if struct offsets change the asm needs to be updated too */ -static_assert(offsetof(SwsInternal, yuv2rgb_y_offset) == 40316, +static_assert(offsetof(SwsInternal, yuv2rgb_y_offset) == 40332, "yuv2rgb_y_offset must be updated in x86 asm"); #endif diff --git a/libswscale/utils.c b/libswscale/utils.c index 95f3abc1d3..6f8e19fef6 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -284,22 +284,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; @@ -1080,11 +1078,11 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4], - c->brightness = brightness; - c->contrast = contrast; - c->saturation = saturation; - c->opts.src_range = srcRange; - c->opts.dst_range = dstRange; + c->brightness = brightness; + c->contrast = contrast; + c->saturation = saturation; + c->opts.src_range = srcRange; + c->opts.dst_range = dstRange; if (need_reinit) { ff_sws_init_range_convert(c); @@ -1153,7 +1151,7 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4], if (!c->cascaded_context[0]) return -1; - sws_internal(c->cascaded_context[0])->opts.alpha_blend = c->opts.alpha_blend; + c->cascaded_context[0]->alpha_blend = c->opts.alpha_blend; ret = sws_init_context(c->cascaded_context[0], NULL , NULL); if (ret < 0) return ret; @@ -1168,8 +1166,8 @@ int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4], c->opts.scaler_params); if (!c->cascaded_context[1]) return -1; - sws_internal(c->cascaded_context[1])->opts.src_range = srcRange; - sws_internal(c->cascaded_context[1])->opts.dst_range = dstRange; + c->cascaded_context[1]->src_range = srcRange; + c->cascaded_context[1]->dst_range = dstRange; ret = sws_init_context(c->cascaded_context[1], NULL , NULL); if (ret < 0) return ret; @@ -1227,16 +1225,23 @@ int sws_getColorspaceDetails(SwsContext *sws, int **inv_table, SwsContext *sws_alloc_context(void) { - SwsInternal *c = av_mallocz(sizeof(SwsInternal)); + SwsInternal *c; + SwsContext *sws = (SwsContext *) av_mallocz(sizeof(SwsContext)); + if (!sws) + 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 = sws->internal = av_mallocz(sizeof(SwsInternal)); + if (!c) { + av_free(sws); + return NULL; } - return (SwsContext *) c; + sws->av_class = &ff_sws_context_class; + av_opt_set_defaults(sws); + atomic_init(&c->stride_unaligned_warned, 0); + atomic_init(&c->data_unaligned_warned, 0); + + return sws; } static uint16_t * alloc_gamma_tbl(double e) @@ -1314,6 +1319,7 @@ static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt) } } +/* Assumes c->opts is already initialized */ static av_cold int sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, SwsFilter *dstFilter) { @@ -1736,7 +1742,7 @@ static av_cold int sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter flags, c->opts.scaler_params); if (!c->cascaded_context[0]) return AVERROR(EINVAL); - sws_internal(c->cascaded_context[0])->opts.alpha_blend = c->opts.alpha_blend; + c->cascaded_context[0]->alpha_blend = c->opts.alpha_blend; ret = sws_init_context(c->cascaded_context[0], NULL , NULL); if (ret < 0) return ret; @@ -1747,8 +1753,8 @@ static av_cold int sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter if (!c->cascaded_context[1]) return AVERROR(EINVAL); - sws_internal(c->cascaded_context[1])->opts.src_range = c->opts.src_range; - sws_internal(c->cascaded_context[1])->opts.dst_range = c->opts.dst_range; + c->cascaded_context[1]->src_range = c->opts.src_range; + c->cascaded_context[1]->dst_range = c->opts.dst_range; ret = sws_init_context(c->cascaded_context[1], srcFilter , dstFilter); if (ret < 0) return ret; @@ -2057,15 +2063,11 @@ static int context_init_threaded(SwsContext *sws, c->slice_ctx[i] = sws_alloc_context(); if (!c->slice_ctx[i]) return AVERROR(ENOMEM); - c2 = sws_internal(c->slice_ctx[i]); - c->nb_slice_ctx++; - c2->parent = sws; - - ret = av_opt_copy((void*)c->slice_ctx[i], (void*)c); - if (ret < 0) - return ret; + c2 = sws_internal(c->slice_ctx[i]); + c2->parent = sws; + c2->opts = c->opts; /* copy initialized opts directly */ c2->opts.threads = 1; ret = sws_init_single_context(c->slice_ctx[i], src_filter, dst_filter); @@ -2090,6 +2092,11 @@ av_cold int sws_init_context(SwsContext *sws, SwsFilter *srcFilter, enum AVPixelFormat src_format, dst_format; int ret; + /* Apply options from main context. Note that this also copies the + * AVClass, for logging */ + c->opts = *sws; + c->opts.internal = NULL; /* sanity */ + c->frame_src = av_frame_alloc(); c->frame_dst = av_frame_alloc(); if (!c->frame_src || !c->frame_dst) @@ -2520,6 +2527,7 @@ void sws_freeContext(SwsContext *sws) ff_free_filters(c); + av_free(c); av_free(sws); } @@ -2533,7 +2541,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, @@ -2541,59 +2549,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; } diff --git a/libswscale/x86/output.asm b/libswscale/x86/output.asm index dec1d27f9a..7a1e5d9bc1 100644 --- a/libswscale/x86/output.asm +++ b/libswscale/x86/output.asm @@ -582,7 +582,7 @@ yuv2nv12cX_fn yuv2nv21 %if ARCH_X86_64 struc SwsInternal - .padding: resb 40316 ; offsetof(SwsInternal, yuv2rgb_y_offset) + .padding: resb 40332 ; offsetof(SwsInternal, yuv2rgb_y_offset) .yuv2rgb_y_offset: resd 1 .yuv2rgb_y_coeff: resd 1 .yuv2rgb_v2r_coeff: resd 1 diff --git a/tests/checkasm/sw_scale.c b/tests/checkasm/sw_scale.c index 8951ddce43..119bff96d9 100644 --- a/tests/checkasm/sw_scale.c +++ b/tests/checkasm/sw_scale.c @@ -124,12 +124,12 @@ static void check_yuv2yuv1(int accurate) randomize_buffers((uint8_t*)dither, 8); randomize_buffers((uint8_t*)src_pixels, LARGEST_INPUT_SIZE * sizeof(int16_t)); sws = sws_alloc_context(); - c = sws_internal(sws); if (accurate) - c->opts.flags |= SWS_ACCURATE_RND; + sws->flags |= SWS_ACCURATE_RND; if (sws_init_context(sws, NULL, NULL) < 0) fail(); + c = sws_internal(sws); ff_sws_init_scale(c); for (isi = 0; isi < INPUT_SIZES; ++isi) { dstW = input_sizes[isi]; @@ -192,12 +192,12 @@ static void check_yuv2yuvX(int accurate) memset(dither, d_val, LARGEST_INPUT_SIZE); randomize_buffers((uint8_t*)src_pixels, LARGEST_FILTER * LARGEST_INPUT_SIZE * sizeof(int16_t)); sws = sws_alloc_context(); - c = sws_internal(sws); if (accurate) - c->opts.flags |= SWS_ACCURATE_RND; + sws->flags |= SWS_ACCURATE_RND; if (sws_init_context(sws, NULL, NULL) < 0) fail(); + c = sws_internal(sws); ff_sws_init_scale(c); for(isi = 0; isi < INPUT_SIZES; ++isi){ dstW = input_sizes[isi]; -- 2.46.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".