FFmpeg
sws_ops.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2025 Niklas Haas
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 #include "libavutil/avassert.h"
22 #include "libavutil/avstring.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/pixdesc.h"
25 #include "libavutil/tree.h"
26 #include "libswscale/ops.h"
28 #include "libswscale/format.h"
29 
30 #ifdef _WIN32
31 #include <io.h>
32 #include <fcntl.h>
33 #endif
34 
35 static int pass_idx;
36 
38 {
39  if (pass_idx > 0)
40  av_log(NULL, AV_LOG_INFO, " Sub-pass #%d:\n", pass_idx);
41 
43  *out = (SwsCompiledOp) {0}; /* dummy value, will be immediately freed */
44 
45  bool has_filters = false;
46  for (int i = 0; i < ops->num_ops; i++) {
47  const SwsOp *op = &ops->ops[i];
48  if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V) {
49  has_filters = true;
50  break;
51  }
52  }
53 
54  if (has_filters) {
55  av_log(NULL, AV_LOG_INFO, " Retrying with split passes:\n");
56  return AVERROR(ENOTSUP);
57  }
58 
59  pass_idx++;
60  return 0;
61 }
62 
63 /* Dummy backend that just prints all seen op lists */
64 static const SwsOpBackend backend_print = {
65  .name = "print_ops",
66  .compile = print_ops,
67 };
68 
69 static int print_passes(SwsContext *ctx, void *graph, SwsOpList *ops)
70 {
71  av_log(NULL, AV_LOG_INFO, "%s %dx%d -> %s %dx%d:\n",
73  ops->src.width, ops->src.height,
75  ops->dst.width, ops->dst.height);
76 
77  if (ff_sws_op_list_is_noop(ops)) {
78  av_log(NULL, AV_LOG_INFO, " (no-op)\n");
79  return 0;
80  }
81 
82  /* ff_sws_compile_pass() takes over ownership of `ops` */
84  if (!copy)
85  return AVERROR(ENOMEM);
86 
87  pass_idx = 0;
88  return ff_sws_compile_pass(graph, &backend_print, &copy, 0, NULL, NULL);
89 }
90 
91 static int cmp_str(const void *a, const void *b)
92 {
93  return strcmp(a, b);
94 }
95 
96 static int register_op(SwsContext *ctx, void *opaque, SwsOp *op)
97 {
98  struct AVTreeNode **root = opaque;
99  AVBPrint bp;
100  char *desc;
101 
102  /* Strip irrelevant constant data from some operations */
103  switch (op->op) {
104  case SWS_OP_LINEAR:
105  for (int i = 0; i < 4; i++) {
106  for (int j = 0; j < 5; j++)
107  op->lin.m[i][j] = (AVRational) { 0, 1 };
108  }
109  break;
110  case SWS_OP_SCALE:
111  op->scale.factor = (AVRational) { 0, 1 };
112  break;
113  case SWS_OP_MIN:
114  case SWS_OP_MAX:
115  for (int i = 0; i < 4; i++)
116  op->clamp.limit[i] = (AVRational) { 0, 1 };
117  break;
118  case SWS_OP_CLEAR:
119  for (int i = 0; i < 4; i++)
120  op->clear.value[i] = (AVRational) { 0, SWS_COMP_TEST(op->clear.mask, i) };
121  break;
122  case SWS_OP_DITHER:
123  /* Strip arbitrary offset */
124  for (int i = 0; i < 4; i++)
125  op->dither.y_offset[i] = op->dither.y_offset[i] >= 0 ? 0 : -1;
126  break;
127  }
128 
130  ff_sws_op_desc(&bp, op);
131  int ret = av_bprint_finalize(&bp, &desc);
132  if (ret < 0)
133  return ret;
134 
135  struct AVTreeNode *node = av_tree_node_alloc();
136  if (!node) {
137  av_free(desc);
138  return AVERROR(ENOMEM);
139  }
140 
141  av_tree_insert(root, desc, cmp_str, &node);
142  if (node) {
143  av_free(node);
144  av_free(desc);
145  }
146  return ret;
147 }
148 
149 static int print_and_free_summary(void *opaque, void *key)
150 {
151  char *desc = key;
152  av_log(opaque, AV_LOG_INFO, "%s\n", desc);
153  av_free(desc);
154  return 0;
155 }
156 
157 static void log_stdout(void *avcl, int level, const char *fmt, va_list vl)
158 {
159  if (level != AV_LOG_INFO) {
160  av_log_default_callback(avcl, level, fmt, vl);
161  } else if (av_log_get_level() >= AV_LOG_INFO) {
162  vfprintf(stdout, fmt, vl);
163  }
164 }
165 
166 int main(int argc, char **argv)
167 {
168  enum AVPixelFormat src_fmt = AV_PIX_FMT_NONE;
169  enum AVPixelFormat dst_fmt = AV_PIX_FMT_NONE;
170  bool summarize = false;
171  int ret = 1;
172 
173 #ifdef _WIN32
174  _setmode(_fileno(stdout), _O_BINARY);
175 #endif
176 
177  for (int i = 1; i < argc; i++) {
178  if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
179  fprintf(stderr,
180  "sws_ops [options...]\n"
181  " -help\n"
182  " This text\n"
183  " -dst <pixfmt>\n"
184  " Only test the specified destination pixel format\n"
185  " -src <pixfmt>\n"
186  " Only test the specified source pixel format\n"
187  " -v <level>\n"
188  " Enable log verbosity at given level\n"
189  " -summarize\n"
190  " Summarize operation types, instead of printing op lists\n"
191  );
192  return 0;
193  }
194  if (!strcmp(argv[i], "-src")) {
195  if (i + 1 >= argc)
196  goto bad_option;
197  src_fmt = av_get_pix_fmt(argv[i + 1]);
198  if (src_fmt == AV_PIX_FMT_NONE) {
199  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
200  goto error;
201  }
202  i++;
203  } else if (!strcmp(argv[i], "-dst")) {
204  if (i + 1 >= argc)
205  goto bad_option;
206  dst_fmt = av_get_pix_fmt(argv[i + 1]);
207  if (dst_fmt == AV_PIX_FMT_NONE) {
208  fprintf(stderr, "invalid pixel format %s\n", argv[i + 1]);
209  goto error;
210  }
211  i++;
212  } else if (!strcmp(argv[i], "-v")) {
213  if (i + 1 >= argc)
214  goto bad_option;
215  av_log_set_level(atoi(argv[i + 1]));
216  i++;
217  } else if (!strcmp(argv[i], "-summarize")) {
218  summarize = true;
219  } else {
220 bad_option:
221  fprintf(stderr, "bad option or argument missing (%s) see -help\n", argv[i]);
222  goto error;
223  }
224  }
225 
227  if (!ctx)
228  goto fail;
229  ctx->scaler = SWS_SCALE_BILINEAR; /* reduce filter generation overhead */
230 
232 
233  if (summarize) {
234  struct AVTreeNode *root = NULL;
235  ret = ff_sws_enum_ops(ctx, &root, src_fmt, dst_fmt, register_op);
236  if (ret < 0)
237  goto fail;
239  av_tree_destroy(root);
240  } else {
241  /* Allocate dummy graph and context for ff_sws_compile_pass() */
242  SwsGraph *graph = ff_sws_graph_alloc();
243  if (!graph) {
244  ret = AVERROR(ENOMEM);
245  goto fail;
246  }
247  graph->ctx = ctx;
248 
249  ret = ff_sws_enum_op_lists(ctx, graph, src_fmt, dst_fmt, print_passes);
250  ff_sws_graph_free(&graph);
251  if (ret < 0)
252  goto fail;
253  }
254 
255  ret = 0;
256 fail:
258  return ret;
259 
260 error:
261  return AVERROR(EINVAL);
262 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
ff_sws_enum_ops
int ff_sws_enum_ops(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOp *op))
Helper function to enumerate over all possible operations, under the current set of options in ctx,...
Definition: ops.c:1104
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
level
uint8_t level
Definition: svq3.c:208
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:122
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
ff_sws_op_list_duplicate
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
Definition: ops.c:634
out
static FILE * out
Definition: movenc.c:55
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
pass_idx
static int pass_idx
Definition: sws_ops.c:35
av_tree_insert
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:59
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:62
SWS_SCALE_BILINEAR
@ SWS_SCALE_BILINEAR
bilinear filtering
Definition: swscale.h:98
main
int main(int argc, char **argv)
Definition: sws_ops.c:166
pixdesc.h
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:70
b
#define b
Definition: input.c:43
ops_dispatch.h
av_tree_node_alloc
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
format.h
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:131
av_tree_enumerate
void av_tree_enumerate(AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem))
Apply enu(opaque, &elem) to all the elements in the tree in a given range.
Definition: tree.c:155
ff_sws_graph_alloc
SwsGraph * ff_sws_graph_alloc(void)
Allocate an empty SwsGraph.
Definition: graph.c:797
ff_sws_op_list_print
void ff_sws_op_list_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
Definition: ops.c:961
fail
#define fail()
Definition: checkasm.h:225
SwsOpList::num_ops
int num_ops
Definition: ops.h:290
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: ops.h:89
print_and_free_summary
static int print_and_free_summary(void *opaque, void *key)
Definition: sws_ops.c:149
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:66
avassert.h
SwsFormat::height
int height
Definition: format.h:78
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
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:69
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
key
const char * key
Definition: hwcontext_opencl.c:189
SwsOpBackend
Definition: ops_dispatch.h:130
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
ff_sws_op_list_is_noop
bool ff_sws_op_list_is_noop(const SwsOpList *ops)
Returns whether an op list represents a true no-op operation, i.e.
Definition: ops.c:719
NULL
#define NULL
Definition: coverity.c:32
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVTreeNode
Definition: tree.c:26
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:74
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
ff_sws_graph_free
void ff_sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition: graph.c:885
av_log_set_callback
void av_log_set_callback(void(*callback)(void *, int, const char *, va_list))
Set the logging callback.
Definition: log.c:492
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1031
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsOpList::src
SwsFormat src
Definition: ops.h:293
tree.h
a
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
Definition: undefined.txt:41
log_stdout
static void log_stdout(void *avcl, int level, const char *fmt, va_list vl)
Definition: sws_ops.c:157
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:854
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
av_log_set_level
void av_log_set_level(int level)
Set the log level.
Definition: log.c:477
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
SwsOpList::ops
SwsOp * ops
Definition: ops.h:289
SwsFormat::width
int width
Definition: format.h:78
ff_sws_enum_op_lists
int ff_sws_enum_op_lists(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
Helper function to enumerate over all possible (optimized) operation lists, under the current set of ...
Definition: ops.c:1059
SwsOp
Definition: ops.h:238
backend_print
static const SwsOpBackend backend_print
Definition: sws_ops.c:64
ret
ret
Definition: filter_design.txt:187
SwsOpList::dst
SwsFormat dst
Definition: ops.h:293
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
SwsCompiledOp
Definition: ops_dispatch.h:100
print_ops
static int print_ops(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
Definition: sws_ops.c:37
av_get_pix_fmt
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:3388
cmp_str
static int cmp_str(const void *a, const void *b)
Definition: sws_ops.c:91
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
ff_sws_compile_pass
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.
Definition: ops_dispatch.c:594
register_op
static int register_op(SwsContext *ctx, void *opaque, SwsOp *op)
Definition: sws_ops.c:96
desc
const char * desc
Definition: libsvtav1.c:83
av_log_default_callback
void av_log_default_callback(void *ptr, int level, const char *fmt, va_list vl)
Default logging callback.
Definition: log.c:380
mem.h
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:121
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
sws_free_context
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition: utils.c:2369
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
print_passes
static int print_passes(SwsContext *ctx, void *graph, SwsOpList *ops)
Definition: sws_ops.c:69
avstring.h
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:288
SwsContext
Main external API structure.
Definition: swscale.h:206
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3376