FFmpeg
ops_impl_conv.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2026 Ramiro Polla
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * NOTE: This file is #include'd directly by both the NEON backend and
23  * the sws_ops_aarch64 tool.
24  */
25 
26 #include "libavutil/error.h"
27 #include "libavutil/rational.h"
28 #include "libswscale/ops.h"
29 
30 #include "ops_impl.h"
31 
33 {
34  switch (type) {
35  case SWS_PIXEL_U8: return AARCH64_PIXEL_U8;
36  case SWS_PIXEL_U16: return AARCH64_PIXEL_U16;
37  case SWS_PIXEL_U32: return AARCH64_PIXEL_U32;
38  case SWS_PIXEL_F32: return AARCH64_PIXEL_F32;
39  }
40  return 0;
41 }
42 
43 /**
44  * The column index order for SwsLinearOp.mask follows the affine transform
45  * order, where the offset is the last element. SwsAArch64LinearOpMask, on
46  * the other hand, follows execution order, where the offset is the first
47  * element.
48  */
49 static int linear_index_from_sws_op(int idx)
50 {
51  const int reorder_col[5] = { 1, 2, 3, 4, 0 };
52  return reorder_col[idx];
53 }
54 
55 /**
56  * Convert SwsOp to a SwsAArch64OpImplParams. Read the comments regarding
57  * SwsAArch64OpImplParams in ops_impl.h for more information.
58  */
59 static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
60  int block_size, SwsAArch64OpImplParams *out)
61 {
62  const SwsOp *op = &ops->ops[n];
63  const SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : op;
64 
65  out->block_size = block_size;
66 
67  /**
68  * Most SwsOp work on fields described by next->comps.unused.
69  * The few that don't will override this field later.
70  */
71  out->mask = 0;
72  for (int i = 0; i < 4; i++) {
73  if (!next->comps.unused[i])
74  MASK_SET(out->mask, i, 1);
75  }
76 
77  out->type = sws_pixel_to_aarch64(op->type);
78 
79  /* Map SwsOpType to SwsAArch64OpType */
80  switch (op->op) {
81  case SWS_OP_READ:
82  if (op->rw.filter)
83  return AVERROR(ENOTSUP);
84  /**
85  * The different types of read operations have been split into
86  * their own SwsAArch64OpType to simplify the implementation.
87  */
88  if (op->rw.frac == 1)
90  else if (op->rw.frac == 3)
92  else if (op->rw.packed && op->rw.elems != 1)
94  else
96  break;
97  case SWS_OP_WRITE:
98  if (op->rw.filter)
99  return AVERROR(ENOTSUP);
100  /**
101  * The different types of write operations have been split into
102  * their own SwsAArch64OpType to simplify the implementation.
103  */
104  if (op->rw.frac == 1)
106  else if (op->rw.frac == 3)
108  else if (op->rw.packed && op->rw.elems != 1)
110  else
112  break;
114  case SWS_OP_SWIZZLE: out->op = AARCH64_SWS_OP_SWIZZLE; break;
115  case SWS_OP_UNPACK: out->op = AARCH64_SWS_OP_UNPACK; break;
116  case SWS_OP_PACK: out->op = AARCH64_SWS_OP_PACK; break;
117  case SWS_OP_LSHIFT: out->op = AARCH64_SWS_OP_LSHIFT; break;
118  case SWS_OP_RSHIFT: out->op = AARCH64_SWS_OP_RSHIFT; break;
119  case SWS_OP_CLEAR: out->op = AARCH64_SWS_OP_CLEAR; break;
120  case SWS_OP_CONVERT:
121  out->op = op->convert.expand ? AARCH64_SWS_OP_EXPAND : AARCH64_SWS_OP_CONVERT;
122  break;
123  case SWS_OP_MIN: out->op = AARCH64_SWS_OP_MIN; break;
124  case SWS_OP_MAX: out->op = AARCH64_SWS_OP_MAX; break;
125  case SWS_OP_SCALE: out->op = AARCH64_SWS_OP_SCALE; break;
126  case SWS_OP_LINEAR: out->op = AARCH64_SWS_OP_LINEAR; break;
127  case SWS_OP_DITHER: out->op = AARCH64_SWS_OP_DITHER; break;
128  }
129 
130  switch (out->op) {
139  switch (op->rw.elems) {
140  case 1: out->mask = 0x0001; break;
141  case 2: out->mask = 0x0011; break;
142  case 3: out->mask = 0x0111; break;
143  case 4: out->mask = 0x1111; break;
144  };
145  break;
147  /* Only the element size matters, not the type. */
148  if (out->type == AARCH64_PIXEL_F32)
149  out->type = AARCH64_PIXEL_U32;
150  break;
152  out->mask = 0;
153  MASK_SET(out->mask, 0, op->swizzle.in[0] != 0);
154  MASK_SET(out->mask, 1, op->swizzle.in[1] != 1);
155  MASK_SET(out->mask, 2, op->swizzle.in[2] != 2);
156  MASK_SET(out->mask, 3, op->swizzle.in[3] != 3);
157  MASK_SET(out->swizzle, 0, op->swizzle.in[0]);
158  MASK_SET(out->swizzle, 1, op->swizzle.in[1]);
159  MASK_SET(out->swizzle, 2, op->swizzle.in[2]);
160  MASK_SET(out->swizzle, 3, op->swizzle.in[3]);
161  /* The element size and type don't matter. */
162  out->block_size = block_size * ff_sws_pixel_type_size(op->type);
163  out->type = AARCH64_PIXEL_U8;
164  break;
166  MASK_SET(out->pack, 0, op->pack.pattern[0]);
167  MASK_SET(out->pack, 1, op->pack.pattern[1]);
168  MASK_SET(out->pack, 2, op->pack.pattern[2]);
169  MASK_SET(out->pack, 3, op->pack.pattern[3]);
170  break;
171  case AARCH64_SWS_OP_PACK:
172  out->mask = 0;
173  MASK_SET(out->mask, 0, !op->comps.unused[0]);
174  MASK_SET(out->mask, 1, !op->comps.unused[1]);
175  MASK_SET(out->mask, 2, !op->comps.unused[2]);
176  MASK_SET(out->mask, 3, !op->comps.unused[3]);
177  MASK_SET(out->pack, 0, op->pack.pattern[0]);
178  MASK_SET(out->pack, 1, op->pack.pattern[1]);
179  MASK_SET(out->pack, 2, op->pack.pattern[2]);
180  MASK_SET(out->pack, 3, op->pack.pattern[3]);
181  break;
184  out->shift = op->c.u;
185  break;
187  out->mask = 0;
188  MASK_SET(out->mask, 0, !!op->c.q4[0].den);
189  MASK_SET(out->mask, 1, !!op->c.q4[1].den);
190  MASK_SET(out->mask, 2, !!op->c.q4[2].den);
191  MASK_SET(out->mask, 3, !!op->c.q4[3].den);
192  break;
195  out->to_type = sws_pixel_to_aarch64(op->convert.to);
196  break;
198  /**
199  * The out->linear.mask field packs the 4x5 matrix from SwsLinearOp as
200  * 2 bits per element:
201  * 00: m[i][j] == 0
202  * 01: m[i][j] == 1
203  * 11: m[i][j] is any other coefficient
204  */
205  out->mask = 0;
206  for (int i = 0; i < 4; i++) {
207  /* Skip unused or identity rows */
208  if (op->comps.unused[i] || !(op->lin.mask & SWS_MASK_ROW(i)))
209  continue;
210  MASK_SET(out->mask, i, 1);
211  for (int j = 0; j < 5; j++) {
212  int jj = linear_index_from_sws_op(j);
213  if (!av_cmp_q(op->lin.m[i][j], av_make_q(1, 1)))
214  LINEAR_MASK_SET(out->linear.mask, i, jj, LINEAR_MASK_1);
215  else if (av_cmp_q(op->lin.m[i][j], av_make_q(0, 1)))
216  LINEAR_MASK_SET(out->linear.mask, i, jj, LINEAR_MASK_X);
217  }
218  }
219  out->linear.fmla = !(ctx->flags & SWS_BITEXACT);
220  break;
222  out->mask = 0;
223  MASK_SET(out->mask, 0, op->dither.y_offset[0] >= 0);
224  MASK_SET(out->mask, 1, op->dither.y_offset[1] >= 0);
225  MASK_SET(out->mask, 2, op->dither.y_offset[2] >= 0);
226  MASK_SET(out->mask, 3, op->dither.y_offset[3] >= 0);
227  MASK_SET(out->dither.y_offset, 0, op->dither.y_offset[0]);
228  MASK_SET(out->dither.y_offset, 1, op->dither.y_offset[1]);
229  MASK_SET(out->dither.y_offset, 2, op->dither.y_offset[2]);
230  MASK_SET(out->dither.y_offset, 3, op->dither.y_offset[3]);
231  out->dither.size_log2 = op->dither.size_log2;
232  break;
233  }
234 
235  return 0;
236 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:50
AARCH64_SWS_OP_MIN
@ AARCH64_SWS_OP_MIN
Definition: ops_impl.h:59
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: ops.h:36
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:53
AVERROR
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
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:58
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:56
out
static FILE * out
Definition: movenc.c:55
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:62
SwsComps::unused
bool unused[4]
Definition: ops.h:102
rational.h
ops_impl.h
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:70
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:157
AARCH64_SWS_OP_SWIZZLE
@ AARCH64_SWS_OP_SWIZZLE
Definition: ops_impl.h:51
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: ops.h:37
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:68
AARCH64_SWS_OP_CLEAR
@ AARCH64_SWS_OP_CLEAR
Definition: ops_impl.h:56
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:186
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:33
AARCH64_SWS_OP_READ_NIBBLE
@ AARCH64_SWS_OP_READ_NIBBLE
Definition: ops_impl.h:43
AARCH64_SWS_OP_PACK
@ AARCH64_SWS_OP_PACK
Definition: ops_impl.h:53
AARCH64_SWS_OP_SWAP_BYTES
@ AARCH64_SWS_OP_SWAP_BYTES
Definition: ops_impl.h:50
AARCH64_SWS_OP_READ_BIT
@ AARCH64_SWS_OP_READ_BIT
Definition: ops_impl.h:42
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
AARCH64_SWS_OP_MAX
@ AARCH64_SWS_OP_MAX
Definition: ops_impl.h:60
SwsOpList::num_ops
int num_ops
Definition: ops.h:256
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: ops.h:35
type
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
Definition: writing_filters.txt:86
LINEAR_MASK_1
#define LINEAR_MASK_1
Definition: ops_impl.h:129
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:66
sws_pixel_to_aarch64
static uint8_t sws_pixel_to_aarch64(SwsPixelType type)
NOTE: This file is #include'd directly by both the NEON backend and the sws_ops_aarch64 tool.
Definition: ops_impl_conv.c:32
AARCH64_SWS_OP_WRITE_NIBBLE
@ AARCH64_SWS_OP_WRITE_NIBBLE
Definition: ops_impl.h:47
AARCH64_SWS_OP_DITHER
@ AARCH64_SWS_OP_DITHER
Definition: ops_impl.h:63
AARCH64_SWS_OP_RSHIFT
@ AARCH64_SWS_OP_RSHIFT
Definition: ops_impl.h:55
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1414
AARCH64_SWS_OP_LINEAR
@ AARCH64_SWS_OP_LINEAR
Definition: ops_impl.h:62
op
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.
Definition: anm.c:76
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:64
AARCH64_SWS_OP_CONVERT
@ AARCH64_SWS_OP_CONVERT
Definition: ops_impl.h:57
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:69
AARCH64_PIXEL_F32
@ AARCH64_PIXEL_F32
Definition: ops_impl.h:33
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:57
AARCH64_SWS_OP_SCALE
@ AARCH64_SWS_OP_SCALE
Definition: ops_impl.h:61
LINEAR_MASK_SET
#define LINEAR_MASK_SET(mask, idx, jdx, val)
Definition: ops_impl.h:125
AARCH64_SWS_OP_READ_PACKED
@ AARCH64_SWS_OP_READ_PACKED
Definition: ops_impl.h:44
LINEAR_MASK_X
#define LINEAR_MASK_X
Definition: ops_impl.h:130
error.h
linear_index_from_sws_op
static int linear_index_from_sws_op(int idx)
The column index order for SwsLinearOp.mask follows the affine transform order, where the offset is t...
Definition: ops_impl_conv.c:49
AARCH64_SWS_OP_WRITE_PLANAR
@ AARCH64_SWS_OP_WRITE_PLANAR
Definition: ops_impl.h:49
AARCH64_SWS_OP_LSHIFT
@ AARCH64_SWS_OP_LSHIFT
Definition: ops_impl.h:54
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:59
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:51
SwsOp::comps
SwsComps comps
Metadata about the operation's input/output components.
Definition: ops.h:233
AARCH64_SWS_OP_WRITE_BIT
@ AARCH64_SWS_OP_WRITE_BIT
Definition: ops_impl.h:46
AARCH64_SWS_OP_READ_PLANAR
@ AARCH64_SWS_OP_READ_PLANAR
Definition: ops_impl.h:45
AARCH64_SWS_OP_EXPAND
@ AARCH64_SWS_OP_EXPAND
Definition: ops_impl.h:58
AARCH64_SWS_OP_UNPACK
@ AARCH64_SWS_OP_UNPACK
Definition: ops_impl.h:52
SwsOpList::ops
SwsOp * ops
Definition: ops.h:255
SwsOp
Definition: ops.h:212
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
MASK_SET
#define MASK_SET(mask, idx, val)
Definition: ops_impl.h:112
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
AARCH64_PIXEL_U8
@ AARCH64_PIXEL_U8
Definition: ops_impl.h:30
AARCH64_PIXEL_U32
@ AARCH64_PIXEL_U32
Definition: ops_impl.h:32
convert_to_aarch64_impl
static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n, int block_size, SwsAArch64OpImplParams *out)
Convert SwsOp to a SwsAArch64OpImplParams.
Definition: ops_impl_conv.c:59
SWS_OP_SWAP_BYTES
@ SWS_OP_SWAP_BYTES
Definition: ops.h:52
AARCH64_SWS_OP_WRITE_PACKED
@ AARCH64_SWS_OP_WRITE_PACKED
Definition: ops_impl.h:48
SwsAArch64OpImplParams
SwsAArch64OpImplParams describes the parameters for an SwsAArch64OpType operation.
Definition: ops_impl.h:94
AARCH64_PIXEL_U16
@ AARCH64_PIXEL_U16
Definition: ops_impl.h:31
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:63
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:254
SwsContext
Main external API structure.
Definition: swscale.h:206