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 
64  out->block_size = block_size;
65 
66  /**
67  * Most SwsOp work on fields described by SWS_OP_NEEDED().
68  * The few that don't will override this field later.
69  */
70  out->mask = 0;
71  for (int i = 0; i < 4; i++) {
72  if (SWS_OP_NEEDED(op, i))
73  MASK_SET(out->mask, i, 1);
74  }
75 
76  out->type = sws_pixel_to_aarch64(op->type);
77 
78  /* Map SwsOpType to SwsAArch64OpType */
79  switch (op->op) {
80  case SWS_OP_READ:
81  if (op->rw.filter)
82  return AVERROR(ENOTSUP);
83  /**
84  * The different types of read operations have been split into
85  * their own SwsAArch64OpType to simplify the implementation.
86  */
87  if (op->rw.frac == 1)
89  else if (op->rw.frac == 3)
91  else if (op->rw.packed && op->rw.elems != 1)
93  else
95  break;
96  case SWS_OP_WRITE:
97  if (op->rw.filter)
98  return AVERROR(ENOTSUP);
99  /**
100  * The different types of write operations have been split into
101  * their own SwsAArch64OpType to simplify the implementation.
102  */
103  if (op->rw.frac == 1)
105  else if (op->rw.frac == 3)
107  else if (op->rw.packed && op->rw.elems != 1)
109  else
111  break;
113  case SWS_OP_SWIZZLE: out->op = AARCH64_SWS_OP_SWIZZLE; break;
114  case SWS_OP_UNPACK: out->op = AARCH64_SWS_OP_UNPACK; break;
115  case SWS_OP_PACK: out->op = AARCH64_SWS_OP_PACK; break;
116  case SWS_OP_LSHIFT: out->op = AARCH64_SWS_OP_LSHIFT; break;
117  case SWS_OP_RSHIFT: out->op = AARCH64_SWS_OP_RSHIFT; break;
118  case SWS_OP_CLEAR: out->op = AARCH64_SWS_OP_CLEAR; break;
119  case SWS_OP_CONVERT:
120  out->op = op->convert.expand ? AARCH64_SWS_OP_EXPAND : AARCH64_SWS_OP_CONVERT;
121  break;
122  case SWS_OP_MIN: out->op = AARCH64_SWS_OP_MIN; break;
123  case SWS_OP_MAX: out->op = AARCH64_SWS_OP_MAX; break;
124  case SWS_OP_SCALE: out->op = AARCH64_SWS_OP_SCALE; break;
125  case SWS_OP_LINEAR: out->op = AARCH64_SWS_OP_LINEAR; break;
126  case SWS_OP_DITHER: out->op = AARCH64_SWS_OP_DITHER; break;
127  case SWS_OP_FILTER_H:
128  case SWS_OP_FILTER_V:
129  return AVERROR(ENOTSUP);
130  }
131 
132  switch (out->op) {
141  switch (op->rw.elems) {
142  case 1: out->mask = 0x0001; break;
143  case 2: out->mask = 0x0011; break;
144  case 3: out->mask = 0x0111; break;
145  case 4: out->mask = 0x1111; break;
146  };
147  break;
149  /* Only the element size matters, not the type. */
150  if (out->type == AARCH64_PIXEL_F32)
151  out->type = AARCH64_PIXEL_U32;
152  break;
154  out->mask = 0;
155  MASK_SET(out->mask, 0, op->swizzle.in[0] != 0);
156  MASK_SET(out->mask, 1, op->swizzle.in[1] != 1);
157  MASK_SET(out->mask, 2, op->swizzle.in[2] != 2);
158  MASK_SET(out->mask, 3, op->swizzle.in[3] != 3);
159  MASK_SET(out->swizzle, 0, op->swizzle.in[0]);
160  MASK_SET(out->swizzle, 1, op->swizzle.in[1]);
161  MASK_SET(out->swizzle, 2, op->swizzle.in[2]);
162  MASK_SET(out->swizzle, 3, op->swizzle.in[3]);
163  /* The element size and type don't matter. */
164  out->block_size = block_size * ff_sws_pixel_type_size(op->type);
165  out->type = AARCH64_PIXEL_U8;
166  break;
168  MASK_SET(out->pack, 0, op->pack.pattern[0]);
169  MASK_SET(out->pack, 1, op->pack.pattern[1]);
170  MASK_SET(out->pack, 2, op->pack.pattern[2]);
171  MASK_SET(out->pack, 3, op->pack.pattern[3]);
172  break;
173  case AARCH64_SWS_OP_PACK:
174  out->mask = 0;
175  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
176  MASK_SET(out->mask, i, 1);
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->shift.amount;
185  break;
187  out->mask = 0;
188  MASK_SET(out->mask, 0, !!op->clear.value[0].den);
189  MASK_SET(out->mask, 1, !!op->clear.value[1].den);
190  MASK_SET(out->mask, 2, !!op->clear.value[2].den);
191  MASK_SET(out->mask, 3, !!op->clear.value[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 (!SWS_OP_NEEDED(op, 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:38
AARCH64_SWS_OP_MIN
@ AARCH64_SWS_OP_MIN
Definition: ops_impl.h:57
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:41
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:46
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:44
out
static FILE * out
Definition: movenc.c:55
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:50
rational.h
ops_impl.h
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:58
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:180
AARCH64_SWS_OP_SWIZZLE
@ AARCH64_SWS_OP_SWIZZLE
Definition: ops_impl.h:49
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:77
AARCH64_SWS_OP_CLEAR
@ AARCH64_SWS_OP_CLEAR
Definition: ops_impl.h:54
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:182
AARCH64_SWS_OP_READ_NIBBLE
@ AARCH64_SWS_OP_READ_NIBBLE
Definition: ops_impl.h:41
AARCH64_SWS_OP_PACK
@ AARCH64_SWS_OP_PACK
Definition: ops_impl.h:51
AARCH64_SWS_OP_SWAP_BYTES
@ AARCH64_SWS_OP_SWAP_BYTES
Definition: ops_impl.h:48
AARCH64_SWS_OP_READ_BIT
@ AARCH64_SWS_OP_READ_BIT
Definition: ops_impl.h:40
AARCH64_SWS_OP_MAX
@ AARCH64_SWS_OP_MAX
Definition: ops_impl.h:58
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:127
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:54
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
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:235
AARCH64_SWS_OP_WRITE_NIBBLE
@ AARCH64_SWS_OP_WRITE_NIBBLE
Definition: ops_impl.h:45
AARCH64_SWS_OP_DITHER
@ AARCH64_SWS_OP_DITHER
Definition: ops_impl.h:61
AARCH64_SWS_OP_RSHIFT
@ AARCH64_SWS_OP_RSHIFT
Definition: ops_impl.h:53
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1465
AARCH64_SWS_OP_LINEAR
@ AARCH64_SWS_OP_LINEAR
Definition: ops_impl.h:60
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:52
AARCH64_SWS_OP_CONVERT
@ AARCH64_SWS_OP_CONVERT
Definition: ops_impl.h:55
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:57
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:61
AARCH64_PIXEL_F32
@ AARCH64_PIXEL_F32
Definition: ops_impl.h:33
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:45
AARCH64_SWS_OP_SCALE
@ AARCH64_SWS_OP_SCALE
Definition: ops_impl.h:59
LINEAR_MASK_SET
#define LINEAR_MASK_SET(mask, idx, jdx, val)
Definition: ops_impl.h:123
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:62
AARCH64_SWS_OP_READ_PACKED
@ AARCH64_SWS_OP_READ_PACKED
Definition: ops_impl.h:42
LINEAR_MASK_X
#define LINEAR_MASK_X
Definition: ops_impl.h:128
SwsPixelType
SwsPixelType
Definition: uops.h:38
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:47
AARCH64_SWS_OP_LSHIFT
@ AARCH64_SWS_OP_LSHIFT
Definition: ops_impl.h:52
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:47
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:39
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: uops.h:42
AARCH64_SWS_OP_WRITE_BIT
@ AARCH64_SWS_OP_WRITE_BIT
Definition: ops_impl.h:44
AARCH64_SWS_OP_READ_PLANAR
@ AARCH64_SWS_OP_READ_PLANAR
Definition: ops_impl.h:43
AARCH64_SWS_OP_EXPAND
@ AARCH64_SWS_OP_EXPAND
Definition: ops_impl.h:56
AARCH64_SWS_OP_UNPACK
@ AARCH64_SWS_OP_UNPACK
Definition: ops_impl.h:50
SwsOpList::ops
SwsOp * ops
Definition: ops.h:259
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: uops.h:40
SwsOp
Definition: ops.h:208
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:110
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:53
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:40
AARCH64_SWS_OP_WRITE_PACKED
@ AARCH64_SWS_OP_WRITE_PACKED
Definition: ops_impl.h:46
SwsAArch64OpImplParams
SwsAArch64OpImplParams describes the parameters for an SwsAArch64OpType operation.
Definition: ops_impl.h:92
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: uops.h:43
AARCH64_PIXEL_U16
@ AARCH64_PIXEL_U16
Definition: ops_impl.h:31
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:51
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:258
SwsContext
Main external API structure.
Definition: swscale.h:229
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: uops.h:41