35 if ((ret = (x)) < 0) \
82 av_log(
ctx, msg_lev,
"Backend '%s' failed to compile operations: %s\n",
91 "block size = %d, over-read = {%d %d %d %d}, over-write = {%d %d %d %d}, "
92 "cpu flags = 0x%x\n", backend->
name,
out->block_size,
93 out->over_read[0],
out->over_read[1],
94 out->over_read[2],
out->over_read[3],
95 out->over_write[0],
out->over_write[1],
96 out->over_write[2],
out->over_write[3],
117 !(enabled & backend->
flags))
144 av_free(p->exec_base.in_bump_y);
145 av_free(p->exec_base.in_offset_x);
151 const uint8_t *in[4], uint8_t *
out[4])
154 const int y_src = p->offsets_y ? p->offsets_y[y_dst] : y_dst;
155 for (
int i = 0;
i < p->planes_in;
i++)
157 for (
int i = 0;
i < p->planes_out;
i++)
166 return h >>
base->in_sub_y[plane];
168 const int y0 = p->offsets_y[y] >>
base->in_sub_y[plane];
169 const int y1 = p->offsets_y[y +
h - 1] >>
base->in_sub_y[plane];
176 const uint64_t
bits = (uint64_t) pixels * pixel_bits;
183 return (
bits + 7) >> 3;
194 return FFMAX(safe_bytes, 0);
198 ptrdiff_t safe_offset,
201 size_t safe_blocks = num_blocks;
202 while (safe_blocks && offset_bytes[safe_blocks * block_size - 1] > safe_offset)
219 const unsigned block_size =
comp->block_size;
220 const size_t num_blocks = (
width + block_size - 1) / block_size;
221 const size_t aligned_w = num_blocks * block_size;
222 if (aligned_w <
width)
224 p->num_blocks = num_blocks;
225 p->memcpy_first =
false;
226 p->memcpy_last =
false;
227 p->memcpy_out =
false;
229 size_t safe_blocks = num_blocks;
230 for (
int i = 0;
i < p->planes_in;
i++) {
231 const int idx = p->idx_in[
i];
232 size_t input_bytes = in->
linesize[idx];
233 if (p->filter_size_h && float_in) {
240 size_t safe_blocks_in;
242 size_t filter_size =
pixel_bytes(p->filter_size_h, p->pixel_bits_in,
245 safe_bytes - filter_size,
251 if (safe_blocks_in < num_blocks) {
252 p->memcpy_first |= in->
linesize[idx] < 0;
253 p->memcpy_last |= in->
linesize[idx] > 0;
254 safe_blocks =
FFMIN(safe_blocks, safe_blocks_in);
263 for (
int i = 0;
i < p->planes_out;
i++) {
264 const int idx = p->idx_out[
i];
267 if (safe_blocks_out < num_blocks) {
268 p->memcpy_out =
true;
269 safe_blocks =
FFMIN(safe_blocks, safe_blocks_out);
278 if (p->palette_idx >= 0) {
279 exec->
in[1] = in->
data[p->palette_idx];
283 const bool memcpy_in = p->memcpy_first || p->memcpy_last;
284 if (!memcpy_in && !p->memcpy_out) {
292 size_t alloc_size = 0;
295 const size_t safe_width = safe_blocks * block_size;
296 const size_t tail_size =
width - safe_width;
299 p->tail_blocks = num_blocks - safe_blocks;
310 const size_t alloc_width = aligned_w - safe_width;
311 for (
int i = 0; memcpy_in &&
i < p->planes_in;
i++) {
317 needed_size = p->tail_size_in;
327 for (
int i = 0; p->memcpy_out &&
i < p->planes_out;
i++) {
340 alloc_size += aligned_w *
sizeof(*exec->
in_offset_x);
347 uint8_t *tail_buf = p->tail_buf;
348 for (
int i = 0; memcpy_in &&
i < p->planes_in;
i++) {
349 tail->
in[
i] = tail_buf;
353 for (
int i = 0; p->memcpy_out &&
i < p->planes_out;
i++) {
354 tail->
out[
i] = tail_buf;
360 for (
int i = safe_width;
i < aligned_w;
i++)
368 const uint8_t *
src,
const size_t src_stride,
369 const int h,
const size_t bytes)
371 for (
int y = 0; y <
h; y++) {
403 const bool memcpy_in = p->memcpy_last && y +
h == pass->
lines ||
404 p->memcpy_first && y == 0;
405 const bool memcpy_out = p->memcpy_out;
406 const size_t num_blocks = p->num_blocks;
407 const size_t tail_blocks = p->tail_blocks;
410 if (!memcpy_in && !memcpy_out) {
412 comp->func(&exec,
comp->priv, 0, y, num_blocks, y +
h);
418 if (num_blocks > tail_blocks) {
419 for (
int i = 0;
i < 4;
i++) {
423 exec.in_bump[
i] += exec.block_size_in[
i] * tail_blocks;
424 exec.out_bump[
i] += exec.block_size_out[
i] * tail_blocks;
427 comp->func(&exec,
comp->priv, 0, y, num_blocks - tail_blocks, y +
h);
434 for (
int i = 0;
i < p->planes_in;
i++) {
436 if (!exec.in_offset_x || memcpy_in)
437 exec.in[
i] += p->tail_off_in;
438 tail.in[
i] += y * tail.in_stride[
i];
440 for (
int i = 0;
i < p->planes_out;
i++) {
441 exec.out[
i] += p->tail_off_out;
442 tail.out[
i] += y * tail.out_stride[
i];
445 for (
int i = 0;
i < p->planes_in;
i++) {
449 exec.in[
i], exec.in_stride[
i], lines, p->tail_size_in);
452 const size_t loop_size = tail_blocks * exec.block_size_in[
i];
453 tail.in[
i] = exec.in[
i];
454 tail.in_stride[
i] = exec.in_stride[
i];
455 tail.in_bump[
i] = exec.in_stride[
i] - loop_size;
459 for (
int i = 0; !memcpy_out &&
i < p->planes_out;
i++) {
461 const size_t loop_size = tail_blocks * exec.block_size_out[
i];
462 tail.out[
i] = exec.out[
i];
463 tail.out_stride[
i] = exec.out_stride[
i];
464 tail.out_bump[
i] = exec.out_stride[
i] - loop_size;
469 comp->func(&tail,
comp->priv, num_blocks - tail_blocks, y, num_blocks, y +
h);
471 for (
int i = 0; memcpy_out &&
i < p->planes_out;
i++) {
472 const int lines =
h >> tail.out_sub_y[
i];
474 tail.out[
i], tail.out_stride[
i], lines, p->tail_size_out);
519 switch (
op->rw.mode) {
525 const int bits = 8 >>
op->rw.frac;
533 if (!pass || pixel_bits <= 0)
538 for (
int i = 0;
i < 4;
i++) {
539 const int pad = (over_rw[
i] * 8 + pixel_bits - 1) / pixel_bits;
540 pad_max =
FFMAX(pad_max, pad);
574 if (p->comp.opaque) {
578 input, 0,
c.slice_align,
c.func_opaque,
579 NULL,
c.priv,
c.free, output);
581 (*output)->backend =
c.backend->flags;
596 .height =
dst->height,
609 if (block_bits_in & 0x7 || block_bits_out & 0x7) {
615 for (
int i = 0;
i < 4;
i++)
616 p->idx_in[
i] = p->idx_out[
i] = -1;
618 for (
int i = 0;
i < p->planes_in;
i++) {
620 const int chroma = idx == 1 || idx == 2;
623 p->exec_base.in_sub_x[
i] = sub_x;
624 p->exec_base.in_sub_y[
i] = sub_y;
625 p->exec_base.block_size_in[
i] = block_bits_in >> 3;
629 for (
int i = 0;
i < p->planes_out;
i++) {
631 const int chroma = idx == 1 || idx == 2;
634 p->exec_base.out_sub_x[
i] = sub_x;
635 p->exec_base.out_sub_y[
i] = sub_y;
636 p->exec_base.block_size_out[
i] = block_bits_out >> 3;
652 for (
int y = 0; y <
filter->dst_size - 1; y++) {
653 int next =
filter->offsets[y + 1];
654 bump[y] = next -
line - 1;
657 bump[
filter->dst_size - 1] = 0;
658 p->exec_base.in_bump_y = bump;
661 const int pixels =
FFALIGN(
filter->dst_size, p->comp.block_size);
667 p->exec_base.in_offset_x =
offset;
669 for (
int x = 0; x <
filter->dst_size; x++) {
674 if ((
bits & 0x7) || (
bits >> 3) > INT32_MAX) {
680 for (
int x =
filter->dst_size; x < pixels; x++)
682 for (
int i = 0;
i < 4;
i++)
683 p->exec_base.block_size_in[
i] = 0;
684 p->filter_size_h =
filter->filter_size;
693 (*output)->backend =
comp->backend->flags;
710 for (
int c = 0;
c < 4;
c++) {
751 for (
int idx = 1; idx < ops->
num_ops - 1; idx++) {
822 const int num_passes = graph->
num_passes - passes_orig;
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static const uint8_t *BS_FUNC align(BSCTX *bc)
Skip bits to a byte boundary.
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
#define flags(name, subs,...)
#define i(width, name, range_min, range_max)
#define AV_CEIL_RSHIFT(a, b)
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
static const uint8_t bits[8]
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int lines, int align, SwsPassFunc run, SwsPassSetup setup, void *priv, void(*free_cb)(void *priv), SwsPass **out_pass)
Allocate and add a new pass to the filter graph.
void ff_sws_pass_link_output(SwsPass *dst, const SwsPass *src)
Link the output buffers to a different pass, rather than allocating new image buffers.
void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
Remove all passes added since the given index.
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVRounding
Rounding methods.
@ AV_ROUND_INF
Round away from zero.
@ AV_ROUND_ZERO
Round toward zero.
@ AV_ROUND_DOWN
Round toward -infinity.
@ AV_ROUND_UP
Round toward +infinity.
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
Allocate and clear a buffer, reusing the given one if large enough.
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
static const struct @257111027162314367033347246032313251342043035002 planes[]
#define FFSWAP(type, a, b)
Memory handling functions.
#define DECLARE_ALIGNED_32(t, v)
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
const SwsOp * ff_sws_op_list_input(const SwsOpList *ops)
Returns the input operation for a given op list, or NULL if there is none (e.g.
void ff_sws_op_list_free(SwsOpList **p_ops)
const SwsOpBackend *const ff_sws_op_backends[]
int ff_sws_rw_op_planes(const SwsOp *op)
Return the number of planes involved in a read/write operation.
const SwsOp * ff_sws_op_list_output(const SwsOpList *ops)
Returns the output operation for a given op list, or NULL if there is none.
bool ff_sws_op_list_is_noop(const SwsOpList *ops)
Returns whether an op list represents a true no-op operation, i.e.
void ff_sws_op_list_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
int ff_sws_op_list_optimize(SwsOpList *ops)
Fuse compatible and eliminate redundant operations, as well as replacing some operations with more ef...
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
static size_t safe_blocks_offset(size_t num_blocks, unsigned block_size, ptrdiff_t safe_offset, const int32_t *offset_bytes)
static int rw_data_planes(const SwsOp *op)
static int get_lines_in(const SwsOpPass *p, const int y, const int h, const int plane)
static int rw_pixel_bits(const SwsOp *op)
static size_t pixel_bytes(size_t pixels, int pixel_bits, enum AVRounding rounding)
static int compile_single(const CompileArgs *args, const SwsOpList *ops, SwsPass *link, SwsPass *input, SwsPass **output)
void ff_sws_compiled_op_unref(SwsCompiledOp *comp)
static void op_pass_free(void *ptr)
static void op_list_get_plane_copy(const SwsOpList *ops, SwsPass *pass)
#define RET(x)
Copyright (C) 2025 Niklas Haas.
static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, const int h, const SwsPass *pass)
static int compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
static int op_pass_setup(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
static int compile_subpass(const CompileArgs *args, SwsOpList **pops, SwsPass *link, SwsPass *input, SwsPass **output)
static void get_row_data(const SwsOpPass *p, const int y_dst, const uint8_t *in[4], uint8_t *out[4])
static SwsCompMask plane_mask_flags(const SwsOp *op, SwsCompFlags flags)
int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend, SwsOpList **pops, int flags, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
static void align_pass(SwsPass *pass, int block_size, const int *over_rw, int pixel_bits)
static void copy_lines(uint8_t *dst, const size_t dst_stride, const uint8_t *src, const size_t src_stride, const int h, const size_t bytes)
int ff_sws_ops_compile(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Attempt to compile a list of operations using a specific backend, or the best available backend if ba...
static size_t safe_bytes_pad(int linesize, int plane_pad)
@ SWS_OP_FLAG_SPLIT_MEMCPY
int ff_sws_op_list_split_at(SwsOpList *ops1, SwsOpList **ops2, int index)
Split an op list into two at the given index.
int ff_sws_op_list_split_planes(SwsOpList *ops1, SwsOpList **ops2, SwsCompMask planes)
Reduce an op list into a reduced subset that operates only on a given subset of planes.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
uint64_t flags
Combination of AV_PIX_FMT_FLAG_... flags.
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
const SwsOpBackend * backend
const struct SwsOpBackend * backend
Main external API structure.
Represents a computed filter kernel.
Represents a view into a single field of frame data.
enum AVPixelFormat format
int width
Dimensions and format.
Filter graph, which represents a 'baked' pixel format conversion.
int(* compile)(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Compile an operation list to an implementation chain.
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
Copyright (C) 2026 Niklas Haas.
int32_t block_size_out[4]
int32_t * in_offset_x
Pixel offset map; for horizontal scaling, in bytes.
ptrdiff_t in_bump[4]
Pointer bump, difference between stride and processed line size.
Helper struct for representing a list of operations.
unsigned int tail_buf_size
SwsComps comps
Metadata about the operation's input/output components.
Represents an output buffer for a filter pass.
int plane_copy[4]
Map of planes which are directly copied from the pass input.
Represents a single filter pass in the scaling graph.
enum AVPixelFormat format
SwsPassBuffer * output
Filter output buffer.
SwsReadWriteMode mode
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
SwsBackend ff_sws_enabled_backends(const SwsContext *ctx)
#define av_malloc_array(a, b)
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
#define ff_sws_comp_mask_str(mask)
uint8_t SwsCompMask
Bit-mask of components.
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
static void copy(const float *p1, float *p2, const int length)