Go to the documentation of this file.
38 #if ARCH_X86_64 && HAVE_X86ASM
50 if ((ret = (x)) < 0) \
125 for (
int i = 0;
i < 4;
i++)
133 for (
int i = 0;
i < 4;
i++)
142 for (
int i = 0;
i < 4;
i++)
146 for (
int i = 0;
i < 4;
i++)
152 for (
int i = 0;
i < 4;
i++) {
160 for (
int i = 0;
i < 4;
i++)
166 for (
int i = 0;
i < 4;
i++)
167 x[
i] = x[
i].den ?
Q((x[
i].num / x[
i].den) >>
op->c.u) : x[
i];
171 const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
172 for (
int i = 0;
i < 4;
i++)
173 x[
i] = orig[
op->swizzle.in[
i]];
179 for (
int i = 0;
i < 4;
i++) {
180 x[
i] = x[
i].
den ?
Q(x[
i].num / x[
i].den) : x[
i];
181 if (
op->convert.expand)
188 for (
int i = 0;
i < 4;
i++) {
189 if (
op->dither.y_offset[
i] >= 0 && x[
i].
den)
194 for (
int i = 0;
i < 4;
i++)
198 for (
int i = 0;
i < 4;
i++)
203 const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
204 for (
int i = 0;
i < 4;
i++) {
206 for (
int j = 0; j < 4; j++)
213 for (
int i = 0;
i < 4;
i++)
227 return ((
a &
b) & flags_and) | ((
a |
b) & flags_or);
233 for (
int i = 0;
i < 4;
i++)
240 for (
int i = 0;
i < 4;
i++) {
255 for (
int n = 0; n < ops->
num_ops; n++) {
265 memcpy(
op->comps.min, prev.
min,
sizeof(prev.
min));
266 memcpy(
op->comps.max, prev.
max,
sizeof(prev.
max));
276 for (
int i = 0;
i <
op->rw.elems;
i++) {
282 for (
int i =
op->rw.elems;
i < 4;
i++) {
284 op->comps.min[
i] = prev.
min[
i];
285 op->comps.max[
i] = prev.
max[
i];
289 for (
int i = 0;
i < 4;
i++) {
291 op->comps.min[
i] = prev.
min[
i];
292 op->comps.max[
i] = prev.
max[
i];
296 for (
int i = 0;
i <
op->rw.elems;
i++)
313 for (
int i = 0;
i < 4;
i++)
317 for (
int i = 0;
i < 4;
i++) {
318 const int pattern =
op->pack.pattern[
i];
322 op->comps.min[
i] =
Q(0);
323 op->comps.max[
i] =
Q((1ULL << pattern) - 1);
330 for (
int i = 0;
i < 4;
i++) {
331 if (
op->pack.pattern[
i])
340 for (
int i = 0;
i < 4;
i++) {
341 if (
op->c.q4[
i].den) {
342 op->comps.flags[
i] = 0;
343 if (
op->c.q4[
i].num == 0)
345 if (
op->c.q4[
i].den == 1)
353 for (
int i = 0;
i < 4;
i++)
354 op->comps.flags[
i] = prev.
flags[
op->swizzle.in[
i]];
357 for (
int i = 0;
i < 4;
i++) {
364 for (
int i = 0;
i < 4;
i++) {
367 for (
int j = 0; j < 4; j++) {
381 if (
op->lin.m[
i][4].num) {
383 if (
op->lin.m[
i][4].den != 1)
394 for (
int i = 0;
i < 4;
i++) {
396 if (
op->c.q.den != 1)
412 for (
int n = ops->
num_ops - 1; n >= 0; n--) {
418 for (
int i = 0;
i <
op->rw.elems;
i++)
420 for (
int i =
op->rw.elems;
i < 4;
i++)
431 for (
int i = 0;
i < 4;
i++)
436 for (
int i = 0;
i < 4;
i++) {
437 if (
op->pack.pattern[
i])
439 op->comps.unused[
i] =
i > 0;
441 op->comps.unused[0] = unused;
445 for (
int i = 0;
i < 4;
i++) {
446 if (
op->pack.pattern[
i])
449 op->comps.unused[
i] =
true;
453 for (
int i = 0;
i < 4;
i++) {
455 op->comps.unused[
i] =
true;
461 bool unused[4] = {
true,
true,
true,
true };
462 for (
int i = 0;
i < 4;
i++)
464 for (
int i = 0;
i < 4;
i++)
465 op->comps.unused[
i] = unused[
i];
469 for (
int j = 0; j < 4; j++) {
471 for (
int i = 0;
i < 4;
i++) {
472 if (
op->lin.m[
i][j].num)
475 op->comps.unused[j] = unused;
552 const int end = ops->
num_ops - count;
601 const int num_planes =
read->rw.packed ? 1 :
read->rw.elems;
602 for (
int i = 0;
i < num_planes;
i++) {
624 for (
int i = 0;
i < 4;
i++) {
625 for (
int j = 0; j < 5; j++) {
636 static const struct {
667 return patterns[
i].
name;
703 return q.
num > 0 ?
"inf" : q.
num < 0 ?
"-inf" :
"nan";
704 }
else if (q.
den == 1) {
716 #define PRINTQ(q) print_q(q, (char[32]){0}, sizeof(char[32]))
733 op->comps.unused[0] ?
'X' :
'.',
734 op->comps.unused[1] ?
'X' :
'.',
735 op->comps.unused[2] ?
'X' :
'.',
736 op->comps.unused[3] ?
'X' :
'.',
751 op->rw.elems,
op->rw.packed ?
"packed" :
"planar",
755 op->rw.packed ? 1 :
op->rw.elems, buf));
771 op->pack.pattern[0],
op->pack.pattern[1],
772 op->pack.pattern[2],
op->pack.pattern[3]);
775 av_log(
log,
lev,
"%-20s: {%s %s %s %s}\n",
"SWS_OP_CLEAR",
783 op->swizzle.x,
op->swizzle.y,
op->swizzle.z,
op->swizzle.w);
786 av_log(
log,
lev,
"%-20s: %s -> %s%s\n",
"SWS_OP_CONVERT",
789 op->convert.expand ?
" (expand)" :
"");
792 av_log(
log,
lev,
"%-20s: %dx%d matrix + {%d %d %d %d}\n",
"SWS_OP_DITHER",
793 1 <<
op->dither.size_log2, 1 <<
op->dither.size_log2,
794 op->dither.y_offset[0],
op->dither.y_offset[1],
795 op->dither.y_offset[2],
op->dither.y_offset[3]);
798 av_log(
log,
lev,
"%-20s: x <= {%s %s %s %s}\n",
"SWS_OP_MIN",
805 av_log(
log,
lev,
"%-20s: {%s %s %s %s} <= x\n",
"SWS_OP_MAX",
815 "[%s %s %s %s %s]]\n",
830 if (
op->comps.min[0].den ||
op->comps.min[1].den ||
831 op->comps.min[2].den ||
op->comps.min[3].den ||
832 op->comps.max[0].den ||
op->comps.max[1].den ||
833 op->comps.max[2].den ||
op->comps.max[3].den)
835 av_log(
log, lev_extra,
" min: {%s, %s, %s, %s}, max: {%s, %s, %s, %s}\n",
848 av_log(
log,
lev,
" (X = unused, z = byteswapped, + = exact, 0 = zero)\n");
872 av_log(
ctx, msg_lev,
"Backend '%s' failed to compile operations: %s\n",
875 av_log(
ctx, msg_lev,
"Uncompiled remainder:\n");
897 "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n",
898 backend->
name,
out->block_size,
out->over_read,
out->over_write,
908 typedef struct SwsOpPass {
926 static void op_pass_free(
void *ptr)
933 p->comp.free(
p->comp.priv);
939 const int plane_idx[4])
942 for (
int i = 0;
i < 4;
i++) {
943 const int idx = plane_idx[
i];
946 img.data[
i] =
base->data[idx] + yshift *
base->linesize[idx];
954 static void op_pass_setup(
const SwsImg *out_base,
const SwsImg *in_base,
960 SwsOpPass *
p = pass->
priv;
963 const int block_size =
comp->block_size;
964 p->num_blocks = (pass->
width + block_size - 1) / block_size;
967 const int aligned_w =
p->num_blocks * block_size;
968 const int safe_width = (
p->num_blocks - 1) * block_size;
969 const int tail_size = pass->
width - safe_width;
970 p->tail_off_in = safe_width *
p->pixel_bits_in >> 3;
971 p->tail_off_out = safe_width *
p->pixel_bits_out >> 3;
972 p->tail_size_in = tail_size *
p->pixel_bits_in >> 3;
973 p->tail_size_out = tail_size *
p->pixel_bits_out >> 3;
974 p->memcpy_in =
false;
975 p->memcpy_out =
false;
977 const SwsImg in = img_shift_idx(in_base, 0,
p->idx_in);
978 const SwsImg out = img_shift_idx(out_base, 0,
p->idx_out);
983 for (
int i = 0;
i <
p->planes_in;
i++) {
984 const int idx =
p->idx_in[
i];
985 const int sub_x = (idx == 1 || idx == 2) ? indesc->
log2_chroma_w : 0;
986 const int plane_w = (aligned_w + sub_x) >> sub_x;
987 const int plane_pad = (
comp->over_read + sub_x) >> sub_x;
988 const int plane_size = plane_w *
p->pixel_bits_in >> 3;
989 if (
comp->slice_align)
990 p->memcpy_in |= plane_size + plane_pad > in.
linesize[
i];
994 for (
int i = 0;
i <
p->planes_out;
i++) {
995 const int idx =
p->idx_out[
i];
996 const int sub_x = (idx == 1 || idx == 2) ? outdesc->
log2_chroma_w : 0;
997 const int plane_w = (aligned_w + sub_x) >> sub_x;
998 const int plane_pad = (
comp->over_write + sub_x) >> sub_x;
999 const int plane_size = plane_w *
p->pixel_bits_out >> 3;
1000 if (
comp->slice_align)
1001 p->memcpy_out |= plane_size + plane_pad >
out.linesize[
i];
1008 const int blocks_main =
p->num_blocks -
p->memcpy_out;
1009 for (
int i = 0;
i < 4;
i++) {
1017 handle_tail(
const SwsOpPass *
p,
SwsOpExec *exec,
1018 const SwsImg *out_base,
const bool copy_out,
1019 const SwsImg *in_base,
const bool copy_in,
1025 const int tail_size_in =
p->tail_size_in;
1026 const int tail_size_out =
p->tail_size_out;
1027 const int bx =
p->num_blocks - 1;
1029 SwsImg in = img_shift_idx(in_base, y,
p->idx_in);
1030 SwsImg out = img_shift_idx(out_base, y,
p->idx_out);
1031 for (
int i = 0;
i <
p->planes_in;
i++) {
1032 in.
data[
i] +=
p->tail_off_in;
1034 exec->
in[
i] = (
void *)
tmp[0][
i];
1041 for (
int i = 0;
i <
p->planes_out;
i++) {
1042 out.data[
i] +=
p->tail_off_out;
1051 for (
int y_end = y +
h; y < y_end; y++) {
1053 for (
int i = 0;
i <
p->planes_in;
i++) {
1055 memcpy(
tmp[0][
i], in.
data[
i], tail_size_in);
1060 comp->func(exec,
comp->priv, bx, y,
p->num_blocks, y + 1);
1063 for (
int i = 0;
i <
p->planes_out;
i++) {
1065 memcpy(
out.data[
i],
tmp[1][
i], tail_size_out);
1070 for (
int i = 0;
i < 4;
i++) {
1071 if (!copy_in && exec->
in[
i])
1073 if (!copy_out && exec->
out[
i])
1079 static void op_pass_run(
const SwsImg *out_base,
const SwsImg *in_base,
1080 const int y,
const int h,
const SwsPass *pass)
1082 const SwsOpPass *
p = pass->
priv;
1084 const SwsImg in = img_shift_idx(in_base, y,
p->idx_in);
1085 const SwsImg out = img_shift_idx(out_base, y,
p->idx_out);
1091 for (
int i = 0;
i < 4;
i++) {
1116 const int last_slice = y +
h == pass->
height;
1117 const bool memcpy_in = last_slice &&
p->memcpy_in;
1118 const bool memcpy_out =
p->memcpy_out;
1119 const int num_blocks =
p->num_blocks;
1120 const int blocks_main = num_blocks - memcpy_out;
1121 const int h_main =
h - memcpy_in;
1124 comp->func(&exec,
comp->priv, 0, y, blocks_main, y + h_main);
1128 for (
int i = 0;
i < 4;
i++) {
1130 exec.
out[
i] += h_main *
out.linesize[
i];
1132 comp->func(&exec,
comp->priv, 0, y + h_main, num_blocks - 1, y +
h);
1137 handle_tail(
p, &exec, out_base,
true, in_base,
false, y, h_main);
1139 handle_tail(
p, &exec, out_base, memcpy_out, in_base,
true, y + h_main, 1);
1142 static int rw_planes(
const SwsOp *
op)
1144 return op->rw.packed ? 1 :
op->rw.elems;
1149 const int elems =
op->rw.packed ?
op->rw.elems : 1;
1151 const int bits = 8 >>
op->rw.frac;
1160 SwsOpPass *
p =
NULL;
1179 "and write, respectively.\n");
1196 p->planes_in = rw_planes(
read);
1197 p->planes_out = rw_planes(write);
1202 .height =
dst.height,
1203 .block_size_in =
p->comp.block_size *
p->pixel_bits_in >> 3,
1204 .block_size_out =
p->comp.block_size *
p->pixel_bits_out >> 3,
1207 for (
int i = 0;
i < 4;
i++) {
1213 p->comp.slice_align,
p, op_pass_run);
1218 pass->
setup = op_pass_setup;
1219 pass->
free = op_pass_free;
void ff_sws_op_list_free(SwsOpList **p_ops)
#define AV_LOG_WARNING
Something somehow does not look correct.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Represents a single filter pass in the scaling graph.
SwsOpList * ff_sws_op_list_alloc(void)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
static AVRational av_min_q(AVRational a, AVRational b)
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
uint32_t ff_sws_linear_mask(const SwsLinearOp c)
int ff_sws_op_list_max_size(const SwsOpList *ops)
Returns the size of the largest pixel type used in ops.
const SwsOpBackend backend_x86
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
These will take over ownership of op and set it to {0}, even on failure.
const SwsOpBackend backend_vulkan
const AVFrame * frame_ptr
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
#define AV_LOG_VERBOSE
Detailed information.
void(* free)(void *priv)
Optional private state and associated free() function.
Represents a view into a single field of frame data.
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
int ff_sws_pixel_type_size(SwsPixelType type)
static char describe_comp_flags(unsigned flags)
static void clear_undefined_values(AVRational dst[4], const AVRational src[4])
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
#define DECLARE_ALIGNED_64(t, v)
SwsPixelType
Copyright (C) 2025 Niklas Haas.
void ff_sws_op_list_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
const SwsOpBackend *const ff_sws_op_backends[]
static const unsigned flags_identity
int(* compile)(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
Compile an operation list to an implementation chain.
bool ff_sws_pixel_type_is_int(SwsPixelType type)
static double val(void *priv, double ch)
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Attempt to compile a list of operations using a specific backend.
static int16_t mult(Float11 *f1, Float11 *f2)
const AVFrame * src_frame_ptr
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define FF_ARRAY_ELEMS(a)
#define SWS_SWIZZLE(X, Y, Z, W)
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.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
void(* setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Called once from the main thread before running the filter.
static AVFormatContext * ctx
static AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
static const char * describe_order(SwsSwizzleOp order, int planes, char buf[32])
Global execution context for all compiled functions.
static unsigned merge_comp_flags(unsigned a, unsigned b)
bool ff_sws_op_list_is_noop(const SwsOpList *ops)
Returns whether an op list represents a true no-op operation, i.e.
SwsPass * ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int align, void *priv, sws_filter_run_t run)
Allocate and add a new pass to the filter graph.
static int rw_pixel_bits(const SwsOp *op)
Rational number (pair of numerator and denominator).
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
static const char * print_q(const AVRational q, char buf[], int buf_len)
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
Apply an operation to an AVRational.
static void copy(const float *p1, float *p2, const int length)
static int shift(int a, int b)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
#define i(width, name, range_min, range_max)
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
static AVRational av_make_q(int num, int den)
Create an AVRational.
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
static void op_uninit(SwsOp *op)
SwsComps comps
Metadata about the operation's input/output components.
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
int ff_sws_op_list_optimize(SwsOpList *ops)
Fuse compatible and eliminate redundant operations, as well as replacing some operations with more ef...
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane)
static AVRational av_max_q(AVRational a, AVRational b)
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
#define DECLARE_ALIGNED_32(t, v)
int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Compile a list of operations using the best available backend.
static LevelCodes lev[4+3+3]
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
const SwsOpBackend backend_murder
#define FFSWAP(type, a, b)
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes,...
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, SwsFormat dst, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
const char * ff_sws_pixel_type_name(SwsPixelType type)
static const struct @554 planes[]
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
static const char * describe_lin_mask(uint32_t mask)
Filter graph, which represents a 'baked' pixel format conversion.
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
static void scale(int *out, const int *in, const int w, const int h, const int shift)
AVRational av_add_q(AVRational b, AVRational c)
Add two rationals.
static void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int shift[4])
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
static void propagate_flags(SwsOp *op, const SwsComps *prev)
Helper struct for representing a list of operations.
Main external API structure.
const AVFrame * dst_frame_ptr
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.