Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Niklas Haas <ffmpeg@haasn.xyz>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [RFC]] swscale modernization proposal
Date: Fri, 5 Jul 2024 20:31:17 +0200
Message-ID: <20240705203117.GB297771@haasn.xyz> (raw)
In-Reply-To: <20240703152558.GB29034@haasn.xyz>

[-- Attachment #1: Type: text/plain, Size: 1518 bytes --]

On Wed, 03 Jul 2024 15:25:58 +0200 Niklas Haas <ffmpeg@haasn.xyz> wrote:
> On Tue, 02 Jul 2024 15:27:00 +0200 Niklas Haas <ffmpeg@haasn.xyz> wrote:
>  
> > 1. Is this a good idea, or too confusing / complex to be worth the gain?
> >    Specifically, I am worried about confusion arising due to differences
> >    in behavior, and implemented options, between all of the above.
> > 
> >    That said, I think there is a big win to be had from unifying all of
> >    the different scaling and/or conversion filters we have in e.g.
> >    libavfilter, as well as making it trivial for users of this API to
> >    try using e.g. GPU scaling instead of CPU scaling.
> 
> After prototyping this approach a bit (using an internal struct
> AVScaleBackend), I think I like it. It specifically makes handling
> unscaled special converters pretty straightforward, for example - the
> "unscaled" backend can be separate from the generic/scaling backend.
> 
> We could also trivially plug in something like libyuv, or some other
> limited-use-case fast path, without the user really noticing.

Small update: I decided to scrap the idea of separate user-visible
"backends" for now, but preserved the internal API boundary between the
avscale_* "front-end" and the actual back-end implementation, which
I have called 'AVScaleGraph' for now.

The idea is that this will grow into a full colorspace <-> colorspace
"solver", but for now it is just hooked up to sws_createContext().

Attached is my revised working draft of <avscale.h>.

[-- Attachment #2: avscale.h --]
[-- Type: text/plain, Size: 10215 bytes --]

/*
 * Copyright (C) 2024 Niklas Haas
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef SWSCALE_AVSCALE_H
#define SWSCALE_AVSCALE_H

/**
 * @file
 * @ingroup libsws
 * Higher-level wrapper around libswscale + related libraries, which is
 * capable of handling more advanced colorspace transformations.
 */

#include "libavutil/frame.h"
#include "libavutil/log.h"

/**
 * Main external API structure. New fields cannot be added to the end with
 * minor version bumps. Removal, reordering and changes to existing fields
 * require a major version bump. sizeof(AVScaleContext) is not part of the ABI.
 */
typedef struct AVScaleContext {
    const AVClass *av_class;

    /**
     * Private context used for internal data.
     */
    struct AVScaleInternal *internal;

    /**
     * Private data of the user, can be used to carry app specific stuff.
     */
    void *opaque;

    /**
     * Bitmask of AV_SCALE_* flags.
     */
    int64_t flags;

    /**
     * How many threads to use for processing, or 0 for automatic selection.
     */
    int threads;

    /**
     * Quality preset, on a scale from 1 to 10. See `enum AVScaleQuality`.
     */
    int preset;

    /**
     * Dither mode. If set to something other than AV_DITHER_AUTO, this will
     * override the dither mode implied by the `preset`.
     */
    int dither;

    /**
     * Scaling filter. If set to something other than AV_SCALE_AUTO, this will
     * override the filter implied by the `preset`.
     */
    int filter;

    /**
     * Filter used specifically for up/downsampling subsampled (chroma) planes.
     * If set to something other than AV_SCALE_AUTO, this will override the
     * filter implied by the `preset`.
     */
    int filter_sub;

    /**
     * Backwards compatibility field with libswscale. Anything set here
     * will override the corresponding options implied by the fields above.
     *
     * @deprecated use AVScaleContext.flags/filter/dither
     */
    attribute_deprecated
    int sws_flags;
} AVScaleContext;

/**
 * Allocate an AVScaleContext and set its fields to default values. The
 * resulting struct should be freed with avscale_free_context().
 */
AVScaleContext *avscale_alloc_context(void);

/**
 * Free the codec context and everything associated with it, and write NULL
 * to the provided pointer.
 */
void avscale_free_context(AVScaleContext **ctx);

/**
 * Get the AVClass for AVScaleContext. It can be used in combination with
 * AV_OPT_SEARCH_FAKE_OBJ for examining options.
 *
 * @see av_opt_find().
 */
const AVClass *avscale_get_class(void);

/******************************
 * Flags and quality settings *
 ******************************/

enum AVScaleFlags {
    /**
    * Force bit-exact output. This will prevent the use of platform-specific
    * optimizations that may lead to slight difference in rounding, in favor
    * of always maintaining exact bit output compatibility with the reference
    * C code.
    */
    AV_SCALE_BITEXACT = 1 << 0,

    /**
    * Return an error on underspecified conversions. Without this flag,
    * unspecified fields are defaulted to sensible values.
    */
    AV_SCALE_STRICT = 1 << 1,
};

/**
 * The exact interpretation of these quality presets depends on the backend
 * used, but the backend-invariant common settings are derived as follows:
 */
enum AVScaleQuality {
    AV_SCALE_ULTRAFAST = 1,  /* no dither,      nearest+nearest     */
    AV_SCALE_SUPERFAST = 2,  /* no dither,      bilinear+nearest    */
    AV_SCALE_VERYFAST  = 3,  /* no dither,      bilinear+bilinear   */
    AV_SCALE_FASTER    = 4,  /* bayer dither,   bilinear+bilinear   */
    AV_SCALE_FAST      = 5,  /* bayer dither,   bicubic+bilinear    */
    AV_SCALE_MEDIUM    = 6,  /* bayer dither,   bicubic+bicubic     */
    AV_SCALE_SLOW      = 7,  /* bayer dither,   lanczos+bicubic     */
    AV_SCALE_SLOWER    = 8,  /* full dither,    lanczos+bicubic     */
    AV_SCALE_VERYSLOW  = 9,  /* full dither,    lanczos+lanczos     */
    AV_SCALE_PLACEBO   = 10, /* full dither,    lanczos+lanczos     */
};

enum AVDitherMode {
    AV_DITHER_AUTO = 0, /* auto-select from preset */
    AV_DITHER_NONE,     /* disable dithering */
    AV_DITHER_BAYER,    /* ordered dither matrix */
    AV_DITHER_FULL,     /* full error diffusion */
};

/**
 * Returns the default dither mode implied by a given quality preset.
 */
enum AVDitherMode avscale_default_dither(int preset);

enum AVScaleFilter {
    AV_SCALE_AUTO = 0,  /* auto-select from preset */
    AV_SCALE_NEAREST,   /* nearest neighbour */
    AV_SCALE_BILINEAR,  /* bilinear filtering */
    AV_SCALE_BICUBIC,   /* 2-tap cubic B-spline */
    AV_SCALE_GAUSSIAN,  /* gaussian approximation */
    AV_SCALE_LANCZOS,   /* 3-tap sinc/sinc */
};

/**
 * Returns the default scaling filters implied by a given quality preset.
 */
enum AVScaleFilter avscale_default_filter(int preset);
enum AVScaleFilter avscale_default_filter_sub(int preset);

/***************************
 * Supported frame formats *
 ***************************/

/**
 * Test if a given pixel format is supported.
 *
 * @param output  If 0, test if compatible with the source/input frame;
 *                otherwise, with the destination/output frame.
 * @param format  The format to check.
 *
 * @return A positive integer if supported, 0 otherwise.
 */
int avscale_test_format(enum AVPixelFormat format, int output);

/**
 * Test if a given color space is supported.
 *
 * @param output  If 0, test if compatible with the source/input frame;
 *                otherwise, with the destination/output frame.
 * @param colorspace The colorspace to check.
 *
 * @return A positive integer if supported, 0 otherwise.
 */
int avscale_test_colorspace(enum AVColorSpace colorspace, int output);

/**
 * Test if a given set of color primaries is supported.
 *
 * @param output  If 0, test if compatible with the source/input frame;
 *                otherwise, with the destination/output frame.
 * @param primaries The color primaries to check.
 *
 * @return A positive integer if supported, 0 otherwise.
 */
int avscale_test_primaries(enum AVColorPrimaries primaries, int output);

/**
 * Test if a given color transfer function is supported.
 *
 * @param output  If 0, test if compatible with the source/input frame;
 *                otherwise, with the destination/output frame.
 * @param trc     The color transfer function to check.
 *
 * @return A positive integer if supported, 0 otherwise.
 */
int avscale_test_transfer(enum AVColorTransferCharacteristic trc, int output);

/**
 * Helper function to run all avscale_test_* against a frame. Ignores irrelevant
 * properties, for example AVColorSpace is not checked for RGB frames.
 */
int avscale_test_frame(const AVFrame *frame, int output);

/********************
 * Main scaling API *
 ********************/

/**
 * Check if a given conversion is a noop. Returns a positive integer if
 * no operation needs to be performed, 0 otherwise.
 */
int avscale_is_noop(const AVFrame *dst, const AVFrame *src);

/**
 * Return the minimum slice alignment required for a given frame. This is
 * always a power of two, typically 1, 2 or 4 depending on the frame's
 * subsampling and interlacing.
 */
int avscale_slice_alignment(const AVFrame *frame);

/**
 * Scale source data from `src` and write the output to `dst`. This is
 * merely a convenience wrapper around `avscale_frame_slice(ctx, dst, src, 0,
 * src->height)`.
 *
 * @param ctx   The scaling context.
 * @param dst   The destination frame. See avscale_frame_slice().
 * @param src   The source frame. See avscale_frame_slice().
 * @return 0 on success, a negative AVERROR code on failure.
 */
int avscale_frame(AVScaleContext *ctx, AVFrame *dst, const AVFrame *src);

/**
 * Like `avscale_frame`, but operates only on the (source) range from `ystart`
 * to `height`.
 *
 * @param ctx   The scaling context.
 * @param dst   The destination frame. The data buffers may either be already
 *              allocated by the caller or left clear, in which case they will
 *              be allocated by the scaler. The latter may have performance
 *              advantages - e.g. in certain cases some (or all) output planes
 *              may be references to input planes, rather than copies.
 * @param src   The source frame. If the data buffers are set to NULL, then
 *              this function behaves identically to `avscale_frame_setup`.
 * @param slice_start   First row of slice, relative to `src`. Must be a
 *                      multiple of avscale_slice_alignment(src).
 * @param slice_height  Number of (source) rows in the slice. Must be a
 *                      multiple of avscale_slice_alignment(src).
 *
 * @return 0 on success, a negative AVERROR code on failure.
 */
int avscale_frame_slice(AVScaleContext *ctx, AVFrame *dst,
                        const AVFrame *src, int slice_start, int slice_height);

/**
 * Like `avscale_frame`, but without actually scaling. It will instead merely
 * initialize internal state that *would* be required to perform the operation,
 * as well as returning the correct error code for unsupported frame
 * combinations.
 *
 * @param ctx   The scaling context.
 * @param dst   The destination frame to consider.
 * @param src   The source frame to consider.
 * @return 0 on success, a negative AVERROR code on failure.
 */
int avscale_frame_setup(AVScaleContext *ctx, const AVFrame *dst,
                        const AVFrame *src);

#endif /* SWSCALE_AVSCALE_H */

[-- Attachment #3: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2024-07-05 18:31 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-22 13:13 Niklas Haas
2024-06-22 14:23 ` Andrew Sayers
2024-06-22 15:10   ` Niklas Haas
2024-06-22 19:52     ` Michael Niedermayer
2024-06-22 22:24       ` Niklas Haas
2024-06-23 17:27         ` Michael Niedermayer
2024-06-22 22:19 ` Vittorio Giovara
2024-06-22 22:39   ` Niklas Haas
2024-06-23 17:46   ` Michael Niedermayer
2024-06-23 19:00     ` Paul B Mahol
2024-06-23 17:57   ` James Almer
2024-06-23 18:40     ` Andrew Sayers
2024-06-24 14:33     ` Niklas Haas
2024-06-24 14:44     ` Vittorio Giovara
2024-06-25 15:31       ` Niklas Haas
2024-07-01 21:10       ` Stefano Sabatini
2024-06-29  7:41 ` Zhao Zhili
2024-06-29 10:58   ` Niklas Haas
2024-06-29 11:47 ` Niklas Haas
2024-06-29 12:35   ` Michael Niedermayer
2024-06-29 14:05     ` Niklas Haas
2024-06-29 14:11       ` James Almer
2024-06-30  6:25   ` Vittorio Giovara
2024-07-02 13:27 ` Niklas Haas
2024-07-03 13:25   ` Niklas Haas
2024-07-05 18:31     ` Niklas Haas [this message]
2024-07-05 21:34       ` Michael Niedermayer
2024-07-06  0:11         ` Hendrik Leppkes
2024-07-06 12:32           ` Niklas Haas
2024-07-06 16:42           ` Michael Niedermayer
2024-07-06 17:29             ` Hendrik Leppkes
2024-07-08 11:58               ` Ronald S. Bultje
2024-07-08 12:33                 ` Andrew Sayers
2024-07-08 13:25                   ` Ronald S. Bultje
2024-07-06 11:36         ` Andrew Sayers
2024-07-06 12:27         ` Niklas Haas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240705203117.GB297771@haasn.xyz \
    --to=ffmpeg@haasn.xyz \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git