FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/format.c
Date: 2026-08-15 14:54:27
Exec Total Coverage
Lines: 634 710 89.3%
Functions: 49 50 98.0%
Branches: 358 482 74.3%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2024 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/attributes.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/hdr_dynamic_metadata.h"
24 #include "libavutil/mastering_display_metadata.h"
25 #include "libavutil/refstruct.h"
26
27 #include "format.h"
28 #include "csputils.h"
29 #include "ops_internal.h"
30 #include "config_components.h"
31
32 #if CONFIG_UNSTABLE
33 #include "libavutil/hwcontext.h"
34 #endif
35
36 #define RET(x) \
37 do { \
38 int _ret = (x); \
39 if (_ret < 0) \
40 return _ret; \
41 } while (0)
42
43 typedef struct LegacyFormatEntry {
44 uint8_t is_supported_in :1;
45 uint8_t is_supported_out :1;
46 uint8_t is_supported_endianness :1;
47 } LegacyFormatEntry;
48
49 /* Format support table for legacy swscale */
50 static const LegacyFormatEntry legacy_format_entries[] = {
51 [AV_PIX_FMT_YUV420P] = { 1, 1 },
52 [AV_PIX_FMT_YUYV422] = { 1, 1 },
53 [AV_PIX_FMT_RGB24] = { 1, 1 },
54 [AV_PIX_FMT_BGR24] = { 1, 1 },
55 [AV_PIX_FMT_YUV422P] = { 1, 1 },
56 [AV_PIX_FMT_YUV444P] = { 1, 1 },
57 [AV_PIX_FMT_YUV410P] = { 1, 1 },
58 [AV_PIX_FMT_YUV411P] = { 1, 1 },
59 [AV_PIX_FMT_GRAY8] = { 1, 1 },
60 [AV_PIX_FMT_MONOWHITE] = { 1, 1 },
61 [AV_PIX_FMT_MONOBLACK] = { 1, 1 },
62 [AV_PIX_FMT_PAL8] = { 1, 0 },
63 [AV_PIX_FMT_YUVJ420P] = { 1, 1 },
64 [AV_PIX_FMT_YUVJ411P] = { 1, 1 },
65 [AV_PIX_FMT_YUVJ422P] = { 1, 1 },
66 [AV_PIX_FMT_YUVJ444P] = { 1, 1 },
67 [AV_PIX_FMT_YVYU422] = { 1, 1 },
68 [AV_PIX_FMT_UYVY422] = { 1, 1 },
69 [AV_PIX_FMT_UYYVYY411] = { 1, 0 },
70 [AV_PIX_FMT_BGR8] = { 1, 1 },
71 [AV_PIX_FMT_BGR4] = { 0, 1 },
72 [AV_PIX_FMT_BGR4_BYTE] = { 1, 1 },
73 [AV_PIX_FMT_RGB8] = { 1, 1 },
74 [AV_PIX_FMT_RGB4] = { 0, 1 },
75 [AV_PIX_FMT_RGB4_BYTE] = { 1, 1 },
76 [AV_PIX_FMT_NV12] = { 1, 1 },
77 [AV_PIX_FMT_NV21] = { 1, 1 },
78 [AV_PIX_FMT_ARGB] = { 1, 1 },
79 [AV_PIX_FMT_RGBA] = { 1, 1 },
80 [AV_PIX_FMT_ABGR] = { 1, 1 },
81 [AV_PIX_FMT_BGRA] = { 1, 1 },
82 [AV_PIX_FMT_0RGB] = { 1, 1 },
83 [AV_PIX_FMT_RGB0] = { 1, 1 },
84 [AV_PIX_FMT_0BGR] = { 1, 1 },
85 [AV_PIX_FMT_BGR0] = { 1, 1 },
86 [AV_PIX_FMT_GRAY9BE] = { 1, 1 },
87 [AV_PIX_FMT_GRAY9LE] = { 1, 1 },
88 [AV_PIX_FMT_GRAY10BE] = { 1, 1 },
89 [AV_PIX_FMT_GRAY10LE] = { 1, 1 },
90 [AV_PIX_FMT_GRAY12BE] = { 1, 1 },
91 [AV_PIX_FMT_GRAY12LE] = { 1, 1 },
92 [AV_PIX_FMT_GRAY14BE] = { 1, 1 },
93 [AV_PIX_FMT_GRAY14LE] = { 1, 1 },
94 [AV_PIX_FMT_GRAY16BE] = { 1, 1 },
95 [AV_PIX_FMT_GRAY16LE] = { 1, 1 },
96 [AV_PIX_FMT_YUV440P] = { 1, 1 },
97 [AV_PIX_FMT_YUVJ440P] = { 1, 1 },
98 [AV_PIX_FMT_YUV440P10LE] = { 1, 1 },
99 [AV_PIX_FMT_YUV440P10BE] = { 1, 1 },
100 [AV_PIX_FMT_YUV440P12LE] = { 1, 1 },
101 [AV_PIX_FMT_YUV440P12BE] = { 1, 1 },
102 [AV_PIX_FMT_YUVA420P] = { 1, 1 },
103 [AV_PIX_FMT_YUVA422P] = { 1, 1 },
104 [AV_PIX_FMT_YUVA444P] = { 1, 1 },
105 [AV_PIX_FMT_YUVA420P9BE] = { 1, 1 },
106 [AV_PIX_FMT_YUVA420P9LE] = { 1, 1 },
107 [AV_PIX_FMT_YUVA422P9BE] = { 1, 1 },
108 [AV_PIX_FMT_YUVA422P9LE] = { 1, 1 },
109 [AV_PIX_FMT_YUVA444P9BE] = { 1, 1 },
110 [AV_PIX_FMT_YUVA444P9LE] = { 1, 1 },
111 [AV_PIX_FMT_YUVA420P10BE] = { 1, 1 },
112 [AV_PIX_FMT_YUVA420P10LE] = { 1, 1 },
113 [AV_PIX_FMT_YUVA422P10BE] = { 1, 1 },
114 [AV_PIX_FMT_YUVA422P10LE] = { 1, 1 },
115 [AV_PIX_FMT_YUVA444P10BE] = { 1, 1 },
116 [AV_PIX_FMT_YUVA444P10LE] = { 1, 1 },
117 [AV_PIX_FMT_YUVA420P16BE] = { 1, 1 },
118 [AV_PIX_FMT_YUVA420P16LE] = { 1, 1 },
119 [AV_PIX_FMT_YUVA422P16BE] = { 1, 1 },
120 [AV_PIX_FMT_YUVA422P16LE] = { 1, 1 },
121 [AV_PIX_FMT_YUVA444P16BE] = { 1, 1 },
122 [AV_PIX_FMT_YUVA444P16LE] = { 1, 1 },
123 [AV_PIX_FMT_RGB48BE] = { 1, 1 },
124 [AV_PIX_FMT_RGB48LE] = { 1, 1 },
125 [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 },
126 [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 },
127 [AV_PIX_FMT_RGB565BE] = { 1, 1 },
128 [AV_PIX_FMT_RGB565LE] = { 1, 1 },
129 [AV_PIX_FMT_RGB555BE] = { 1, 1 },
130 [AV_PIX_FMT_RGB555LE] = { 1, 1 },
131 [AV_PIX_FMT_BGR565BE] = { 1, 1 },
132 [AV_PIX_FMT_BGR565LE] = { 1, 1 },
133 [AV_PIX_FMT_BGR555BE] = { 1, 1 },
134 [AV_PIX_FMT_BGR555LE] = { 1, 1 },
135 [AV_PIX_FMT_YUV420P16LE] = { 1, 1 },
136 [AV_PIX_FMT_YUV420P16BE] = { 1, 1 },
137 [AV_PIX_FMT_YUV422P16LE] = { 1, 1 },
138 [AV_PIX_FMT_YUV422P16BE] = { 1, 1 },
139 [AV_PIX_FMT_YUV444P16LE] = { 1, 1 },
140 [AV_PIX_FMT_YUV444P16BE] = { 1, 1 },
141 [AV_PIX_FMT_RGB444LE] = { 1, 1 },
142 [AV_PIX_FMT_RGB444BE] = { 1, 1 },
143 [AV_PIX_FMT_BGR444LE] = { 1, 1 },
144 [AV_PIX_FMT_BGR444BE] = { 1, 1 },
145 [AV_PIX_FMT_YA8] = { 1, 1 },
146 [AV_PIX_FMT_YA16BE] = { 1, 1 },
147 [AV_PIX_FMT_YA16LE] = { 1, 1 },
148 [AV_PIX_FMT_BGR48BE] = { 1, 1 },
149 [AV_PIX_FMT_BGR48LE] = { 1, 1 },
150 [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 },
151 [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 },
152 [AV_PIX_FMT_YUV420P9BE] = { 1, 1 },
153 [AV_PIX_FMT_YUV420P9LE] = { 1, 1 },
154 [AV_PIX_FMT_YUV420P10BE] = { 1, 1 },
155 [AV_PIX_FMT_YUV420P10LE] = { 1, 1 },
156 [AV_PIX_FMT_YUV420P12BE] = { 1, 1 },
157 [AV_PIX_FMT_YUV420P12LE] = { 1, 1 },
158 [AV_PIX_FMT_YUV420P14BE] = { 1, 1 },
159 [AV_PIX_FMT_YUV420P14LE] = { 1, 1 },
160 [AV_PIX_FMT_YUV422P9BE] = { 1, 1 },
161 [AV_PIX_FMT_YUV422P9LE] = { 1, 1 },
162 [AV_PIX_FMT_YUV422P10BE] = { 1, 1 },
163 [AV_PIX_FMT_YUV422P10LE] = { 1, 1 },
164 [AV_PIX_FMT_YUV422P12BE] = { 1, 1 },
165 [AV_PIX_FMT_YUV422P12LE] = { 1, 1 },
166 [AV_PIX_FMT_YUV422P14BE] = { 1, 1 },
167 [AV_PIX_FMT_YUV422P14LE] = { 1, 1 },
168 [AV_PIX_FMT_YUV444P9BE] = { 1, 1 },
169 [AV_PIX_FMT_YUV444P9LE] = { 1, 1 },
170 [AV_PIX_FMT_YUV444P10BE] = { 1, 1 },
171 [AV_PIX_FMT_YUV444P10LE] = { 1, 1 },
172 [AV_PIX_FMT_YUV444P12BE] = { 1, 1 },
173 [AV_PIX_FMT_YUV444P12LE] = { 1, 1 },
174 [AV_PIX_FMT_YUV444P14BE] = { 1, 1 },
175 [AV_PIX_FMT_YUV444P14LE] = { 1, 1 },
176 [AV_PIX_FMT_YUV444P10MSBBE] = { 1, 1 },
177 [AV_PIX_FMT_YUV444P10MSBLE] = { 1, 1 },
178 [AV_PIX_FMT_YUV444P12MSBBE] = { 1, 1 },
179 [AV_PIX_FMT_YUV444P12MSBLE] = { 1, 1 },
180 [AV_PIX_FMT_GBRP] = { 1, 1 },
181 [AV_PIX_FMT_GBRP9LE] = { 1, 1 },
182 [AV_PIX_FMT_GBRP9BE] = { 1, 1 },
183 [AV_PIX_FMT_GBRP10LE] = { 1, 1 },
184 [AV_PIX_FMT_GBRP10BE] = { 1, 1 },
185 [AV_PIX_FMT_GBRAP10LE] = { 1, 1 },
186 [AV_PIX_FMT_GBRAP10BE] = { 1, 1 },
187 [AV_PIX_FMT_GBRP10MSBLE] = { 1, 1 },
188 [AV_PIX_FMT_GBRP10MSBBE] = { 1, 1 },
189 [AV_PIX_FMT_GBRP12LE] = { 1, 1 },
190 [AV_PIX_FMT_GBRP12BE] = { 1, 1 },
191 [AV_PIX_FMT_GBRP12MSBLE] = { 1, 1 },
192 [AV_PIX_FMT_GBRP12MSBBE] = { 1, 1 },
193 [AV_PIX_FMT_GBRAP12LE] = { 1, 1 },
194 [AV_PIX_FMT_GBRAP12BE] = { 1, 1 },
195 [AV_PIX_FMT_GBRP14LE] = { 1, 1 },
196 [AV_PIX_FMT_GBRP14BE] = { 1, 1 },
197 [AV_PIX_FMT_GBRAP14LE] = { 1, 1 },
198 [AV_PIX_FMT_GBRAP14BE] = { 1, 1 },
199 [AV_PIX_FMT_GBRP16LE] = { 1, 1 },
200 [AV_PIX_FMT_GBRP16BE] = { 1, 1 },
201 [AV_PIX_FMT_GBRPF32LE] = { 1, 1 },
202 [AV_PIX_FMT_GBRPF32BE] = { 1, 1 },
203 [AV_PIX_FMT_GBRAPF32LE] = { 1, 1 },
204 [AV_PIX_FMT_GBRAPF32BE] = { 1, 1 },
205 [AV_PIX_FMT_GBRPF16LE] = { 1, 0 },
206 [AV_PIX_FMT_GBRPF16BE] = { 1, 0 },
207 [AV_PIX_FMT_GBRAPF16LE] = { 1, 0 },
208 [AV_PIX_FMT_GBRAPF16BE] = { 1, 0 },
209 [AV_PIX_FMT_GBRAP] = { 1, 1 },
210 [AV_PIX_FMT_GBRAP16LE] = { 1, 1 },
211 [AV_PIX_FMT_GBRAP16BE] = { 1, 1 },
212 [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 },
213 [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 },
214 [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 },
215 [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 },
216 [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 },
217 [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 },
218 [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 },
219 [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 },
220 [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 },
221 [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 },
222 [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 },
223 [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 },
224 [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 },
225 [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 },
226 [AV_PIX_FMT_AYUV64LE] = { 1, 1},
227 [AV_PIX_FMT_AYUV64BE] = { 1, 1 },
228 [AV_PIX_FMT_P010LE] = { 1, 1 },
229 [AV_PIX_FMT_P010BE] = { 1, 1 },
230 [AV_PIX_FMT_P012LE] = { 1, 1 },
231 [AV_PIX_FMT_P012BE] = { 1, 1 },
232 [AV_PIX_FMT_P016LE] = { 1, 1 },
233 [AV_PIX_FMT_P016BE] = { 1, 1 },
234 [AV_PIX_FMT_GRAYF32LE] = { 1, 1 },
235 [AV_PIX_FMT_GRAYF32BE] = { 1, 1 },
236 [AV_PIX_FMT_GRAYF16LE] = { 1, 0 },
237 [AV_PIX_FMT_GRAYF16BE] = { 1, 0 },
238 [AV_PIX_FMT_YAF32LE] = { 1, 0 },
239 [AV_PIX_FMT_YAF32BE] = { 1, 0 },
240 [AV_PIX_FMT_YAF16LE] = { 1, 0 },
241 [AV_PIX_FMT_YAF16BE] = { 1, 0 },
242 [AV_PIX_FMT_YUVA422P12BE] = { 1, 1 },
243 [AV_PIX_FMT_YUVA422P12LE] = { 1, 1 },
244 [AV_PIX_FMT_YUVA444P12BE] = { 1, 1 },
245 [AV_PIX_FMT_YUVA444P12LE] = { 1, 1 },
246 [AV_PIX_FMT_NV24] = { 1, 1 },
247 [AV_PIX_FMT_NV42] = { 1, 1 },
248 [AV_PIX_FMT_Y210LE] = { 1, 1 },
249 [AV_PIX_FMT_Y212LE] = { 1, 1 },
250 [AV_PIX_FMT_Y216LE] = { 1, 1 },
251 [AV_PIX_FMT_X2RGB10LE] = { 1, 1 },
252 [AV_PIX_FMT_X2BGR10LE] = { 1, 1 },
253 [AV_PIX_FMT_NV20BE] = { 1, 1 },
254 [AV_PIX_FMT_NV20LE] = { 1, 1 },
255 [AV_PIX_FMT_P210BE] = { 1, 1 },
256 [AV_PIX_FMT_P210LE] = { 1, 1 },
257 [AV_PIX_FMT_P212BE] = { 1, 1 },
258 [AV_PIX_FMT_P212LE] = { 1, 1 },
259 [AV_PIX_FMT_P410BE] = { 1, 1 },
260 [AV_PIX_FMT_P410LE] = { 1, 1 },
261 [AV_PIX_FMT_P412BE] = { 1, 1 },
262 [AV_PIX_FMT_P412LE] = { 1, 1 },
263 [AV_PIX_FMT_P216BE] = { 1, 1 },
264 [AV_PIX_FMT_P216LE] = { 1, 1 },
265 [AV_PIX_FMT_P416BE] = { 1, 1 },
266 [AV_PIX_FMT_P416LE] = { 1, 1 },
267 [AV_PIX_FMT_NV16] = { 1, 1 },
268 [AV_PIX_FMT_VUYA] = { 1, 1 },
269 [AV_PIX_FMT_VUYX] = { 1, 1 },
270 [AV_PIX_FMT_RGBAF16BE] = { 1, 0 },
271 [AV_PIX_FMT_RGBAF16LE] = { 1, 0 },
272 [AV_PIX_FMT_RGBF16BE] = { 1, 0 },
273 [AV_PIX_FMT_RGBF16LE] = { 1, 0 },
274 [AV_PIX_FMT_RGBF32BE] = { 1, 0 },
275 [AV_PIX_FMT_RGBF32LE] = { 1, 0 },
276 [AV_PIX_FMT_XV30LE] = { 1, 1 },
277 [AV_PIX_FMT_XV36LE] = { 1, 1 },
278 [AV_PIX_FMT_XV36BE] = { 1, 1 },
279 [AV_PIX_FMT_XV48LE] = { 1, 1 },
280 [AV_PIX_FMT_XV48BE] = { 1, 1 },
281 [AV_PIX_FMT_AYUV] = { 1, 1 },
282 [AV_PIX_FMT_UYVA] = { 1, 1 },
283 [AV_PIX_FMT_VYU444] = { 1, 1 },
284 [AV_PIX_FMT_V30XLE] = { 1, 1 },
285 };
286
287 2132308 int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
288 {
289 2132308 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
290
2/2
✓ Branch 0 taken 2118220 times.
✓ Branch 1 taken 14088 times.
2132308 legacy_format_entries[pix_fmt].is_supported_in : 0;
291 }
292
293 2153661 int sws_isSupportedOutput(enum AVPixelFormat pix_fmt)
294 {
295 2153661 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
296
2/2
✓ Branch 0 taken 2139373 times.
✓ Branch 1 taken 14288 times.
2153661 legacy_format_entries[pix_fmt].is_supported_out : 0;
297 }
298
299 49920 int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
300 {
301 49920 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
302
1/2
✓ Branch 0 taken 49920 times.
✗ Branch 1 not taken.
49920 legacy_format_entries[pix_fmt].is_supported_endianness : 0;
303 }
304
305 1820942 static void sanitize_fmt(SwsFormat *fmt, const AVPixFmtDescriptor *desc)
306 {
307
2/2
✓ Branch 0 taken 659376 times.
✓ Branch 1 taken 1161566 times.
1820942 if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER)) {
308 /* RGB-like family */
309 659376 fmt->csp = AVCOL_SPC_RGB;
310 659376 fmt->range = AVCOL_RANGE_JPEG;
311
2/2
✓ Branch 0 taken 9874 times.
✓ Branch 1 taken 1151692 times.
1161566 } else if (desc->flags & AV_PIX_FMT_FLAG_XYZ) {
312 9874 fmt->csp = AVCOL_SPC_UNSPECIFIED;
313 9874 fmt->color = (SwsColor) {
314 .prim = AVCOL_PRI_BT709, /* swscale currently hard-codes this XYZ matrix */
315 .trc = AVCOL_TRC_SMPTE428,
316 };
317
2/2
✓ Branch 0 taken 230424 times.
✓ Branch 1 taken 921268 times.
1151692 } else if (desc->nb_components < 3) {
318 /* Grayscale formats */
319 230424 fmt->color.prim = AVCOL_PRI_UNSPECIFIED;
320 230424 fmt->csp = AVCOL_SPC_UNSPECIFIED;
321
2/2
✓ Branch 0 taken 40752 times.
✓ Branch 1 taken 189672 times.
230424 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT)
322 40752 fmt->range = AVCOL_RANGE_UNSPECIFIED;
323 else
324 189672 fmt->range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted
325 }
326
327
2/2
✓ Branch 1 taken 34180 times.
✓ Branch 2 taken 1786762 times.
1820942 switch (av_pix_fmt_desc_get_id(desc)) {
328 34180 case AV_PIX_FMT_YUVJ420P:
329 case AV_PIX_FMT_YUVJ411P:
330 case AV_PIX_FMT_YUVJ422P:
331 case AV_PIX_FMT_YUVJ444P:
332 case AV_PIX_FMT_YUVJ440P:
333 34180 fmt->range = AVCOL_RANGE_JPEG;
334 34180 break;
335 }
336
337
4/4
✓ Branch 0 taken 1336338 times.
✓ Branch 1 taken 484604 times.
✓ Branch 2 taken 1302978 times.
✓ Branch 3 taken 33360 times.
1820942 if (!desc->log2_chroma_w && !desc->log2_chroma_h)
338 1302978 fmt->loc = AVCHROMA_LOC_UNSPECIFIED;
339 1820942 }
340
341 /**
342 * This function also sanitizes and strips the input data, removing irrelevant
343 * fields for certain formats.
344 */
345 671758 SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field)
346 {
347 const AVColorPrimariesDesc *primaries;
348 AVFrameSideData *sd;
349
350 671758 enum AVPixelFormat format = frame->format;
351 671758 enum AVPixelFormat hw_format = AV_PIX_FMT_NONE;
352
353 #if CONFIG_UNSTABLE
354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 671758 times.
671758 if (frame->hw_frames_ctx) {
355 AVHWFramesContext *hwfc = (AVHWFramesContext *)frame->hw_frames_ctx->data;
356 hw_format = frame->format;
357 format = hwfc->sw_format;
358 }
359 #endif
360
361 671758 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
362
363 671758 SwsFormat fmt = {
364 671758 .width = frame->width,
365 671758 .height = frame->height,
366 .format = format,
367 .hw_format = hw_format,
368 671758 .range = frame->color_range,
369 671758 .csp = frame->colorspace,
370 671758 .loc = frame->chroma_location,
371 .desc = desc,
372 .color = {
373 671758 .prim = frame->color_primaries,
374 671758 .trc = frame->color_trc,
375 },
376 };
377
378 av_assert1(fmt.width > 0);
379 av_assert1(fmt.height > 0);
380 av_assert1(fmt.format != AV_PIX_FMT_NONE);
381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 671758 times.
671758 av_assert0(desc);
382 671758 sanitize_fmt(&fmt, desc);
383
384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 671758 times.
671758 if (frame->flags & AV_FRAME_FLAG_INTERLACED) {
385 fmt.height = (fmt.height + (field == FIELD_TOP)) >> 1;
386 fmt.interlaced = 1;
387 fmt.field = field;
388 }
389
390 /* Set luminance and gamut information */
391 671758 fmt.color.min_luma = av_make_q(0, 1);
392
3/3
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 671284 times.
671758 switch (fmt.color.trc) {
393 416 case AVCOL_TRC_SMPTE2084:
394 416 fmt.color.max_luma = av_make_q(10000, 1); break;
395 58 case AVCOL_TRC_ARIB_STD_B67:
396 58 fmt.color.max_luma = av_make_q( 1000, 1); break; /* HLG reference display */
397 671284 default:
398 671284 fmt.color.max_luma = av_make_q( 203, 1); break; /* SDR reference brightness */
399 }
400
401 671758 primaries = av_csp_primaries_desc_from_id(fmt.color.prim);
402
2/2
✓ Branch 0 taken 2494 times.
✓ Branch 1 taken 669264 times.
671758 if (primaries)
403 2494 fmt.color.gamut = primaries->prim;
404
405
2/2
✓ Branch 1 taken 404 times.
✓ Branch 2 taken 671354 times.
671758 if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA))) {
406 404 const AVMasteringDisplayMetadata *mdm = (const AVMasteringDisplayMetadata *) sd->data;
407
1/2
✓ Branch 0 taken 404 times.
✗ Branch 1 not taken.
404 if (mdm->has_luminance) {
408 404 fmt.color.min_luma = mdm->min_luminance;
409 404 fmt.color.max_luma = mdm->max_luminance;
410 }
411
412
1/2
✓ Branch 0 taken 404 times.
✗ Branch 1 not taken.
404 if (mdm->has_primaries) {
413 /* Ignore mastering display white point as it has no bearance on
414 * the underlying content */
415 404 fmt.color.gamut.r.x = mdm->display_primaries[0][0];
416 404 fmt.color.gamut.r.y = mdm->display_primaries[0][1];
417 404 fmt.color.gamut.g.x = mdm->display_primaries[1][0];
418 404 fmt.color.gamut.g.y = mdm->display_primaries[1][1];
419 404 fmt.color.gamut.b.x = mdm->display_primaries[2][0];
420 404 fmt.color.gamut.b.y = mdm->display_primaries[2][1];
421 }
422 }
423
424
2/2
✓ Branch 1 taken 671754 times.
✓ Branch 2 taken 4 times.
671758 if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS))) {
425 4 const AVDynamicHDRPlus *dhp = (const AVDynamicHDRPlus *) sd->data;
426 4 const AVHDRPlusColorTransformParams *pars = &dhp->params[0];
427 4 const AVRational nits = av_make_q(10000, 1);
428 4 AVRational maxrgb = pars->maxscl[0];
429
430
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (!dhp->num_windows || dhp->application_version > 1)
431 goto skip_hdr10;
432
433 /* Maximum of MaxSCL components */
434
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (av_cmp_q(pars->maxscl[1], maxrgb) > 0)
435 maxrgb = pars->maxscl[1];
436
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (av_cmp_q(pars->maxscl[2], maxrgb) > 0)
437 maxrgb = pars->maxscl[2];
438
439
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (maxrgb.num > 0) {
440 /* Estimate true luminance from MaxSCL */
441 4 const AVLumaCoefficients *luma = av_csp_luma_coeffs_from_avcsp(fmt.csp);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!luma)
443 goto skip_hdr10;
444 4 fmt.color.frame_peak = av_add_q(av_mul_q(luma->cr, pars->maxscl[0]),
445 av_add_q(av_mul_q(luma->cg, pars->maxscl[1]),
446 av_mul_q(luma->cb, pars->maxscl[2])));
447 /* Scale the scene average brightness by the ratio between the
448 * maximum luminance and the MaxRGB values */
449 4 fmt.color.frame_avg = av_mul_q(pars->average_maxrgb,
450 av_div_q(fmt.color.frame_peak, maxrgb));
451 } else {
452 /**
453 * Calculate largest value from histogram to use as fallback for
454 * clips with missing MaxSCL information. Note that this may end
455 * up picking the "reserved" value at the 5% percentile, which in
456 * practice appears to track the brightest pixel in the scene.
457 */
458 for (int i = 0; i < pars->num_distribution_maxrgb_percentiles; i++) {
459 const AVRational pct = pars->distribution_maxrgb[i].percentile;
460 if (av_cmp_q(pct, maxrgb) > 0)
461 maxrgb = pct;
462 fmt.color.frame_peak = maxrgb;
463 fmt.color.frame_avg = pars->average_maxrgb;
464 }
465 }
466
467 /* Rescale to nits */
468 4 fmt.color.frame_peak = av_mul_q(nits, fmt.color.frame_peak);
469 4 fmt.color.frame_avg = av_mul_q(nits, fmt.color.frame_avg);
470 }
471 671754 skip_hdr10:
472
473 /* PQ is always scaled down to absolute zero, so ignore mastering metadata */
474
2/2
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 671342 times.
671758 if (fmt.color.trc == AVCOL_TRC_SMPTE2084)
475 416 fmt.color.min_luma = av_make_q(0, 1);
476
477 671758 return fmt;
478 }
479
480 1149184 void ff_fmt_from_pixfmt(enum AVPixelFormat pixfmt, SwsFormat *fmt)
481 {
482 1149184 ff_fmt_clear(fmt);
483 1149184 fmt->format = pixfmt;
484 1149184 fmt->desc = av_pix_fmt_desc_get(pixfmt);
485 1149184 sanitize_fmt(fmt, fmt->desc);
486 1149184 }
487
488 1318680 static int infer_prim_ref(SwsColor *csp, const SwsColor *ref)
489 {
490
2/2
✓ Branch 0 taken 8740 times.
✓ Branch 1 taken 1309940 times.
1318680 if (csp->prim != AVCOL_PRI_UNSPECIFIED)
491 8740 return 0;
492
493 /* Reuse the reference gamut only for "safe", similar primaries */
494
2/2
✓ Branch 0 taken 659250 times.
✓ Branch 1 taken 650690 times.
1309940 switch (ref->prim) {
495 659250 case AVCOL_PRI_BT709:
496 case AVCOL_PRI_BT470M:
497 case AVCOL_PRI_BT470BG:
498 case AVCOL_PRI_SMPTE170M:
499 case AVCOL_PRI_SMPTE240M:
500 659250 csp->prim = ref->prim;
501 659250 csp->gamut = ref->gamut;
502 659250 break;
503 650690 default:
504 650690 csp->prim = AVCOL_PRI_BT709;
505 650690 csp->gamut = av_csp_primaries_desc_from_id(csp->prim)->prim;
506 650690 break;
507 }
508
509 1309940 return 1;
510 }
511
512 1318680 static int infer_trc_ref(SwsColor *csp, const SwsColor *ref)
513 {
514
2/2
✓ Branch 0 taken 8888 times.
✓ Branch 1 taken 1309792 times.
1318680 if (csp->trc != AVCOL_TRC_UNSPECIFIED)
515 8888 return 0;
516
517 /* Pick a suitable SDR transfer function, to try and minimize conversions */
518
2/2
✓ Branch 0 taken 650616 times.
✓ Branch 1 taken 659176 times.
1309792 switch (ref->trc) {
519 650616 case AVCOL_TRC_UNSPECIFIED:
520 /* HDR curves, never default to these */
521 case AVCOL_TRC_SMPTE2084:
522 case AVCOL_TRC_ARIB_STD_B67:
523 650616 csp->trc = AVCOL_TRC_BT709;
524 650616 csp->min_luma = av_make_q(0, 1);
525 650616 csp->max_luma = av_make_q(203, 1);
526 650616 break;
527 659176 default:
528 659176 csp->trc = ref->trc;
529 659176 csp->min_luma = ref->min_luma;
530 659176 csp->max_luma = ref->max_luma;
531 659176 break;
532 }
533
534 1309792 return 1;
535 }
536
537 659340 bool ff_infer_colors(SwsColor *src, SwsColor *dst)
538 {
539 659340 int incomplete = 0;
540
541 659340 incomplete |= infer_prim_ref(dst, src);
542 659340 incomplete |= infer_prim_ref(src, dst);
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 659340 times.
659340 av_assert0(src->prim != AVCOL_PRI_UNSPECIFIED);
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 659340 times.
659340 av_assert0(dst->prim != AVCOL_PRI_UNSPECIFIED);
545
546 659340 incomplete |= infer_trc_ref(dst, src);
547 659340 incomplete |= infer_trc_ref(src, dst);
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 659340 times.
659340 av_assert0(src->trc != AVCOL_TRC_UNSPECIFIED);
549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 659340 times.
659340 av_assert0(dst->trc != AVCOL_TRC_UNSPECIFIED);
550
551 659340 return incomplete;
552 }
553
554 79018 void ff_sws_chroma_pos(const SwsFormat *fmt, bool *incomplete,
555 int *out_x_pos, int *out_y_pos)
556 {
557 79018 enum AVChromaLocation chroma_loc = fmt->loc;
558 79018 const int sub_x = fmt->desc->log2_chroma_w;
559 79018 const int sub_y = fmt->desc->log2_chroma_h;
560 int x_pos, y_pos;
561
562 /* Explicitly default to center siting for compatibility with swscale */
563
2/2
✓ Branch 0 taken 79017 times.
✓ Branch 1 taken 1 times.
79018 if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
564 79017 chroma_loc = AVCHROMA_LOC_CENTER;
565
4/4
✓ Branch 0 taken 72914 times.
✓ Branch 1 taken 6103 times.
✓ Branch 2 taken 240 times.
✓ Branch 3 taken 72674 times.
79017 *incomplete |= sub_x || sub_y;
566 }
567
568 /* av_chroma_location_enum_to_pos() always gives us values in the range from
569 * 0 to 256, but we need to adjust this to the true value range of the
570 * subsampling grid, which may be larger for h/v_sub > 1 */
571 79018 av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
572 79018 x_pos *= (1 << sub_x) - 1;
573 79018 y_pos *= (1 << sub_y) - 1;
574
575 /* Fix vertical chroma position for interlaced frames */
576
3/4
✓ Branch 0 taken 4923 times.
✓ Branch 1 taken 74095 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4923 times.
79018 if (sub_y && fmt->interlaced) {
577 /* When vertically subsampling, chroma samples are effectively only
578 * placed next to even rows. To access them from the odd field, we need
579 * to account for this shift by offsetting the distance of one luma row.
580 *
581 * For 4x vertical subsampling (v_sub == 2), they are only placed
582 * next to every *other* even row, so we need to shift by three luma
583 * rows to get to the chroma sample. */
584 if (fmt->field == FIELD_BOTTOM)
585 y_pos += (256 << sub_y) - 256;
586
587 /* Luma row distance is doubled for fields, so halve offsets */
588 y_pos >>= 1;
589 }
590
591 79018 *out_x_pos = x_pos;
592 79018 *out_y_pos = y_pos;
593 79018 }
594
595 /* Variant of sws_test_format() for the ops-based code */
596 static int test_format_ops(enum AVPixelFormat format, int output);
597 4066880 static int test_format_legacy(enum AVPixelFormat format, int output)
598 {
599
2/2
✓ Branch 0 taken 2045000 times.
✓ Branch 1 taken 2021880 times.
4066880 return output ? sws_isSupportedOutput(format) : sws_isSupportedInput(format);
600 }
601
602 4354850 int ff_sws_test_pixfmt_backend(const SwsBackend backends,
603 enum AVPixelFormat format, int output)
604 {
605 /* The only non-ops backend is the legacy backend */
606 4354850 const SwsBackend backends_ops = SWS_BACKEND_ALL ^ SWS_BACKEND_LEGACY;
607
4/4
✓ Branch 0 taken 4066880 times.
✓ Branch 1 taken 287970 times.
✓ Branch 3 taken 710669 times.
✓ Branch 4 taken 3356211 times.
5353489 return ((backends & SWS_BACKEND_LEGACY) && test_format_legacy(format, output)) ||
608
4/4
✓ Branch 0 taken 329939 times.
✓ Branch 1 taken 668700 times.
✓ Branch 3 taken 257619 times.
✓ Branch 4 taken 72320 times.
998639 ((backends & backends_ops) && test_format_ops(format, output));
609 }
610
611 3584232 int sws_test_format(enum AVPixelFormat format, int output)
612 {
613 3584232 return ff_sws_test_pixfmt_backend(SWS_BACKEND_STABLE, format, output);
614 }
615
616 450604 int sws_test_hw_format(enum AVPixelFormat format)
617 {
618
1/2
✓ Branch 0 taken 450604 times.
✗ Branch 1 not taken.
450604 switch (format) {
619 450604 case AV_PIX_FMT_NONE: return 1;
620 #if CONFIG_VULKAN
621 case AV_PIX_FMT_VULKAN: return 1;
622 #endif
623 default: return 0;
624 }
625 }
626
627 689205 int sws_test_colorspace(enum AVColorSpace csp, int output)
628 {
629
2/2
✓ Branch 0 taken 568857 times.
✓ Branch 1 taken 120348 times.
689205 switch (csp) {
630 568857 case AVCOL_SPC_UNSPECIFIED:
631 case AVCOL_SPC_RGB:
632 case AVCOL_SPC_BT709:
633 case AVCOL_SPC_BT470BG:
634 case AVCOL_SPC_SMPTE170M:
635 case AVCOL_SPC_FCC:
636 case AVCOL_SPC_SMPTE240M:
637 case AVCOL_SPC_BT2020_NCL:
638 568857 return 1;
639 120348 default:
640 120348 return 0;
641 }
642 }
643
644 450604 int sws_test_primaries(enum AVColorPrimaries prim, int output)
645 {
646
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
450604 return ((prim > AVCOL_PRI_RESERVED0 && prim < AVCOL_PRI_NB) ||
647
2/6
✓ Branch 0 taken 450604 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 450604 times.
✗ Branch 5 not taken.
901208 (prim >= AVCOL_PRI_EXT_BASE && prim < AVCOL_PRI_EXT_NB)) &&
648 prim != AVCOL_PRI_RESERVED;
649 }
650
651 450604 int sws_test_transfer(enum AVColorTransferCharacteristic trc, int output)
652 {
653 225302 av_csp_eotf_function eotf = output ? av_csp_itu_eotf_inv(trc)
654
2/2
✓ Branch 0 taken 225302 times.
✓ Branch 1 taken 225302 times.
450604 : av_csp_itu_eotf(trc);
655
3/4
✓ Branch 0 taken 1393 times.
✓ Branch 1 taken 449211 times.
✓ Branch 2 taken 1393 times.
✗ Branch 3 not taken.
450604 return trc == AVCOL_TRC_UNSPECIFIED || eotf != NULL;
656 }
657
658 450604 static int test_range(enum AVColorRange range)
659 {
660 450604 return (unsigned)range < AVCOL_RANGE_NB;
661 }
662
663 450604 static int test_loc(enum AVChromaLocation loc)
664 {
665 450604 return (unsigned)loc < AVCHROMA_LOC_NB;
666 }
667
668 450604 int ff_test_fmt(const SwsBackend backends, const SwsFormat *fmt, int output)
669 {
670
2/4
✓ Branch 0 taken 450604 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 450604 times.
✗ Branch 3 not taken.
901208 return fmt->width > 0 && fmt->height > 0 &&
671
1/2
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
901208 ff_sws_test_pixfmt_backend(backends, fmt->format, output) &&
672
1/2
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
901208 sws_test_colorspace(fmt->csp, output) &&
673
1/2
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
901208 sws_test_primaries (fmt->color.prim, output) &&
674
1/2
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
901208 sws_test_transfer (fmt->color.trc, output) &&
675
1/2
✓ Branch 1 taken 450604 times.
✗ Branch 2 not taken.
901208 sws_test_hw_format (fmt->hw_format) &&
676
2/4
✓ Branch 0 taken 450604 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 450604 times.
✗ Branch 4 not taken.
1351812 test_range (fmt->range) &&
677 450604 test_loc (fmt->loc);
678 }
679
680 int sws_test_frame(const AVFrame *frame, int output)
681 {
682 for (int field = 0; field < 2; field++) {
683 const SwsFormat fmt = ff_fmt_from_frame(frame, field);
684 if (!ff_test_fmt(SWS_BACKEND_STABLE, &fmt, output))
685 return 0;
686 if (!fmt.interlaced)
687 break;
688 }
689
690 return 1;
691 }
692
693 110577 int sws_is_noop(const AVFrame *dst, const AVFrame *src)
694 {
695
1/2
✓ Branch 0 taken 110577 times.
✗ Branch 1 not taken.
110577 for (int field = 0; field < 2; field++) {
696 110577 SwsFormat dst_fmt = ff_fmt_from_frame(dst, field);
697 110577 SwsFormat src_fmt = ff_fmt_from_frame(src, field);
698
2/2
✓ Branch 1 taken 105659 times.
✓ Branch 2 taken 4918 times.
110577 if (!ff_fmt_equal(&dst_fmt, &src_fmt))
699 105659 return 0;
700
1/2
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
4918 if (!dst_fmt.interlaced)
701 4918 break;
702 }
703
704 4918 return 1;
705 }
706
707 403570 void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src)
708 {
709 403570 dst->format = src->format;
710 403570 dst->width = src->width;
711 403570 dst->height = src->height;
712 403570 dst->avframe = src;
713
2/2
✓ Branch 0 taken 1614280 times.
✓ Branch 1 taken 403570 times.
2017850 for (int i = 0; i < FF_ARRAY_ELEMS(dst->data); i++) {
714 1614280 dst->data[i] = src->data[i];
715 1614280 dst->linesize[i] = src->linesize[i];
716 }
717 403570 }
718
719 #if CONFIG_UNSTABLE
720
721 /**
722 * Returns the underlying descriptor for fake formats like PAL8 whose
723 * descriptors alone do not fully describe the pixel data.
724 */
725 7638142 static inline const AVPixFmtDescriptor *fmt_desc_decoded(enum AVPixelFormat fmt)
726 {
727
2/2
✓ Branch 0 taken 34328 times.
✓ Branch 1 taken 7603814 times.
7638142 if (fmt == AV_PIX_FMT_PAL8)
728 34328 return av_pix_fmt_desc_get(AV_PIX_FMT_RGB32);
729
730 7603814 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7603814 times.
7603814 av_assert0(!(desc->flags & AV_PIX_FMT_FLAG_PAL));
732 7603814 return desc;
733 }
734
735 /* Returns the type suitable for a pixel after fully decoding/unpacking it */
736 3271913 static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt)
737 {
738 3271913 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt);
739 3271913 const int bits = FFALIGN(desc->comp[0].depth, 8);
740
2/2
✓ Branch 0 taken 325067 times.
✓ Branch 1 taken 2946846 times.
3271913 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
741
2/2
✓ Branch 0 taken 277931 times.
✓ Branch 1 taken 47136 times.
325067 switch (bits) {
742 277931 case 32: return SWS_PIXEL_F32;
743 /* TODO: no support for 16-bit float yet */
744 }
745 } else {
746
3/3
✓ Branch 0 taken 1040591 times.
✓ Branch 1 taken 1817579 times.
✓ Branch 2 taken 88676 times.
2946846 switch (bits) {
747 1040591 case 8: return SWS_PIXEL_U8;
748 1817579 case 16: return SWS_PIXEL_U16;
749 /* TODO: AVRational cannot represent UINT32_MAX */
750 }
751 }
752
753 135812 return SWS_PIXEL_NONE;
754 }
755
756 /* A regular format is defined as any format that contains only a single
757 * component per elementary data type (i.e. no sub-byte pack/unpack needed),
758 * and whose components map 1:1 onto elementary data units */
759 1672531 static int is_regular_fmt(enum AVPixelFormat fmt)
760 {
761 1672531 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
762
2/2
✓ Branch 0 taken 54232 times.
✓ Branch 1 taken 1618299 times.
1672531 if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER))
763 54232 return 0; /* no 1:1 correspondence between components and data units */
764
2/2
✓ Branch 0 taken 76897 times.
✓ Branch 1 taken 1541402 times.
1618299 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM))
765 76897 return 0; /* bitstream formats are packed by definition */
766
4/4
✓ Branch 0 taken 896053 times.
✓ Branch 1 taken 645349 times.
✓ Branch 2 taken 157252 times.
✓ Branch 3 taken 738801 times.
1541402 if ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) || desc->nb_components == 1)
767 802601 return 1; /* planar formats are regular by definition */
768
769 738801 const int step = desc->comp[0].step;
770 738801 int total_bits = 0;
771
772
2/2
✓ Branch 0 taken 1885730 times.
✓ Branch 1 taken 439608 times.
2325338 for (int i = 0; i < desc->nb_components; i++) {
773
3/4
✓ Branch 0 taken 1586537 times.
✓ Branch 1 taken 299193 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1586537 times.
1885730 if (desc->comp[i].shift || desc->comp[i].step != step)
774 299193 return 0; /* irregular/packed format */
775 1586537 total_bits += desc->comp[i].depth;
776 }
777
778 /* Exclude formats with missing components like RGB0, 0RGB, etc. */
779 439608 return total_bits == step * 8;
780 }
781
782 typedef struct FmtInfo {
783 SwsReadWriteOp rw;
784 SwsSwizzleOp swizzle;
785 SwsPackOp pack;
786 int shift;
787 } FmtInfo;
788
789 #define BITSTREAM_FMT(SWIZ, FRAC, MODE, ...) (FmtInfo) { \
790 .rw = { .elems = 1, .frac = FRAC, .mode = MODE }, \
791 .swizzle = SWIZ, \
792 __VA_ARGS__ \
793 }
794
795 #define SUBPACKED_FMT(SWIZ, ...) (FmtInfo) { \
796 .rw = { .elems = 1, .mode = SWS_RW_PACKED }, \
797 .swizzle = SWIZ, \
798 .pack.pattern = {__VA_ARGS__}, \
799 }
800
801 #define PACKED_FMT(SWIZ, N, ...) (FmtInfo) { \
802 .rw = { .elems = N, .mode = SWS_RW_PACKED }, \
803 .swizzle = SWIZ, \
804 __VA_ARGS__ \
805 }
806
807 #define RGBA SWS_SWIZZLE(0, 1, 2, 3)
808 #define BGRA SWS_SWIZZLE(2, 1, 0, 3)
809 #define ARGB SWS_SWIZZLE(3, 0, 1, 2)
810 #define ABGR SWS_SWIZZLE(3, 2, 1, 0)
811 #define AVYU SWS_SWIZZLE(3, 2, 0, 1)
812 #define VYUA SWS_SWIZZLE(2, 0, 1, 3)
813 #define UYVA SWS_SWIZZLE(1, 0, 2, 3)
814 #define VUYA BGRA
815
816 514533 static FmtInfo fmt_info_irregular(enum AVPixelFormat fmt)
817 {
818
26/26
✓ Branch 0 taken 23978 times.
✓ Branch 1 taken 12997 times.
✓ Branch 2 taken 12993 times.
✓ Branch 3 taken 12019 times.
✓ Branch 4 taken 11989 times.
✓ Branch 5 taken 11965 times.
✓ Branch 6 taken 12052 times.
✓ Branch 7 taken 24140 times.
✓ Branch 8 taken 24104 times.
✓ Branch 9 taken 24089 times.
✓ Branch 10 taken 24101 times.
✓ Branch 11 taken 24050 times.
✓ Branch 12 taken 24005 times.
✓ Branch 13 taken 25290 times.
✓ Branch 14 taken 25381 times.
✓ Branch 15 taken 25544 times.
✓ Branch 16 taken 25552 times.
✓ Branch 17 taken 12058 times.
✓ Branch 18 taken 12106 times.
✓ Branch 19 taken 11908 times.
✓ Branch 20 taken 12091 times.
✓ Branch 21 taken 12058 times.
✓ Branch 22 taken 24083 times.
✓ Branch 23 taken 23990 times.
✓ Branch 24 taken 7096 times.
✓ Branch 25 taken 54894 times.
514533 switch (fmt) {
819 /* Bitstream formats */
820 23978 case AV_PIX_FMT_MONOWHITE:
821 case AV_PIX_FMT_MONOBLACK:
822 23978 return BITSTREAM_FMT(RGBA, 3, SWS_RW_PLANAR);
823 12997 case AV_PIX_FMT_RGB4: return BITSTREAM_FMT(RGBA, 1, SWS_RW_PACKED, .pack = {{ 1, 2, 1 }});
824 12993 case AV_PIX_FMT_BGR4: return BITSTREAM_FMT(BGRA, 1, SWS_RW_PACKED, .pack = {{ 1, 2, 1 }});
825
826 /* Sub-packed 8-bit aligned formats */
827 12019 case AV_PIX_FMT_RGB4_BYTE: return SUBPACKED_FMT(RGBA, 1, 2, 1);
828 11989 case AV_PIX_FMT_BGR4_BYTE: return SUBPACKED_FMT(BGRA, 1, 2, 1);
829 11965 case AV_PIX_FMT_RGB8: return SUBPACKED_FMT(RGBA, 3, 3, 2);
830 12052 case AV_PIX_FMT_BGR8: return SUBPACKED_FMT(BGRA, 2, 3, 3);
831
832 /* Sub-packed 16-bit aligned formats */
833 24140 case AV_PIX_FMT_RGB565LE:
834 case AV_PIX_FMT_RGB565BE:
835 24140 return SUBPACKED_FMT(RGBA, 5, 6, 5);
836 24104 case AV_PIX_FMT_BGR565LE:
837 case AV_PIX_FMT_BGR565BE:
838 24104 return SUBPACKED_FMT(BGRA, 5, 6, 5);
839 24089 case AV_PIX_FMT_RGB555LE:
840 case AV_PIX_FMT_RGB555BE:
841 24089 return SUBPACKED_FMT(RGBA, 5, 5, 5);
842 24101 case AV_PIX_FMT_BGR555LE:
843 case AV_PIX_FMT_BGR555BE:
844 24101 return SUBPACKED_FMT(BGRA, 5, 5, 5);
845 24050 case AV_PIX_FMT_RGB444LE:
846 case AV_PIX_FMT_RGB444BE:
847 24050 return SUBPACKED_FMT(RGBA, 4, 4, 4);
848 24005 case AV_PIX_FMT_BGR444LE:
849 case AV_PIX_FMT_BGR444BE:
850 24005 return SUBPACKED_FMT(BGRA, 4, 4, 4);
851
852 /* Sub-packed 32-bit aligned formats */
853 25290 case AV_PIX_FMT_X2RGB10LE:
854 case AV_PIX_FMT_X2RGB10BE:
855 25290 return SUBPACKED_FMT(ARGB, 2, 10, 10, 10);
856 25381 case AV_PIX_FMT_X2BGR10LE:
857 case AV_PIX_FMT_X2BGR10BE:
858 25381 return SUBPACKED_FMT(ABGR, 2, 10, 10, 10);
859 25544 case AV_PIX_FMT_XV30LE:
860 case AV_PIX_FMT_XV30BE:
861 25544 return SUBPACKED_FMT(AVYU, 2, 10, 10, 10);
862 25552 case AV_PIX_FMT_V30XLE:
863 case AV_PIX_FMT_V30XBE:
864 25552 return SUBPACKED_FMT(VYUA, 10, 10, 10, 2);
865
866 /* 3-component formats with extra padding */
867 12058 case AV_PIX_FMT_RGB0: return PACKED_FMT(RGBA, 4);
868 12106 case AV_PIX_FMT_BGR0: return PACKED_FMT(BGRA, 4);
869 11908 case AV_PIX_FMT_0RGB: return PACKED_FMT(ARGB, 4);
870 12091 case AV_PIX_FMT_0BGR: return PACKED_FMT(ABGR, 4);
871 12058 case AV_PIX_FMT_VUYX: return PACKED_FMT(VUYA, 4);
872 24083 case AV_PIX_FMT_XV36LE:
873 case AV_PIX_FMT_XV36BE:
874 24083 return PACKED_FMT(UYVA, 4, .shift = 4);
875 23990 case AV_PIX_FMT_XV48LE:
876 case AV_PIX_FMT_XV48BE:
877 23990 return PACKED_FMT(UYVA, 4);
878
879 /* Miscellaneous irregular formats */
880 7096 case AV_PIX_FMT_PAL8:
881 7096 return (FmtInfo) {
882 .rw = { .elems = 4, .mode = SWS_RW_PALETTE },
883 /* PAL8 is explicitly defined as endian-dependent */
884 #if AV_HAVE_BIGENDIAN
885 .swizzle = ARGB,
886 #else
887 .swizzle = BGRA,
888 #endif
889 };
890 }
891
892 54894 return (FmtInfo) {0};
893 }
894
895 struct comp {
896 int index;
897 int plane;
898 int offset;
899 };
900
901 /* Compare by (plane, offset) */
902 3222174 static int cmp_comp(const void *a, const void *b) {
903 3222174 const struct comp *ca = a;
904 3222174 const struct comp *cb = b;
905
2/2
✓ Branch 0 taken 2122688 times.
✓ Branch 1 taken 1099486 times.
3222174 if (ca->plane != cb->plane)
906 2122688 return ca->plane - cb->plane;
907 1099486 return ca->offset - cb->offset;
908 }
909
910 1157998 static int fmt_analyze_regular(const AVPixFmtDescriptor *desc, SwsReadWriteOp *rw_op,
911 SwsSwizzleOp *swizzle, SwsShiftOp *shift)
912 {
913
2/2
✓ Branch 0 taken 61810 times.
✓ Branch 1 taken 1096188 times.
1157998 if (desc->nb_components == 2) {
914 /* YA formats */
915 61810 *swizzle = SWS_SWIZZLE(0, 3, 1, 2);
916 } else {
917 /* Sort by increasing component order */
918 1096188 struct comp sorted[4] = { {0}, {1}, {2}, {3} };
919
2/2
✓ Branch 0 taken 3404729 times.
✓ Branch 1 taken 1096188 times.
4500917 for (int i = 0; i < desc->nb_components; i++) {
920 3404729 sorted[i].plane = desc->comp[i].plane;
921 3404729 sorted[i].offset = desc->comp[i].offset;
922 }
923
924 1096188 qsort(sorted, desc->nb_components, sizeof(struct comp), cmp_comp);
925
926 1096188 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
927
2/2
✓ Branch 0 taken 3404729 times.
✓ Branch 1 taken 1096188 times.
4500917 for (int i = 0; i < desc->nb_components; i++)
928 3404729 swiz.in[i] = sorted[i].index;
929 1096188 *swizzle = swiz;
930 }
931
932 1157998 SwsReadWriteMode mode = SWS_RW_PLANAR;
933
4/4
✓ Branch 0 taken 1000746 times.
✓ Branch 1 taken 157252 times.
✓ Branch 2 taken 355397 times.
✓ Branch 3 taken 645349 times.
1157998 if (desc->nb_components > 1 && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR))
934 355397 mode = SWS_RW_PACKED;
935
936 1157998 *shift = (SwsShiftOp) { desc->comp[0].shift };
937 1157998 *rw_op = (SwsReadWriteOp) {
938 1157998 .elems = desc->nb_components,
939 .mode = mode,
940 };
941 1157998 return 0;
942 }
943
944 2082949 static int fmt_analyze(enum AVPixelFormat fmt, SwsReadWriteOp *rw_op,
945 SwsPackOp *pack_op, SwsSwizzleOp *swizzle,
946 SwsShiftOp *shift, SwsPixelType *pixel_type,
947 SwsPixelType *raw_type)
948 {
949 2082949 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2082949 times.
2082949 if (!desc)
951 return AVERROR(EINVAL);
952
953 /* No support for subsampled formats at the moment */
954
4/4
✓ Branch 0 taken 1821487 times.
✓ Branch 1 taken 261462 times.
✓ Branch 2 taken 21480 times.
✓ Branch 3 taken 1800007 times.
2082949 if (desc->log2_chroma_w || desc->log2_chroma_h)
955 282942 return AVERROR(ENOTSUP);
956
957 /* No support for semi-planar formats at the moment */
958
2/2
✓ Branch 0 taken 693749 times.
✓ Branch 1 taken 1106258 times.
1800007 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR &&
959
2/2
✓ Branch 1 taken 31032 times.
✓ Branch 2 taken 662717 times.
693749 av_pix_fmt_count_planes(fmt) < desc->nb_components)
960 31032 return AVERROR(ENOTSUP);
961
962 1768975 *pixel_type = *raw_type = fmt_pixel_type(fmt);
963
2/2
✓ Branch 0 taken 96444 times.
✓ Branch 1 taken 1672531 times.
1768975 if (!*pixel_type)
964 96444 return AVERROR(ENOTSUP);
965
966
2/2
✓ Branch 1 taken 1157998 times.
✓ Branch 2 taken 514533 times.
1672531 if (is_regular_fmt(fmt)) {
967 1157998 *pack_op = (SwsPackOp) {0};
968 1157998 return fmt_analyze_regular(desc, rw_op, swizzle, shift);
969 }
970
971 514533 FmtInfo info = fmt_info_irregular(fmt);
972
2/2
✓ Branch 0 taken 54894 times.
✓ Branch 1 taken 459639 times.
514533 if (!info.rw.elems)
973 54894 return AVERROR(ENOTSUP);
974
975 459639 *rw_op = info.rw;
976 459639 *pack_op = info.pack;
977 459639 *swizzle = info.swizzle;
978 459639 *shift = (SwsShiftOp) { info.shift };
979
980
2/2
✓ Branch 0 taken 320271 times.
✓ Branch 1 taken 139368 times.
459639 if (info.pack.pattern[0]) {
981 320271 const int sum = info.pack.pattern[0] + info.pack.pattern[1] +
982 320271 info.pack.pattern[2] + info.pack.pattern[3];
983
2/2
✓ Branch 0 taken 101767 times.
✓ Branch 1 taken 218504 times.
320271 if (sum > 16)
984 101767 *raw_type = SWS_PIXEL_U32;
985
2/2
✓ Branch 0 taken 144489 times.
✓ Branch 1 taken 74015 times.
218504 else if (sum > 8)
986 144489 *raw_type = SWS_PIXEL_U16;
987 else
988 74015 *raw_type = SWS_PIXEL_U8;
989 }
990
991 459639 return 0;
992 }
993
994 329939 static int test_format_ops(enum AVPixelFormat format, int output)
995 {
996 SwsReadWriteOp rw;
997 SwsSwizzleOp swizzle;
998 SwsPackOp pack;
999 SwsShiftOp shift;
1000 SwsPixelType pixel_type, raw_type;
1001 329939 int ret = fmt_analyze(format, &rw, &pack, &swizzle, &shift,
1002 &pixel_type, &raw_type);
1003
2/2
✓ Branch 0 taken 71600 times.
✓ Branch 1 taken 258339 times.
329939 if (ret < 0)
1004 71600 return 0;
1005
3/4
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 257619 times.
✓ Branch 2 taken 720 times.
✗ Branch 3 not taken.
258339 if (rw.mode == SWS_RW_PALETTE && output)
1006 720 return 0; /* palettes are currently only supported as input */
1007 257619 return 1;
1008 }
1009
1010 751469 static void swizzle_inv(SwsSwizzleOp *swiz)
1011 {
1012 /* Input[x] =: Output[swizzle.x] */
1013 unsigned tmp[4];
1014 751469 tmp[swiz->x] = 0;
1015 751469 tmp[swiz->y] = 1;
1016 751469 tmp[swiz->z] = 2;
1017 751469 tmp[swiz->w] = 3;
1018 751469 *swiz = (SwsSwizzleOp) {{ .x = tmp[0], tmp[1], tmp[2], tmp[3] }};
1019 751469 }
1020
1021 /**
1022 * This initializes all absent components explicitly to zero. There is no
1023 * need to worry about the correct neutral value as fmt_decode() will
1024 * implicitly ignore and overwrite absent components in any case. This function
1025 * is just to ensure that we don't operate on undefined memory. In most cases,
1026 * it will end up getting pushed towards the output or optimized away entirely
1027 * by the optimization pass.
1028 */
1029 751469 static SwsClearOp fmt_clear(const SwsFormat *fmt)
1030 {
1031 751469 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1032 751469 const bool has_chroma = desc->nb_components >= 3;
1033 751469 const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
1034
1035 751469 SwsClearOp c = {0};
1036
2/2
✓ Branch 0 taken 113427 times.
✓ Branch 1 taken 638042 times.
751469 if (!has_chroma) {
1037 113427 c.mask |= SWS_COMP(1) | SWS_COMP(2);
1038 113427 c.value[1] = c.value[2] = Q(0);
1039 }
1040
1041
2/2
✓ Branch 0 taken 519794 times.
✓ Branch 1 taken 231675 times.
751469 if (!has_alpha) {
1042 519794 c.mask |= SWS_COMP(3);
1043 519794 c.value[3] = Q(0);
1044 }
1045
1046 751469 return c;
1047 }
1048
1049 #if HAVE_BIGENDIAN
1050 # define NATIVE_ENDIAN_FLAG AV_PIX_FMT_FLAG_BE
1051 #else
1052 # define NATIVE_ENDIAN_FLAG 0
1053 #endif
1054
1055 6216840 static inline AVRational64 intmax_q64(int bits)
1056 {
1057 av_assert1(bits >= 0 && bits < 64);
1058 6216840 return Q(UINT64_MAX >> (64 - bits));
1059 }
1060
1061 1040909 int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
1062 {
1063 1040909 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1064 SwsPixelType pixel_type, raw_type;
1065 SwsReadWriteOp rw_op;
1066 SwsSwizzleOp swizzle;
1067 SwsPackOp unpack;
1068 1040909 SwsComps *comps = &ops->comps_src;
1069 SwsShiftOp shift;
1070
1071
2/2
✓ Branch 1 taken 289440 times.
✓ Branch 2 taken 751469 times.
1040909 RET(fmt_analyze(fmt->format, &rw_op, &unpack, &swizzle, &shift,
1072 &pixel_type, &raw_type));
1073
1074 751469 swizzle_inv(&swizzle);
1075
1076 /* Set baseline pixel content flags */
1077 751469 const int integer = ff_sws_pixel_type_is_int(raw_type);
1078
2/2
✓ Branch 0 taken 577151 times.
✓ Branch 1 taken 174318 times.
1328620 const int swapped = ff_sws_pixel_type_size(raw_type) > 1 &&
1079
2/2
✓ Branch 0 taken 289149 times.
✓ Branch 1 taken 288002 times.
577151 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG;
1080
2/2
✓ Branch 0 taken 2014618 times.
✓ Branch 1 taken 751469 times.
2766087 for (int i = 0; i < rw_op.elems; i++) {
1081
2/2
✓ Branch 0 taken 1813747 times.
✓ Branch 1 taken 200871 times.
4029236 comps->flags[i] = (integer ? SWS_COMP_EXACT : 0) |
1082
2/2
✓ Branch 0 taken 758226 times.
✓ Branch 1 taken 1256392 times.
2014618 (swapped ? SWS_COMP_SWAPPED : 0);
1083 }
1084
1085 /* Generate value range information for simple unpacked formats */
1086
4/4
✓ Branch 0 taken 680580 times.
✓ Branch 1 taken 70889 times.
✓ Branch 2 taken 533024 times.
✓ Branch 3 taken 147556 times.
751469 if (integer && !unpack.pattern[0]) {
1087 /* YA formats have desc->comp[] in the order {Y, A} instead of the
1088 * canonical order {Y, U, V, A} */
1089 533024 const int is_ya = desc->nb_components == 2;
1090
2/2
✓ Branch 0 taken 1615689 times.
✓ Branch 1 taken 533024 times.
2148713 for (int c = 0; c < desc->nb_components; c++) {
1091 1615689 const int bits = desc->comp[c].depth + shift.amount;
1092
2/2
✓ Branch 0 taken 33648 times.
✓ Branch 1 taken 1582041 times.
1615689 const int idx = swizzle.in[is_ya ? 3 * c : c];
1093 1615689 comps->min[idx] = Q(0);
1094 1615689 comps->max[idx] = intmax_q64(bits);
1095 }
1096 }
1097
1098 /* TODO: handle subsampled or semipacked input formats */
1099
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 751469 times.
751469 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1100 .op = SWS_OP_READ,
1101 .type = raw_type,
1102 .rw = rw_op,
1103 }));
1104
1105
2/2
✓ Branch 0 taken 289149 times.
✓ Branch 1 taken 462320 times.
751469 if (swapped) {
1106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 289149 times.
289149 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1107 .op = SWS_OP_SWAP_BYTES,
1108 .type = raw_type,
1109 }));
1110 }
1111
1112
2/2
✓ Branch 0 taken 147556 times.
✓ Branch 1 taken 603913 times.
751469 if (unpack.pattern[0]) {
1113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147556 times.
147556 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1114 .op = SWS_OP_UNPACK,
1115 .type = raw_type,
1116 .pack = unpack,
1117 }));
1118
1119
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147556 times.
147556 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1120 .op = SWS_OP_CONVERT,
1121 .type = raw_type,
1122 .convert.to = pixel_type,
1123 }));
1124 }
1125
1126
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 751469 times.
751469 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1127 .op = SWS_OP_SWIZZLE,
1128 .type = pixel_type,
1129 .swizzle = swizzle,
1130 }));
1131
1132
2/2
✓ Branch 0 taken 56167 times.
✓ Branch 1 taken 695302 times.
751469 if (shift.amount) {
1133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 56167 times.
56167 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1134 .op = SWS_OP_RSHIFT,
1135 .type = pixel_type,
1136 .shift = shift,
1137 }));
1138 }
1139
1140
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 751469 times.
751469 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1141 .op = SWS_OP_CLEAR,
1142 .type = pixel_type,
1143 .clear = fmt_clear(fmt),
1144 }));
1145
1146 751469 return 0;
1147 }
1148
1149 712101 int ff_sws_encode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
1150 {
1151 712101 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1152 SwsPixelType pixel_type, raw_type;
1153 SwsReadWriteOp rw_op;
1154 SwsSwizzleOp swizzle;
1155 SwsPackOp pack;
1156 SwsShiftOp shift;
1157
1158
2/2
✓ Branch 1 taken 104272 times.
✓ Branch 2 taken 607829 times.
712101 RET(fmt_analyze(fmt->format, &rw_op, &pack, &swizzle, &shift,
1159 &pixel_type, &raw_type));
1160
1161
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 606765 times.
607829 if (rw_op.mode == SWS_RW_PALETTE)
1162 1064 return AVERROR(ENOTSUP);
1163
1164
2/2
✓ Branch 0 taken 45579 times.
✓ Branch 1 taken 561186 times.
606765 if (shift.amount) {
1165
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45579 times.
45579 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1166 .op = SWS_OP_LSHIFT,
1167 .type = pixel_type,
1168 .shift = shift,
1169 }));
1170 }
1171
1172
2/2
✓ Branch 0 taken 40979 times.
✓ Branch 1 taken 565786 times.
606765 if (rw_op.elems > desc->nb_components) {
1173 /* Format writes unused alpha channel, clear it explicitly for sanity */
1174 av_assert1(!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
1175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40979 times.
40979 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1176 .op = SWS_OP_CLEAR,
1177 .type = pixel_type,
1178 .clear.mask = SWS_COMP(3),
1179 .clear.value[3] = Q(0),
1180 }));
1181 }
1182
1183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 606765 times.
606765 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1184 .op = SWS_OP_SWIZZLE,
1185 .type = pixel_type,
1186 .swizzle = swizzle,
1187 }));
1188
1189
2/2
✓ Branch 0 taken 118447 times.
✓ Branch 1 taken 488318 times.
606765 if (pack.pattern[0]) {
1190
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 118447 times.
118447 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1191 .op = SWS_OP_CONVERT,
1192 .type = pixel_type,
1193 .convert.to = raw_type,
1194 }));
1195
1196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 118447 times.
118447 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1197 .op = SWS_OP_PACK,
1198 .type = raw_type,
1199 .pack = pack,
1200 }));
1201 }
1202
1203
2/2
✓ Branch 0 taken 464832 times.
✓ Branch 1 taken 141933 times.
606765 if (ff_sws_pixel_type_size(raw_type) > 1 &&
1204
2/2
✓ Branch 0 taken 232376 times.
✓ Branch 1 taken 232456 times.
464832 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG) {
1205
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 232376 times.
232376 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1206 .op = SWS_OP_SWAP_BYTES,
1207 .type = raw_type,
1208 }));
1209 }
1210
1211
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 606765 times.
606765 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1212 .op = SWS_OP_WRITE,
1213 .type = raw_type,
1214 .rw = rw_op,
1215 }));
1216
1217 606765 return 0;
1218 }
1219
1220 3016034 static inline AVRational64 av_neg_q64(AVRational64 x)
1221 {
1222 3016034 return (AVRational64) { -x.num, x.den };
1223 }
1224
1225 1463570 static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete)
1226 {
1227 1463570 const AVRational64 q0 = Q(0);
1228 const AVRational64 q1 = Q(1);
1229
1230 1463570 SwsLinearOp c = { .m = {
1231 { q1, q0, q0, q0, q0 },
1232 { q0, q1, q0, q0, q0 },
1233 { q0, q0, q1, q0, q0 },
1234 { q0, q0, q0, q1, q0 },
1235 }};
1236
1237 1463570 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1238 1463570 const int depth0 = desc->comp[0].depth;
1239 1463570 const int depth1 = desc->comp[1].depth;
1240 1463570 const int depth2 = desc->comp[2].depth;
1241 1463570 const int depth3 = desc->comp[3].depth;
1242
1243
2/2
✓ Branch 0 taken 125614 times.
✓ Branch 1 taken 1337956 times.
1463570 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT)
1244 125614 return c; /* floats are directly output as-is */
1245
1246
4/4
✓ Branch 0 taken 667050 times.
✓ Branch 1 taken 670906 times.
✓ Branch 2 taken 2128 times.
✓ Branch 3 taken 664922 times.
1337956 if (fmt->csp == AVCOL_SPC_RGB || (desc->flags & AV_PIX_FMT_FLAG_XYZ)) {
1247 673034 c.m[0][0] = intmax_q64(depth0);
1248 673034 c.m[1][1] = intmax_q64(depth1);
1249 673034 c.m[2][2] = intmax_q64(depth2);
1250
2/2
✓ Branch 0 taken 177144 times.
✓ Branch 1 taken 487778 times.
664922 } else if (fmt->range == AVCOL_RANGE_JPEG) {
1251 /* Full range YUV */
1252 177144 c.m[0][0] = intmax_q64(depth0);
1253
2/2
✓ Branch 0 taken 14444 times.
✓ Branch 1 taken 162700 times.
177144 if (desc->nb_components >= 3) {
1254 /* This follows the ITU-R convention, which is slightly different
1255 * from the JFIF convention. */
1256 14444 c.m[1][1] = intmax_q64(depth1);
1257 14444 c.m[2][2] = intmax_q64(depth2);
1258 14444 c.m[1][4] = Q(1 << (depth1 - 1));
1259 14444 c.m[2][4] = Q(1 << (depth2 - 1));
1260 }
1261 } else {
1262 /* Limited range YUV */
1263
1/2
✓ Branch 0 taken 487778 times.
✗ Branch 1 not taken.
487778 if (fmt->range == AVCOL_RANGE_UNSPECIFIED)
1264 487778 *incomplete = true;
1265 487778 c.m[0][0] = Q(219 << (depth0 - 8));
1266 487778 c.m[0][4] = Q( 16 << (depth0 - 8));
1267
1/2
✓ Branch 0 taken 487778 times.
✗ Branch 1 not taken.
487778 if (desc->nb_components >= 3) {
1268 487778 c.m[1][1] = Q(224 << (depth1 - 8));
1269 487778 c.m[2][2] = Q(224 << (depth2 - 8));
1270 487778 c.m[1][4] = Q(128 << (depth1 - 8));
1271 487778 c.m[2][4] = Q(128 << (depth2 - 8));
1272 }
1273 }
1274
1275
2/2
✓ Branch 0 taken 374549 times.
✓ Branch 1 taken 963407 times.
1337956 if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) {
1276 374549 const bool is_ya = desc->nb_components == 2;
1277
2/2
✓ Branch 0 taken 30506 times.
✓ Branch 1 taken 344043 times.
374549 c.m[3][3] = intmax_q64(is_ya ? depth1 : depth3);
1278 }
1279
1280
2/2
✓ Branch 0 taken 10158 times.
✓ Branch 1 taken 1327798 times.
1337956 if (fmt->format == AV_PIX_FMT_MONOWHITE) {
1281 /* This format is inverted, 0 = white, 1 = black */
1282 10158 c.m[0][4] = av_add_q64(c.m[0][4], c.m[0][0]);
1283 10158 c.m[0][0] = av_neg_q64(c.m[0][0]);
1284 }
1285
1286 1337956 return c;
1287 }
1288
1289 751469 static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete)
1290 {
1291 751469 SwsLinearOp c = fmt_encode_range(fmt, incomplete);
1292
1293 /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */
1294
2/2
✓ Branch 0 taken 3005876 times.
✓ Branch 1 taken 751469 times.
3757345 for (int i = 0; i < 4; i++) {
1295 av_assert1(c.m[i][i].num);
1296 3005876 c.m[i][i] = av_inv_q64(c.m[i][i]);
1297 3005876 c.m[i][4] = av_mul_q64(c.m[i][4], av_neg_q64(c.m[i][i]));
1298 }
1299
1300 /* Explicitly initialize alpha for sanity */
1301
2/2
✓ Branch 0 taken 519794 times.
✓ Branch 1 taken 231675 times.
751469 if (!(fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA))
1302 519794 c.m[3][4] = Q(1);
1303
1304 751469 return c;
1305 }
1306
1307 398180 static AVRational64 *generate_bayer_matrix(const int size_log2)
1308 {
1309 398180 const int size = 1 << size_log2;
1310 398180 const int num_entries = size * size;
1311 398180 AVRational64 *m = av_refstruct_allocz(sizeof(*m) * num_entries);
1312 av_assert1(size_log2 < 16);
1313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 398180 times.
398180 if (!m)
1314 return NULL;
1315
1316 /* Start with a 1x1 matrix */
1317 398180 m[0] = Q(0);
1318
1319 /* Generate three copies of the current, appropriately scaled and offset */
1320
2/2
✓ Branch 0 taken 1592720 times.
✓ Branch 1 taken 398180 times.
1990900 for (int sz = 1; sz < size; sz <<= 1) {
1321 1592720 const int den = 4 * sz * sz;
1322
2/2
✓ Branch 0 taken 5972700 times.
✓ Branch 1 taken 1592720 times.
7565420 for (int y = 0; y < sz; y++) {
1323
2/2
✓ Branch 0 taken 33845300 times.
✓ Branch 1 taken 5972700 times.
39818000 for (int x = 0; x < sz; x++) {
1324 33845300 const AVRational64 cur = m[y * size + x];
1325 33845300 m[(y + sz) * size + x + sz] = av_add_q64(cur, av_make_q64(1, den));
1326 33845300 m[(y ) * size + x + sz] = av_add_q64(cur, av_make_q64(2, den));
1327 33845300 m[(y + sz) * size + x ] = av_add_q64(cur, av_make_q64(3, den));
1328 }
1329 }
1330 }
1331
1332 /**
1333 * To correctly round, we need to evenly distribute the result on [0, 1),
1334 * giving an average value of 1/2.
1335 *
1336 * After the above construction, we have a matrix with average value:
1337 * [ 0/N + 1/N + 2/N + ... (N-1)/N ] / N = (N-1)/(2N)
1338 * where N = size * size is the total number of entries.
1339 *
1340 * To make the average value equal to 1/2 = N/(2N), add a bias of 1/(2N).
1341 */
1342
2/2
✓ Branch 0 taken 101934080 times.
✓ Branch 1 taken 398180 times.
102332260 for (int i = 0; i < num_entries; i++)
1343 101934080 m[i] = av_add_q64(m[i], av_make_q64(1, 2 * num_entries));
1344
1345 398180 return m;
1346 }
1347
1348 657376 static bool trc_is_hdr(enum AVColorTransferCharacteristic trc)
1349 {
1350 static_assert(AVCOL_TRC_NB == 19, "Update this list when adding TRCs");
1351 static_assert(AVCOL_TRC_EXT_NB == 257, "Update this list when adding TRCs");
1352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 657376 times.
657376 switch (trc) {
1353 case AVCOL_TRC_LOG:
1354 case AVCOL_TRC_LOG_SQRT:
1355 case AVCOL_TRC_V_LOG:
1356 case AVCOL_TRC_SMPTEST2084:
1357 case AVCOL_TRC_ARIB_STD_B67:
1358 return true;
1359 657376 default:
1360 657376 return false;
1361 }
1362 }
1363
1364 657376 static int fmt_dither(SwsContext *ctx, SwsOpList *ops,
1365 const SwsPixelType type,
1366 const SwsFormat *src, const SwsFormat *dst)
1367 {
1368 657376 SwsDither mode = ctx->dither;
1369 SwsDitherOp dither;
1370 657376 const int bpc = dst->desc->comp[0].depth;
1371
1372
1/2
✓ Branch 0 taken 657376 times.
✗ Branch 1 not taken.
657376 if (mode == SWS_DITHER_AUTO) {
1373 /* Visual threshold of perception: 12 bits for SDR, 14 bits for HDR */
1374
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 657376 times.
657376 const int jnd_bits = trc_is_hdr(dst->color.trc) ? 14 : 12;
1375
2/2
✓ Branch 0 taken 259196 times.
✓ Branch 1 taken 398180 times.
657376 mode = bpc >= jnd_bits ? SWS_DITHER_NONE : SWS_DITHER_BAYER;
1376 }
1377
1378
2/5
✓ Branch 0 taken 259196 times.
✓ Branch 1 taken 398180 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
657376 switch (mode) {
1379 259196 case SWS_DITHER_NONE:
1380
2/2
✓ Branch 0 taken 62258 times.
✓ Branch 1 taken 196938 times.
259196 if (ctx->flags & SWS_ACCURATE_RND) {
1381 /* Add constant 0.5 for correct rounding */
1382 62258 AVRational64 *bias = av_refstruct_allocz(sizeof(*bias));
1383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62258 times.
62258 if (!bias)
1384 return AVERROR(ENOMEM);
1385 62258 *bias = (AVRational64) {1, 2};
1386 62258 return ff_sws_op_list_append(ops, &(SwsOp) {
1387 .op = SWS_OP_DITHER,
1388 .type = type,
1389 .dither.matrix = bias,
1390 .dither.min = *bias,
1391 .dither.max = *bias,
1392 });
1393 } else {
1394 196938 return 0; /* No-op */
1395 }
1396 398180 case SWS_DITHER_BAYER:
1397 /* Hardcode 16x16 matrix for now; in theory we could adjust this
1398 * based on the expected level of precision in the output, since lower
1399 * bit depth outputs can suffice with smaller dither matrices; however
1400 * in practice we probably want to use error diffusion for such low bit
1401 * depths anyway */
1402 398180 dither.size_log2 = 4;
1403 398180 dither.matrix = generate_bayer_matrix(dither.size_log2);
1404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 398180 times.
398180 if (!dither.matrix)
1405 return AVERROR(ENOMEM);
1406
1407 398180 const int size = 1 << dither.size_log2;
1408 398180 dither.min = dither.max = dither.matrix[0];
1409
2/2
✓ Branch 0 taken 101535900 times.
✓ Branch 1 taken 398180 times.
101934080 for (int i = 1; i < size * size; i++) {
1410
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 101535900 times.
101535900 if (av_cmp_q64(dither.min, dither.matrix[i]) > 0)
1411 dither.min = dither.matrix[i];
1412
2/2
✓ Branch 1 taken 5574520 times.
✓ Branch 2 taken 95961380 times.
101535900 if (av_cmp_q64(dither.matrix[i], dither.max) > 0)
1413 5574520 dither.max = dither.matrix[i];
1414 }
1415
1416 /* Brute-forced offsets; minimizes quantization error across a 16x16
1417 * bayer dither pattern for standard RGBA and YUVA pixel formats */
1418 398180 const int offsets_16x16[4] = {0, 3, 2, 5};
1419
2/2
✓ Branch 0 taken 1592720 times.
✓ Branch 1 taken 398180 times.
1990900 for (int i = 0; i < 4; i++) {
1420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1592720 times.
1592720 av_assert0(offsets_16x16[i] <= INT8_MAX);
1421 1592720 dither.y_offset[i] = offsets_16x16[i];
1422 }
1423
1424 398180 const AVPixFmtDescriptor *src_desc = fmt_desc_decoded(src->format);
1425
4/4
✓ Branch 0 taken 60270 times.
✓ Branch 1 taken 337910 times.
✓ Branch 2 taken 44618 times.
✓ Branch 3 taken 15652 times.
398180 if (src_desc->nb_components < 3 && bpc >= 8) {
1426 /**
1427 * For high-bit-depth sources without chroma, use same matrix
1428 * offset for all color channels. This prevents introducing color
1429 * noise in grayscale images; and also allows optimizing the dither
1430 * operation. Skipped for low bit depth (<8 bpc) as the loss in
1431 * PSNR, from the inability to diffuse error among all three
1432 * channels, can be substantial.
1433 *
1434 * This shifts: { X, Y, Z, W } -> { X, X, X, Y }
1435 */
1436 44618 dither.y_offset[3] = dither.y_offset[1];
1437 44618 dither.y_offset[1] = dither.y_offset[2] = dither.y_offset[0];
1438 }
1439
1440 398180 return ff_sws_op_list_append(ops, &(SwsOp) {
1441 .op = SWS_OP_DITHER,
1442 .type = type,
1443 .dither = dither,
1444 });
1445 case SWS_DITHER_ED:
1446 case SWS_DITHER_A_DITHER:
1447 case SWS_DITHER_X_DITHER:
1448 return AVERROR(ENOTSUP);
1449
1450 case SWS_DITHER_NB:
1451 break;
1452 }
1453
1454 av_unreachable("Invalid dither mode");
1455 return AVERROR(EINVAL);
1456 }
1457
1458 #define Q64(x) av_make_q64((x).num, (x).den)
1459
1460 static inline SwsLinearOp
1461 708912 linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02,
1462 const AVRational m10, const AVRational m11, const AVRational m12,
1463 const AVRational m20, const AVRational m21, const AVRational m22)
1464 {
1465 708912 return (SwsLinearOp) {{
1466 708912 { Q64(m00), Q64(m01), Q64(m02), Q(0), Q(0) },
1467 708912 { Q64(m10), Q64(m11), Q64(m12), Q(0), Q(0) },
1468 708912 { Q64(m20), Q64(m21), Q64(m22), Q(0), Q(0) },
1469 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1470 }};
1471 }
1472
1473 751469 int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type,
1474 SwsOpList *ops, const SwsFormat *fmt, bool *incomplete)
1475 {
1476 751469 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(fmt->csp);
1477 751469 const SwsPixelType pixel_type = fmt_pixel_type(fmt->format);
1478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751469 times.
751469 if (!pixel_type)
1479 return AVERROR(ENOTSUP);
1480
1481 751469 const AVRational q0 = av_make_q(0, 1);
1482 751469 const AVRational q1 = av_make_q(1, 1);
1483 751469 const AVRational q2 = av_make_q(2, 1);
1484
1485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 751469 times.
751469 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1486 .op = SWS_OP_CONVERT,
1487 .type = pixel_type,
1488 .convert.to = type,
1489 }));
1490
1491 /* Decode pixel format into standardized range */
1492
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 751469 times.
751469 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1493 .type = type,
1494 .op = SWS_OP_LINEAR,
1495 .lin = fmt_decode_range(fmt, incomplete),
1496 }));
1497
1498 /* Final step, decode colorspace */
1499
2/8
✓ Branch 0 taken 412845 times.
✓ Branch 1 taken 338624 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
751469 switch (fmt->csp) {
1500 412845 case AVCOL_SPC_RGB:
1501 751469 return 0;
1502 338624 case AVCOL_SPC_UNSPECIFIED:
1503 338624 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1504 338624 *incomplete = true;
1505 av_fallthrough;
1506 338624 case AVCOL_SPC_FCC:
1507 case AVCOL_SPC_BT470BG:
1508 case AVCOL_SPC_SMPTE170M:
1509 case AVCOL_SPC_BT709:
1510 case AVCOL_SPC_SMPTE240M:
1511 case AVCOL_SPC_BT2020_NCL: {
1512 338624 AVRational crg = av_sub_q(q0, av_div_q(c->cr, c->cg));
1513 338624 AVRational cbg = av_sub_q(q0, av_div_q(c->cb, c->cg));
1514 338624 AVRational m02 = av_mul_q(q2, av_sub_q(q1, c->cr));
1515 338624 AVRational m21 = av_mul_q(q2, av_sub_q(q1, c->cb));
1516 338624 AVRational m11 = av_mul_q(cbg, m21);
1517 338624 AVRational m12 = av_mul_q(crg, m02);
1518
1519 338624 return ff_sws_op_list_append(ops, &(SwsOp) {
1520 .type = type,
1521 .op = SWS_OP_LINEAR,
1522 338624 .lin = linear_mat3(
1523 q1, q0, m02,
1524 q1, m11, m12,
1525 q1, m21, q0
1526 ),
1527 });
1528 }
1529
1530 case AVCOL_SPC_YCGCO:
1531 return ff_sws_op_list_append(ops, &(SwsOp) {
1532 .type = type,
1533 .op = SWS_OP_LINEAR,
1534 .lin = linear_mat3(
1535 q1, av_make_q(-1, 1), av_make_q( 1, 1),
1536 q1, av_make_q( 1, 1), av_make_q( 0, 1),
1537 q1, av_make_q(-1, 1), av_make_q(-1, 1)
1538 ),
1539 });
1540
1541 case AVCOL_SPC_BT2020_CL:
1542 case AVCOL_SPC_SMPTE2085:
1543 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1544 case AVCOL_SPC_CHROMA_DERIVED_CL:
1545 case AVCOL_SPC_ICTCP:
1546 case AVCOL_SPC_IPT_C2:
1547 case AVCOL_SPC_YCGCO_RE:
1548 case AVCOL_SPC_YCGCO_RO:
1549 return AVERROR(ENOTSUP);
1550
1551 case AVCOL_SPC_RESERVED:
1552 return AVERROR(EINVAL);
1553
1554 case AVCOL_SPC_NB:
1555 break;
1556 }
1557
1558 av_unreachable("Corrupt AVColorSpace value?");
1559 return AVERROR(EINVAL);
1560 }
1561
1562 751469 int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type,
1563 SwsOpList *ops, const SwsFormat *src,
1564 const SwsFormat *dst, bool *incomplete)
1565 {
1566 751469 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(dst->csp);
1567 751469 const SwsPixelType pixel_type = fmt_pixel_type(dst->format);
1568
2/2
✓ Branch 0 taken 39368 times.
✓ Branch 1 taken 712101 times.
751469 if (!pixel_type)
1569 39368 return AVERROR(ENOTSUP);
1570
1571
2/7
✓ Branch 0 taken 341813 times.
✓ Branch 1 taken 370288 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
712101 switch (dst->csp) {
1572 341813 case AVCOL_SPC_RGB:
1573 341813 break;
1574 370288 case AVCOL_SPC_UNSPECIFIED:
1575 370288 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1576 370288 *incomplete = true;
1577 av_fallthrough;
1578 370288 case AVCOL_SPC_FCC:
1579 case AVCOL_SPC_BT470BG:
1580 case AVCOL_SPC_SMPTE170M:
1581 case AVCOL_SPC_BT709:
1582 case AVCOL_SPC_SMPTE240M:
1583 case AVCOL_SPC_BT2020_NCL: {
1584 370288 AVRational cb1 = av_sub_q(c->cb, av_make_q(1, 1));
1585 370288 AVRational cr1 = av_sub_q(c->cr, av_make_q(1, 1));
1586 370288 AVRational m20 = av_make_q(1,2);
1587 370288 AVRational m10 = av_mul_q(m20, av_div_q(c->cr, cb1));
1588 370288 AVRational m11 = av_mul_q(m20, av_div_q(c->cg, cb1));
1589 370288 AVRational m21 = av_mul_q(m20, av_div_q(c->cg, cr1));
1590 370288 AVRational m22 = av_mul_q(m20, av_div_q(c->cb, cr1));
1591
1592
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 370288 times.
370288 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1593 .type = type,
1594 .op = SWS_OP_LINEAR,
1595 .lin = linear_mat3(
1596 c->cr, c->cg, c->cb,
1597 m10, m11, m20,
1598 m20, m21, m22
1599 ),
1600 }));
1601 370288 break;
1602 }
1603
1604 case AVCOL_SPC_YCGCO:
1605 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1606 .type = type,
1607 .op = SWS_OP_LINEAR,
1608 .lin = linear_mat3(
1609 av_make_q( 1, 4), av_make_q(1, 2), av_make_q( 1, 4),
1610 av_make_q( 1, 2), av_make_q(0, 1), av_make_q(-1, 2),
1611 av_make_q(-1, 4), av_make_q(1, 2), av_make_q(-1, 4)
1612 ),
1613 }));
1614 break;
1615
1616 case AVCOL_SPC_BT2020_CL:
1617 case AVCOL_SPC_SMPTE2085:
1618 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1619 case AVCOL_SPC_CHROMA_DERIVED_CL:
1620 case AVCOL_SPC_ICTCP:
1621 case AVCOL_SPC_IPT_C2:
1622 case AVCOL_SPC_YCGCO_RE:
1623 case AVCOL_SPC_YCGCO_RO:
1624 return AVERROR(ENOTSUP);
1625
1626 case AVCOL_SPC_RESERVED:
1627 case AVCOL_SPC_NB:
1628 return AVERROR(EINVAL);
1629 }
1630
1631
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 712101 times.
712101 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1632 .type = type,
1633 .op = SWS_OP_LINEAR,
1634 .lin = fmt_encode_range(dst, incomplete),
1635 }));
1636
1637
2/2
✓ Branch 0 taken 657376 times.
✓ Branch 1 taken 54725 times.
712101 if (!(dst->desc->flags & AV_PIX_FMT_FLAG_FLOAT)) {
1638 657376 SwsClampOp range = {0};
1639
1640 657376 const bool is_ya = dst->desc->nb_components == 2;
1641
2/2
✓ Branch 0 taken 2001468 times.
✓ Branch 1 taken 657376 times.
2658844 for (int i = 0; i < dst->desc->nb_components; i++) {
1642 /* Clamp to legal pixel range */
1643
2/2
✓ Branch 0 taken 27364 times.
✓ Branch 1 taken 1974104 times.
2001468 const int idx = i * (is_ya ? 3 : 1);
1644 2001468 range.limit[idx] = intmax_q64(dst->desc->comp[i].depth);
1645 }
1646
1647
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 657376 times.
657376 RET(fmt_dither(ctx, ops, type, src, dst));
1648
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 657376 times.
657376 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1649 .op = SWS_OP_MAX,
1650 .type = type,
1651 .clamp = {{ Q(0), Q(0), Q(0), Q(0) }},
1652 }));
1653
1654
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 657376 times.
657376 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1655 .op = SWS_OP_MIN,
1656 .type = type,
1657 .clamp = range,
1658 }));
1659 }
1660
1661 712101 return ff_sws_op_list_append(ops, &(SwsOp) {
1662 .type = type,
1663 .op = SWS_OP_CONVERT,
1664 .convert.to = pixel_type,
1665 });
1666 }
1667
1668 599730 static SwsScaler get_scaler_fallback(SwsContext *ctx)
1669 {
1670
2/2
✓ Branch 0 taken 491568 times.
✓ Branch 1 taken 108162 times.
599730 if (ctx->scaler != SWS_SCALE_AUTO)
1671 491568 return ctx->scaler;
1672
1673 /* Backwards compatibility with legacy flags API */
1674
2/2
✓ Branch 0 taken 8613 times.
✓ Branch 1 taken 99549 times.
108162 if (ctx->flags & SWS_BILINEAR) {
1675 8613 return SWS_SCALE_BILINEAR;
1676
2/2
✓ Branch 0 taken 78603 times.
✓ Branch 1 taken 20946 times.
99549 } else if (ctx->flags & (SWS_BICUBIC | SWS_BICUBLIN)) {
1677 78603 return SWS_SCALE_BICUBIC;
1678
2/2
✓ Branch 0 taken 4380 times.
✓ Branch 1 taken 16566 times.
20946 } else if (ctx->flags & SWS_POINT) {
1679 4380 return SWS_SCALE_POINT;
1680
2/2
✓ Branch 0 taken 4226 times.
✓ Branch 1 taken 12340 times.
16566 } else if (ctx->flags & SWS_AREA) {
1681 4226 return SWS_SCALE_AREA;
1682
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12340 times.
12340 } else if (ctx->flags & SWS_GAUSS) {
1683 return SWS_SCALE_GAUSSIAN;
1684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12340 times.
12340 } else if (ctx->flags & SWS_SINC) {
1685 return SWS_SCALE_SINC;
1686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12340 times.
12340 } else if (ctx->flags & SWS_LANCZOS) {
1687 return SWS_SCALE_LANCZOS;
1688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12340 times.
12340 } else if (ctx->flags & SWS_SPLINE) {
1689 return SWS_SCALE_SPLINE;
1690 } else {
1691 12340 return SWS_SCALE_AUTO;
1692 }
1693 }
1694
1695 1502938 static int add_filter(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1696 SwsOpType filter, int src_size, int dst_size)
1697 {
1698
2/2
✓ Branch 0 taken 903208 times.
✓ Branch 1 taken 599730 times.
1502938 if (src_size == dst_size)
1699 903208 return 0; /* no-op */
1700
1701 1199460 SwsFilterParams params = {
1702 599730 .scaler = get_scaler_fallback(ctx),
1703 .src_size = src_size,
1704 .dst_size = dst_size,
1705 };
1706
1707
2/2
✓ Branch 0 taken 1199460 times.
✓ Branch 1 taken 599730 times.
1799190 for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
1708 1199460 params.scaler_params[i] = ctx->scaler_params[i];
1709
1710 SwsFilterWeights *kernel;
1711 599730 int ret = ff_sws_filter_generate(ctx, &params, &kernel);
1712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 599730 times.
599730 if (ret == AVERROR(ENOTSUP)) {
1713 /* Filter size exceeds limit; cascade with geometric mean size */
1714 int mean = sqrt((int64_t) src_size * dst_size);
1715 if (mean == src_size || mean == dst_size)
1716 return AVERROR_BUG; /* sanity, prevent infinite loop */
1717 ret = add_filter(ctx, type, ops, filter, src_size, mean);
1718 if (ret < 0)
1719 return ret;
1720 return add_filter(ctx, type, ops, filter, mean, dst_size);
1721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 599730 times.
599730 } else if (ret < 0) {
1722 return ret;
1723 }
1724
1725 599730 return ff_sws_op_list_append(ops, &(SwsOp) {
1726 .type = type,
1727 .op = filter,
1728 .filter.kernel = kernel,
1729 .filter.type = type,
1730 });
1731 }
1732
1733 751469 int ff_sws_add_filters(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1734 const SwsFormat *src, const SwsFormat *dst)
1735 {
1736 /**
1737 * Always perform horizontal scaling first, since it's much more likely to
1738 * benefit from small integer optimizations; we should maybe flip the order
1739 * here if we're downscaling the vertical resolution by a lot, though.
1740 */
1741 751469 int ret = add_filter(ctx, type, ops, SWS_OP_FILTER_H, src->width, dst->width);
1742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751469 times.
751469 if (ret < 0)
1743 return ret;
1744
1745 751469 return add_filter(ctx, type, ops, SWS_OP_FILTER_V, src->height, dst->height);
1746 }
1747
1748 176624 int ff_sws_apply_lut3d(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1749 const SwsLut3D *lut3d)
1750 {
1751 /* Unnormalize to LUT input domain and clamp */
1752 const AVRational64 domain = Q(INPUT_LUT_SIZE - 1);
1753
1754
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176624 times.
176624 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1755 .type = type,
1756 .op = SWS_OP_LINEAR,
1757 .lin = {{
1758 { domain, Q(0), Q(0), Q(0), Q(0) },
1759 { Q(0), domain, Q(0), Q(0), Q(0) },
1760 { Q(0), Q(0), domain, Q(0), Q(0) },
1761 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1762 }},
1763 }));
1764
1765
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176624 times.
176624 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1766 .op = SWS_OP_MAX,
1767 .type = type,
1768 .clamp = {{ Q(0), Q(0), Q(0) }},
1769 }));
1770
1771
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176624 times.
176624 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1772 .op = SWS_OP_MIN,
1773 .type = type,
1774 .clamp = {{ domain, domain, domain }},
1775 }));
1776
1777 /* Apply the 3DLUT itself */
1778
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 176624 times.
176624 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1779 .op = SWS_OP_LUT_3D,
1780 .type = type,
1781 .lut3d.lut = av_refstruct_ref_c(lut3d),
1782 .lut3d.dynamic = lut3d->dynamic,
1783 }));
1784
1785 /* Normalize back to [0, 1] */
1786 176624 const AVRational64 inv = av_inv_q64(Q(UINT16_MAX));
1787
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176624 times.
176624 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1788 .type = type,
1789 .op = SWS_OP_LINEAR,
1790 .lin = {{
1791 { inv, Q(0), Q(0), Q(0), Q(0) },
1792 { Q(0), inv, Q(0), Q(0), Q(0) },
1793 { Q(0), Q(0), inv, Q(0), Q(0) },
1794 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1795 }},
1796 }));
1797
1798 176624 return 0;
1799 }
1800
1801 1040909 int ff_sws_op_list_generate(SwsContext *ctx, const SwsFormat *src,
1802 const SwsFormat *dst, const SwsLut3D *lut3d,
1803 SwsOpList **out_ops, bool *incomplete)
1804 {
1805 /* The new code does not yet support alpha blending */
1806
2/2
✓ Branch 0 taken 287419 times.
✓ Branch 1 taken 753490 times.
1040909 if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
1807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287419 times.
287419 ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
1808 return AVERROR(ENOTSUP);
1809
1810 1040909 SwsOpList *ops = ff_sws_op_list_alloc();
1811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1040909 times.
1040909 if (!ops)
1812 return AVERROR(ENOMEM);
1813 1040909 ops->src = *src;
1814 1040909 ops->dst = *dst;
1815
1816 1040909 const SwsPixelType type = SWS_PIXEL_F32;
1817 1040909 int ret = ff_sws_decode_pixfmt(ops, src);
1818
2/2
✓ Branch 0 taken 289440 times.
✓ Branch 1 taken 751469 times.
1040909 if (ret < 0)
1819 289440 goto fail;
1820 751469 ret = ff_sws_decode_colors(ctx, type, ops, src, incomplete);
1821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751469 times.
751469 if (ret < 0)
1822 goto fail;
1823 751469 ret = ff_sws_add_filters(ctx, type, ops, src, dst);
1824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751469 times.
751469 if (ret < 0)
1825 goto fail;
1826
2/2
✓ Branch 0 taken 176624 times.
✓ Branch 1 taken 574845 times.
751469 if (lut3d) {
1827 176624 ret = ff_sws_apply_lut3d(ctx, type, ops, lut3d);
1828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176624 times.
176624 if (ret < 0)
1829 goto fail;
1830 }
1831 751469 ret = ff_sws_encode_colors(ctx, type, ops, src, dst, incomplete);
1832
2/2
✓ Branch 0 taken 39368 times.
✓ Branch 1 taken 712101 times.
751469 if (ret < 0)
1833 39368 goto fail;
1834 712101 ret = ff_sws_encode_pixfmt(ops, dst);
1835
2/2
✓ Branch 0 taken 105336 times.
✓ Branch 1 taken 606765 times.
712101 if (ret < 0)
1836 105336 goto fail;
1837
1838 606765 *out_ops = ops;
1839 606765 return 0;
1840
1841 434144 fail:
1842 434144 ff_sws_op_list_free(&ops);
1843 434144 return ret;
1844 }
1845
1846 #else /* !CONFIG_UNSTABLE */
1847
1848 static int test_format_ops(enum AVPixelFormat format, int output)
1849 {
1850 return 0;
1851 }
1852
1853 #endif
1854