Go to the documentation of this file.
29 #if IS_FLOAT && BIT_DEPTH == 32
30 # define PIXEL_TYPE SWS_PIXEL_F32
31 # define pixel_t float
32 # define inter_t float
33 # define vec3_t v3f32_t
37 # define PIXEL_MAX 0xFFFFFFFFu
38 # define PIXEL_SWAP av_bswap32
39 # define pixel_t uint32_t
40 # define inter_t int64_t
44 # define PIXEL_MAX 0xFFFFu
45 # define PIXEL_SWAP av_bswap16
46 # define pixel_t uint16_t
47 # define inter_t int64_t
51 # define PIXEL_MAX 0xFFu
52 # define pixel_t uint8_t
53 # define inter_t int32_t
57 # error Invalid BIT_DEPTH
84 const int elems =
W ? 4 :
Z ? 3 :
Y ? 2 : 1;
88 if (
X) x[
i] = in0[elems *
i + 0];
89 if (
Y) y[
i] = in0[elems *
i + 1];
90 if (
Z) z[
i] = in0[elems *
i + 2];
91 if (
W)
w[
i] = in0[elems *
i + 3];
102 if (
X) out0[
i] = x[
i];
103 if (
Y) out1[
i] = y[
i];
104 if (
Z) out2[
i] = z[
i];
105 if (
W) out3[
i] =
w[
i];
116 const int elems =
W ? 4 :
Z ? 3 :
Y ? 2 : 1;
120 if (
X) out0[elems *
i + 0] = x[
i];
121 if (
Y) out0[elems *
i + 1] = y[
i];
122 if (
Z) out0[elems *
i + 2] = z[
i];
123 if (
W) out0[elems *
i + 3] =
w[
i];
138 x[
i + 0] = (
val >> 7) & 1;
139 x[
i + 1] = (
val >> 6) & 1;
140 x[
i + 2] = (
val >> 5) & 1;
141 x[
i + 3] = (
val >> 4) & 1;
142 x[
i + 4] = (
val >> 3) & 1;
143 x[
i + 5] = (
val >> 2) & 1;
144 x[
i + 6] = (
val >> 1) & 1;
145 x[
i + 7] = (
val >> 0) & 1;
160 x[
i + 1] =
val & 0xF;
191 out0[
i >> 3] = x[
i + 0] << 7 |
210 out0[
i >> 1] = x[
i] << 4 | x[
i + 1];
247 static_assert(
sizeof(
out->priv.ptr) <=
sizeof(
int32_t[2]),
248 ">8 byte pointers not supported");
255 for (
int i = 0;
i <
filter->num_weights;
i++)
269 const float *restrict
weights = impl->priv.ptr;
270 const int filter_size = impl->priv.i32[2];
271 weights += filter_size * iter->y;
274 if (
X) memset(&
xs.f32, 0,
sizeof(
xs.f32));
275 if (
Y) memset(&ys.
f32, 0,
sizeof(ys.
f32));
276 if (
Z) memset(&zs.
f32, 0,
sizeof(zs.
f32));
277 if (
W) memset(&ws.
f32, 0,
sizeof(ws.
f32));
279 for (
int j = 0; j < filter_size; j++) {
321 const int *restrict
weights = impl->priv.ptr;
322 const int filter_size = impl->priv.i32[2];
324 const int xpos = iter->x;
325 weights += filter_size * iter->x;
335 inter_t sx = 0, sy = 0, sz = 0, sw = 0;
336 for (
int j = 0; j < filter_size; j++) {
338 if (
X) sx +=
weight * start0[j];
339 if (
Y) sy +=
weight * start1[j];
340 if (
Z) sz +=
weight * start2[j];
341 if (
W) sw +=
weight * start3[j];
365 int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5,
366 int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5)
372 for (
int n = 0; n < num_moves; n++)
373 ptr[
dst[n] + 1] = ptr[
src[n] + 1];
385 int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5,
386 int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5)
393 memcpy(&
data[1].
px, x, block_size);
394 memcpy(&
data[2].
px, y, block_size);
395 memcpy(&
data[3].
px, z, block_size);
396 memcpy(&
data[4].
px,
w, block_size);
398 for (
int n = 0; n < num_moves; n++)
401 memcpy(x, &
data[1].
px, block_size);
402 memcpy(y, &
data[2].
px, block_size);
403 memcpy(z, &
data[3].
px, block_size);
404 memcpy(
w, &
data[4].
px, block_size);
418 #define DECL_CAST(DST, dst) \
419 DECL_FUNC(to_##dst, const SwsCompMask mask) \
421 block_t xx, yy, zz, ww; \
424 for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \
425 if (X) xx.dst[i] = x[i]; \
426 if (Y) yy.dst[i] = y[i]; \
427 if (Z) zz.dst[i] = z[i]; \
428 if (W) ww.dst[i] = w[i]; \
431 CONTINUE(&xx, &yy, &zz, &ww); \
434 SWS_FOR(PX, TO_##DST, DECL_IMPL, to_##dst) \
435 SWS_FOR_STRUCT(PX, TO_##DST, DECL_ENTRY)
451 if (
X) x[
i] <<= amount;
452 if (
Y) y[
i] <<= amount;
453 if (
Z) z[
i] <<= amount;
454 if (
W)
w[
i] <<= amount;
464 if (
X) x[
i] >>= amount;
465 if (
Y) y[
i] >>= amount;
466 if (
Z) z[
i] >>= amount;
467 if (
W)
w[
i] >>= amount;
485 if (
X) x[
i] = PIXEL_SWAP(x[
i]);
486 if (
Y) y[
i] = PIXEL_SWAP(y[
i]);
487 if (
Z) z[
i] = PIXEL_SWAP(z[
i]);
488 if (
W)
w[
i] = PIXEL_SWAP(
w[
i]);
520 if (
X) x16.
u16[
i] = x[
i] << 8 | x[
i];
521 if (
Y) y16.
u16[
i] = y[
i] << 8 | y[
i];
522 if (
Z) z16.
u16[
i] = z[
i] << 8 | z[
i];
535 if (
X) x32.
u32[
i] = (uint32_t) x[
i] << 24 | x[
i] << 16 | x[
i] << 8 | x[
i];
536 if (
Y) y32.
u32[
i] = (uint32_t) y[
i] << 24 | y[
i] << 16 | y[
i] << 8 | y[
i];
537 if (
Z) z32.
u32[
i] = (uint32_t) z[
i] << 24 | z[
i] << 16 | z[
i] << 8 | z[
i];
538 if (
W) w32.
u32[
i] = (uint32_t)
w[
i] << 24 |
w[
i] << 16 |
w[
i] << 8 |
w[
i];
558 const uint8_t bx,
const uint8_t by,
559 const uint8_t bz,
const uint8_t bw)
561 const uint8_t sx = bw + bz + by;
562 const uint8_t sy = bw + bz;
563 const uint8_t sz = bw;
564 const uint8_t sw = 0;
569 const pixel_t mw = (1 << bw) - 1;
574 if (
X) x[
i] = (
val >> sx) &
mx;
575 if (
Y) y[
i] = (
val >> sy) &
my;
576 if (
Z) z[
i] = (
val >> sz) &
mz;
577 if (
W)
w[
i] = (
val >> sw) & mw;
584 const uint8_t bx,
const uint8_t by,
585 const uint8_t bz,
const uint8_t bw)
587 const uint8_t sx = bw + bz + by;
588 const uint8_t sy = bw + bz;
589 const uint8_t sz = bw;
590 const uint8_t sw = 0;
595 if (
X)
val |= x[
i] << sx;
596 if (
Y)
val |= y[
i] << sy;
597 if (
Z)
val |= z[
i] << sz;
619 #define ONE(N) SWS_COMP_TEST(one, N)
620 #define ZERO(N) SWS_COMP_TEST(zero, N)
664 if (
X) x[
i] += impl->priv.px[0];
665 if (
Y) y[
i] += impl->priv.px[1];
666 if (
Z) z[
i] += impl->priv.px[2];
667 if (
W)
w[
i] += impl->priv.px[3];
677 if (
X) x[
i] =
FFMIN(x[
i], impl->priv.px[0]);
678 if (
Y) y[
i] =
FFMIN(y[
i], impl->priv.px[1]);
679 if (
Z) z[
i] =
FFMIN(z[
i], impl->priv.px[2]);
690 if (
X) x[
i] =
FFMAX(x[
i], impl->priv.px[0]);
691 if (
Y) y[
i] =
FFMAX(y[
i], impl->priv.px[1]);
692 if (
Z) z[
i] =
FFMAX(z[
i], impl->priv.px[2]);
735 for (
int y = 0; y <
height; y++) {
737 for (
int x = 0; x <
size; x++)
740 row[x] = row[x %
size];
747 const uint8_t off0,
const uint8_t off1,
748 const uint8_t off2,
const uint8_t off3,
749 const uint8_t size_log2)
751 const int size = 1 << size_log2;
765 if (
X) x[
i] += row0[
i];
766 if (
Y) y[
i] += row1[
i];
767 if (
Z) z[
i] += row2[
i];
768 if (
W)
w[
i] += row3[
i];
792 for (
int i = 0;
i < 4;
i++) {
793 for (
int j = 0; j < 4; j++)
811 const fn(LinCoeffs)
c = *(
const fn(LinCoeffs) *) impl->priv.ptr;
820 #define LIN_VAL(I, J, val) \
821 ((one & SWS_MASK(I, J)) ? (val) : c.m[I][J] * (val))
823 #define LIN_ROW(I, var) do { \
824 var[i] = (zero & SWS_MASK(I, 4)) ? 0 : c.k[I]; \
825 if (!(zero & SWS_MASK(I, 0))) var[i] += LIN_VAL(I, 0, xx); \
826 if (!(zero & SWS_MASK(I, 1))) var[i] += LIN_VAL(I, 1, yy); \
827 if (!(zero & SWS_MASK(I, 2))) var[i] += LIN_VAL(I, 2, zz); \
828 if (!(zero & SWS_MASK(I, 3))) var[i] += LIN_VAL(I, 3, ww); \
858 return (vec3_t) { v.x, v.y, v.z };
861 #define lerp(a, b, w) ((a) + (w) * ((pixel_t) (b) - (a)))
874 vec3_t
fn(lut3d_static)(
const SwsLut3D *restrict lut3d, vec3_t
rgb)
876 const int r_base = (int)
rgb.x;
877 const int g_base = (
int)
rgb.y;
878 const int b_base = (int)
rgb.z;
907 const v3u16_t *restrict
base = &lut3d->input[b_base][g_base][r_base];
908 const vec3_t v0 =
fn(vec3)(
base[0]);
909 const vec3_t v1 =
fn(vec3)(
base[off0]);
910 const vec3_t v2 =
fn(vec3)(
base[off0 + off1]);
911 const vec3_t v3 =
fn(vec3)(
base[off0 + off1 + off2]);
914 w0 * v0.x + w1 * v1.x + w2 * v2.x + w3 * v3.x,
915 w0 * v0.y + w1 * v1.y + w2 * v2.y + w3 * v3.y,
916 w0 * v0.z + w1 * v1.z + w2 * v2.z + w3 * v3.z,
921 vec3_t
fn(lut3d_dynamic)(
const SwsLut3D *restrict lut3d, vec3_t
rgb)
926 const int Ix = (int)
rgb.x;
929 const v2u16_t a = lut3d->tone_map[Ix];
930 const v2u16_t b = lut3d->tone_map[Ix + 1];
946 const int lo0 = (int)
rgb.x;
947 const int lo1 = (
int)
rgb.y;
948 const int lo2 = (int)
rgb.z;
955 const vec3_t c000 =
fn(vec3)(lut3d->output[lo2][lo1][lo0]);
956 const vec3_t c001 =
fn(vec3)(lut3d->output[lo2][lo1][hi0]);
957 const vec3_t c00 =
fn(lerp3)(c000, c001, w0);
958 const vec3_t c010 =
fn(vec3)(lut3d->output[lo2][hi1][lo0]);
959 const vec3_t c011 =
fn(vec3)(lut3d->output[lo2][hi1][hi0]);
960 const vec3_t c01 =
fn(lerp3)(c010, c011, w0);
961 const vec3_t c100 =
fn(vec3)(lut3d->output[hi2][lo1][lo0]);
962 const vec3_t c101 =
fn(vec3)(lut3d->output[hi2][lo1][hi0]);
963 const vec3_t c10 =
fn(lerp3)(c100, c101, w0);
964 const vec3_t c110 =
fn(vec3)(lut3d->output[hi2][hi1][lo0]);
965 const vec3_t c111 =
fn(vec3)(lut3d->output[hi2][hi1][hi0]);
966 const vec3_t c11 =
fn(lerp3)(c110, c111, w0);
969 const vec3_t c0 =
fn(lerp3)(c00, c01, w1);
970 const vec3_t
c1 =
fn(lerp3)(c10, c11, w1);
973 return fn(lerp3)(c0,
c1, w2);
978 const SwsLut3D *restrict lut3d = impl->priv.ptr;
982 vec3_t
c = { x[
i], y[
i], z[
i] };
983 c =
fn(lut3d_static)(lut3d,
c);
985 c =
fn(lut3d_dynamic)(lut3d,
c);
#define DECL_IMPL_WRITE(...)
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
float f32[SWS_BLOCK_SIZE]
#define DECL_ENTRY(SETUP, NAME,...)
Represents a computed filter kernel.
static void permute(int16_t dst[64], const int16_t src[64], enum idct_permutation_type perm_type)
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
void(* filter)(uint8_t *src, int stride, int qscale)
static void ff_op_priv_unref(SwsOpPriv *priv)
static int setup_linear(const SwsImplParams *params, SwsImplResult *out)
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
static int setup_dither(const SwsImplParams *params, SwsImplResult *out)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t mx
DECL_WRITE(write_planar, const SwsCompMask mask)
const h264_weight_func weight
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
#define SWS_COMP_ELEMS(N)
#define SWS_FOR(TYPE, UOP, MACRO,...)
#define SWS_FOR_STRUCT(TYPE, UOP, MACRO,...)
static const uint16_t dither[8][8]
uint8_t SwsCompMask
Bit-mask of components.
SwsAArch64OpImplParams params
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t my
static unsigned int BS_FUNC() read_bit(BSCTX *bc)
Return one bit from the buffer.
Copyright (C) 2026 Niklas Haas.
#define xs(width, name, var, subs,...)
static int bias(int x, int c)
#define DECL_IMPL(FUNC, NAME, TYPE, UOP,...)
#define SWS_BLOCK_SIZE
Copyright (C) 2026 Niklas Haas.
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
int ff_sws_setup_vec4(const SwsImplParams *params, SwsImplResult *out)
static void copy(const float *p1, float *p2, const int length)
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)
static double mz(int i, double w0, double r, double alpha)
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 double lerp(double a, double b, double x)
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 offset
static int zero(InterplayACMContext *s, unsigned ind, unsigned col)
DECL_FUNC(permute, const SwsCompMask mask, int num_moves, int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5)
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Append a set of operations for applying a gamut/tone mapping 3D LUT to the pixels.
static int unpack(const uint8_t *src, const uint8_t *src_end, uint8_t *dst, int width, int height)
Unpack buffer.
int32_t * in_offset_x
Pixel offset map; for horizontal scaling, in bytes.
static const int weights[]
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 value
void * av_calloc(size_t nmemb, size_t size)
static void ff_op_priv_free(SwsOpPriv *priv)
#define FFSWAP(type, a, b)
#define bump_ptr(ptr, bump)
DECL_SETUP(setup_filter_v, params, out)
#define DECL_CAST(DST, dst)
uint32_t u32[SWS_BLOCK_SIZE]
const void * av_refstruct_ref_c(const void *obj)
Analog of av_refstruct_ref(), but for constant objects.
int ff_sws_setup_scalar(const SwsImplParams *params, SwsImplResult *out)
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
uint16_t u16[SWS_BLOCK_SIZE]
static void scale(int *out, const int *in, const int w, const int h, const int shift)
static int setup_filter_v(const SwsImplParams *params, SwsImplResult *out)
DECL_READ(read_planar, const SwsCompMask mask)
static const SheerTable rgb[2]
int ff_sws_dither_height(const SwsDitherUOp *dither)
Computes (1 << size_log2) + MAX(y_offset).
#define DECL_IMPL_READ(...)
static int setup_filter_h(const SwsImplParams *params, SwsImplResult *out)