FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/format.c
Date: 2026-09-23 07:39:07
Exec Total Coverage
Lines: 636 713 89.2%
Functions: 49 50 98.0%
Branches: 359 486 73.9%

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