FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/format.c
Date: 2026-10-12 05:07:00
Exec Total Coverage
Lines: 653 730 89.5%
Functions: 51 52 98.1%
Branches: 372 500 74.4%

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 2480328 int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
288 {
289 2480328 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
290
2/2
✓ Branch 0 taken 2448576 times.
✓ Branch 1 taken 31752 times.
2480328 legacy_format_entries[pix_fmt].is_supported_in : 0;
291 }
292
293 2547834 int sws_isSupportedOutput(enum AVPixelFormat pix_fmt)
294 {
295 2547834 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
296
2/2
✓ Branch 0 taken 2511096 times.
✓ Branch 1 taken 36738 times.
2547834 legacy_format_entries[pix_fmt].is_supported_out : 0;
297 }
298
299 67437 int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
300 {
301 67437 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
302
1/2
✓ Branch 0 taken 67437 times.
✗ Branch 1 not taken.
67437 legacy_format_entries[pix_fmt].is_supported_endianness : 0;
303 }
304
305 2199786 static void sanitize_fmt(SwsFormat *fmt, const AVPixFmtDescriptor *desc)
306 {
307
2/2
✓ Branch 0 taken 822599 times.
✓ Branch 1 taken 1377187 times.
2199786 if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER)) {
308 /* RGB-like family */
309 822599 fmt->csp = AVCOL_SPC_RGB;
310 822599 fmt->range = AVCOL_RANGE_JPEG;
311
2/2
✓ Branch 0 taken 22430 times.
✓ Branch 1 taken 1354757 times.
1377187 } else if (desc->flags & AV_PIX_FMT_FLAG_XYZ) {
312 22430 fmt->csp = AVCOL_SPC_UNSPECIFIED;
313 22430 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 276728 times.
✓ Branch 1 taken 1078029 times.
1354757 } else if (desc->nb_components < 3) {
318 /* Grayscale formats */
319 276728 fmt->color.prim = AVCOL_PRI_UNSPECIFIED;
320 276728 fmt->csp = AVCOL_SPC_UNSPECIFIED;
321
2/2
✓ Branch 0 taken 49304 times.
✓ Branch 1 taken 227424 times.
276728 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT)
322 49304 fmt->range = AVCOL_RANGE_UNSPECIFIED;
323 else
324 227424 fmt->range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted
325 }
326
327
2/2
✓ Branch 1 taken 36445 times.
✓ Branch 2 taken 2163341 times.
2199786 switch (av_pix_fmt_desc_get_id(desc)) {
328 36445 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 36445 fmt->range = AVCOL_RANGE_JPEG;
334 36445 break;
335 }
336
337
4/4
✓ Branch 0 taken 1686702 times.
✓ Branch 1 taken 513084 times.
✓ Branch 2 taken 1653150 times.
✓ Branch 3 taken 33552 times.
2199786 if (!desc->log2_chroma_w && !desc->log2_chroma_h)
338 1653150 fmt->loc = AVCHROMA_LOC_UNSPECIFIED;
339 2199786 }
340
341 /**
342 * This function also sanitizes and strips the input data, removing irrelevant
343 * fields for certain formats.
344 */
345 1033386 SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field)
346 {
347 const AVColorPrimariesDesc *primaries;
348 AVFrameSideData *sd;
349
350 1033386 enum AVPixelFormat format = frame->format;
351 1033386 enum AVPixelFormat hw_format = AV_PIX_FMT_NONE;
352
353 #if CONFIG_UNSTABLE
354 1033386 const AVPixFmtDescriptor *hw_desc = av_pix_fmt_desc_get(frame->format);
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1033386 times.
1033386 av_assert0(hw_desc);
356
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1033386 times.
1033386 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 1033386 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
367
368 1033386 SwsFormat fmt = {
369 1033386 .width = frame->width,
370 1033386 .height = frame->height,
371 .format = format,
372 .hw_format = hw_format,
373 1033386 .range = frame->color_range,
374 1033386 .csp = frame->colorspace,
375 1033386 .loc = frame->chroma_location,
376 .desc = desc,
377 .color = {
378 1033386 .prim = frame->color_primaries,
379 1033386 .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 1033386 times.
1033386 av_assert0(desc);
387 1033386 sanitize_fmt(&fmt, desc);
388
389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1033386 times.
1033386 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 1033386 fmt.color.min_luma = av_make_q(0, 1);
397
3/3
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 1032906 times.
1033386 switch (fmt.color.trc) {
398 420 case AVCOL_TRC_SMPTE2084:
399 420 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 1032906 default:
403 1032906 fmt.color.max_luma = av_make_q( 203, 1); break; /* SDR reference brightness */
404 }
405
406 1033386 primaries = av_csp_primaries_desc_from_id(fmt.color.prim);
407
2/2
✓ Branch 0 taken 6360 times.
✓ Branch 1 taken 1027026 times.
1033386 if (primaries)
408 6360 fmt.color.gamut = primaries->prim;
409
410
2/2
✓ Branch 1 taken 404 times.
✓ Branch 2 taken 1032982 times.
1033386 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 1033382 times.
✓ Branch 2 taken 4 times.
1033386 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 1033382 skip_hdr10:
477
478 /* PQ is always scaled down to absolute zero, so ignore mastering metadata */
479
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 1032966 times.
1033386 if (fmt.color.trc == AVCOL_TRC_SMPTE2084)
480 420 fmt.color.min_luma = av_make_q(0, 1);
481
482 1033386 return fmt;
483 }
484
485 1166400 void ff_fmt_from_pixfmt(enum AVPixelFormat pixfmt, SwsFormat *fmt)
486 {
487 1166400 ff_fmt_clear(fmt);
488 1166400 fmt->format = pixfmt;
489 1166400 fmt->desc = av_pix_fmt_desc_get(pixfmt);
490 1166400 sanitize_fmt(fmt, fmt->desc);
491 1166400 }
492
493 1593106 static int infer_prim_ref(SwsColor *csp, const SwsColor *ref)
494 {
495
2/2
✓ Branch 0 taken 21545 times.
✓ Branch 1 taken 1571561 times.
1593106 if (csp->prim != AVCOL_PRI_UNSPECIFIED)
496 21545 return 0;
497
498 /* Reuse the reference gamut only for "safe", similar primaries */
499
2/2
✓ Branch 0 taken 796121 times.
✓ Branch 1 taken 775440 times.
1571561 switch (ref->prim) {
500 796121 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 796121 csp->prim = ref->prim;
506 796121 csp->gamut = ref->gamut;
507 796121 break;
508 775440 default:
509 775440 csp->prim = AVCOL_PRI_BT709;
510 775440 csp->gamut = av_csp_primaries_desc_from_id(csp->prim)->prim;
511 775440 break;
512 }
513
514 1571561 return 1;
515 }
516
517 1593106 static int infer_trc_ref(SwsColor *csp, const SwsColor *ref)
518 {
519
2/2
✓ Branch 0 taken 21691 times.
✓ Branch 1 taken 1571415 times.
1593106 if (csp->trc != AVCOL_TRC_UNSPECIFIED)
520 21691 return 0;
521
522 /* Pick a suitable SDR transfer function, to try and minimize conversions */
523
2/2
✓ Branch 0 taken 775367 times.
✓ Branch 1 taken 796048 times.
1571415 switch (ref->trc) {
524 775367 case AVCOL_TRC_UNSPECIFIED:
525 /* HDR curves, never default to these */
526 case AVCOL_TRC_SMPTE2084:
527 case AVCOL_TRC_ARIB_STD_B67:
528 775367 csp->trc = AVCOL_TRC_BT709;
529 775367 csp->min_luma = av_make_q(0, 1);
530 775367 csp->max_luma = av_make_q(203, 1);
531 775367 break;
532 796048 default:
533 796048 csp->trc = ref->trc;
534 796048 csp->min_luma = ref->min_luma;
535 796048 csp->max_luma = ref->max_luma;
536 796048 break;
537 }
538
539 1571415 return 1;
540 }
541
542 796553 bool ff_infer_colors(SwsColor *src, SwsColor *dst)
543 {
544 796553 int incomplete = 0;
545
546 796553 incomplete |= infer_prim_ref(dst, src);
547 796553 incomplete |= infer_prim_ref(src, dst);
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 796553 times.
796553 av_assert0(src->prim != AVCOL_PRI_UNSPECIFIED);
549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 796553 times.
796553 av_assert0(dst->prim != AVCOL_PRI_UNSPECIFIED);
550
551 796553 incomplete |= infer_trc_ref(dst, src);
552 796553 incomplete |= infer_trc_ref(src, dst);
553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 796553 times.
796553 av_assert0(src->trc != AVCOL_TRC_UNSPECIFIED);
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 796553 times.
796553 av_assert0(dst->trc != AVCOL_TRC_UNSPECIFIED);
555
556 796553 return incomplete;
557 }
558
559 661144 static int infer_loc_ref(SwsFormat *fmt, const SwsFormat *ref)
560 {
561
2/2
✓ Branch 0 taken 606070 times.
✓ Branch 1 taken 55074 times.
661144 if (fmt->loc != AVCHROMA_LOC_UNSPECIFIED ||
562
2/2
✓ Branch 0 taken 19874 times.
✓ Branch 1 taken 586196 times.
606070 ref->loc == AVCHROMA_LOC_UNSPECIFIED ||
563
3/4
✓ Branch 0 taken 16051 times.
✓ Branch 1 taken 3823 times.
✓ Branch 2 taken 16051 times.
✗ Branch 3 not taken.
19874 (!fmt->desc->log2_chroma_w && !fmt->desc->log2_chroma_h))
564 657321 return 0;
565
566 3823 fmt->loc = ref->loc;
567 3823 return 1;
568 }
569
570 330572 bool ff_infer_chroma_loc(SwsFormat *src, SwsFormat *dst)
571 {
572 330572 int incomplete = 0;
573
574 330572 incomplete |= infer_loc_ref(dst, src);
575 330572 incomplete |= infer_loc_ref(src, dst);
576
577 330572 return incomplete;
578 }
579
580 145312 void ff_sws_chroma_pos(const SwsFormat *fmt, bool *incomplete,
581 int *out_x_pos, int *out_y_pos)
582 {
583 145312 enum AVChromaLocation chroma_loc = fmt->loc;
584 145312 const int sub_x = fmt->desc->log2_chroma_w;
585 145312 const int sub_y = fmt->desc->log2_chroma_h;
586 int x_pos, y_pos;
587
588 /* Explicitly default to center siting for compatibility with swscale */
589
2/2
✓ Branch 0 taken 143818 times.
✓ Branch 1 taken 1494 times.
145312 if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
590 143818 chroma_loc = AVCHROMA_LOC_CENTER;
591
4/4
✓ Branch 0 taken 138903 times.
✓ Branch 1 taken 4915 times.
✓ Branch 2 taken 240 times.
✓ Branch 3 taken 138663 times.
143818 *incomplete |= sub_x || sub_y;
592 }
593
594 /* av_chroma_location_enum_to_pos() always gives us values in the range from
595 * 0 to 256, but we need to adjust this to the true value range of the
596 * subsampling grid, which may be larger for h/v_sub > 1 */
597 145312 av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
598 145312 x_pos *= (1 << sub_x) - 1;
599 145312 y_pos *= (1 << sub_y) - 1;
600
601 /* Fix vertical chroma position for interlaced frames */
602
3/4
✓ Branch 0 taken 5221 times.
✓ Branch 1 taken 140091 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5221 times.
145312 if (sub_y && fmt->interlaced) {
603 /* When vertically subsampling, chroma samples are effectively only
604 * placed next to even rows. To access them from the odd field, we need
605 * to account for this shift by offsetting the distance of one luma row.
606 *
607 * For 4x vertical subsampling (v_sub == 2), they are only placed
608 * next to every *other* even row, so we need to shift by three luma
609 * rows to get to the chroma sample. */
610 ✗ if (fmt->field == FIELD_BOTTOM)
611 ✗ y_pos += (256 << sub_y) - 256;
612
613 /* Luma row distance is doubled for fields, so halve offsets */
614 ✗ y_pos >>= 1;
615 }
616
617 145312 *out_x_pos = x_pos;
618 145312 *out_y_pos = y_pos;
619 145312 }
620
621 /* Variant of sws_test_format() for the ops-based code */
622 static int test_format_ops(enum AVPixelFormat format, int output);
623 4671392 static int test_format_legacy(enum AVPixelFormat format, int output)
624 {
625
2/2
✓ Branch 0 taken 2370676 times.
✓ Branch 1 taken 2300716 times.
4671392 return output ? sws_isSupportedOutput(format) : sws_isSupportedInput(format);
626 }
627
628 5480814 int ff_sws_test_pixfmt_backend(const SwsBackend backends,
629 enum AVPixelFormat format, int output)
630 {
631 /* The only non-ops backend is the legacy backend */
632 5480814 const SwsBackend backends_ops = SWS_BACKEND_ALL ^ SWS_BACKEND_LEGACY;
633
4/4
✓ Branch 0 taken 4671392 times.
✓ Branch 1 taken 809422 times.
✓ Branch 3 taken 843031 times.
✓ Branch 4 taken 3828361 times.
7133267 return ((backends & SWS_BACKEND_LEGACY) && test_format_legacy(format, output)) ||
634
4/4
✓ Branch 0 taken 939325 times.
✓ Branch 1 taken 713128 times.
✓ Branch 3 taken 720061 times.
✓ Branch 4 taken 219264 times.
1652453 ((backends & backends_ops) && test_format_ops(format, output));
635 }
636
637 3702780 int sws_test_format(enum AVPixelFormat format, int output)
638 {
639 3702780 return ff_sws_test_pixfmt_backend(SWS_BACKEND_STABLE, format, output);
640 }
641
642 798948 int sws_test_hw_format(enum AVPixelFormat format)
643 {
644
1/2
✓ Branch 0 taken 798948 times.
✗ Branch 1 not taken.
798948 switch (format) {
645 798948 case AV_PIX_FMT_NONE: return 1;
646 #if CONFIG_VULKAN
647 case AV_PIX_FMT_VULKAN: return 1;
648 #endif
649 ✗ default: return 0;
650 }
651 }
652
653 1043522 int sws_test_colorspace(enum AVColorSpace csp, int output)
654 {
655
2/2
✓ Branch 0 taken 920123 times.
✓ Branch 1 taken 123399 times.
1043522 switch (csp) {
656 920123 case AVCOL_SPC_UNSPECIFIED:
657 case AVCOL_SPC_RGB:
658 case AVCOL_SPC_BT709:
659 case AVCOL_SPC_BT470BG:
660 case AVCOL_SPC_SMPTE170M:
661 case AVCOL_SPC_FCC:
662 case AVCOL_SPC_SMPTE240M:
663 case AVCOL_SPC_BT2020_NCL:
664 920123 return 1;
665 123399 default:
666 123399 return 0;
667 }
668 }
669
670 798948 int sws_test_primaries(enum AVColorPrimaries prim, int output)
671 {
672
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
798948 return ((prim > AVCOL_PRI_RESERVED0 && prim < AVCOL_PRI_NB) ||
673
2/6
✓ Branch 0 taken 798948 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 798948 times.
✗ Branch 5 not taken.
1597896 (prim >= AVCOL_PRI_EXT_BASE && prim < AVCOL_PRI_EXT_NB)) &&
674 prim != AVCOL_PRI_RESERVED;
675 }
676
677 798948 int sws_test_transfer(enum AVColorTransferCharacteristic trc, int output)
678 {
679 399474 av_csp_eotf_function eotf = output ? av_csp_itu_eotf_inv(trc)
680
2/2
✓ Branch 0 taken 399474 times.
✓ Branch 1 taken 399474 times.
798948 : av_csp_itu_eotf(trc);
681
3/4
✓ Branch 0 taken 5249 times.
✓ Branch 1 taken 793699 times.
✓ Branch 2 taken 5249 times.
✗ Branch 3 not taken.
798948 return trc == AVCOL_TRC_UNSPECIFIED || eotf != NULL;
682 }
683
684 798948 static int test_range(enum AVColorRange range)
685 {
686 798948 return (unsigned)range < AVCOL_RANGE_NB;
687 }
688
689 798948 static int test_loc(enum AVChromaLocation loc)
690 {
691 798948 return (unsigned)loc < AVCHROMA_LOC_NB;
692 }
693
694 798948 int ff_test_fmt(const SwsBackend backends, const SwsFormat *fmt, int output)
695 {
696
2/4
✓ Branch 0 taken 798948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 798948 times.
✗ Branch 3 not taken.
1597896 return fmt->width > 0 && fmt->height > 0 &&
697
1/2
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
1597896 ff_sws_test_pixfmt_backend(backends, fmt->format, output) &&
698
1/2
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
1597896 sws_test_colorspace(fmt->csp, output) &&
699
1/2
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
1597896 sws_test_primaries (fmt->color.prim, output) &&
700
1/2
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
1597896 sws_test_transfer (fmt->color.trc, output) &&
701
1/2
✓ Branch 1 taken 798948 times.
✗ Branch 2 not taken.
1597896 sws_test_hw_format (fmt->hw_format) &&
702
2/4
✓ Branch 0 taken 798948 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 798948 times.
✗ Branch 4 not taken.
2396844 test_range (fmt->range) &&
703 798948 test_loc (fmt->loc);
704 }
705
706 ✗ int sws_test_frame(const AVFrame *frame, int output)
707 {
708 ✗ for (int field = 0; field < 2; field++) {
709 ✗ const SwsFormat fmt = ff_fmt_from_frame(frame, field);
710 ✗ if (!ff_test_fmt(SWS_BACKEND_STABLE, &fmt, output))
711 ✗ return 0;
712 ✗ if (!fmt.interlaced)
713 ✗ break;
714 }
715
716 ✗ return 1;
717 }
718
719 117219 int sws_is_noop(const AVFrame *dst, const AVFrame *src)
720 {
721
1/2
✓ Branch 0 taken 117219 times.
✗ Branch 1 not taken.
117219 for (int field = 0; field < 2; field++) {
722 117219 SwsFormat dst_fmt = ff_fmt_from_frame(dst, field);
723 117219 SwsFormat src_fmt = ff_fmt_from_frame(src, field);
724 117219 ff_infer_chroma_loc(&src_fmt, &dst_fmt);
725
2/2
✓ Branch 1 taken 112199 times.
✓ Branch 2 taken 5020 times.
117219 if (!ff_fmt_equal(&dst_fmt, &src_fmt))
726 112199 return 0;
727
1/2
✓ Branch 0 taken 5020 times.
✗ Branch 1 not taken.
5020 if (!dst_fmt.interlaced)
728 5020 break;
729 }
730
731 5020 return 1;
732 }
733
734 593945 void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src)
735 {
736 593945 dst->format = src->format;
737 593945 dst->width = src->width;
738 593945 dst->height = src->height;
739 593945 dst->avframe = src;
740
2/2
✓ Branch 0 taken 2375780 times.
✓ Branch 1 taken 593945 times.
2969725 for (int i = 0; i < FF_ARRAY_ELEMS(dst->data); i++) {
741 2375780 dst->data[i] = src->data[i];
742 2375780 dst->linesize[i] = src->linesize[i];
743 }
744 593945 }
745
746 #if CONFIG_UNSTABLE
747
748 /**
749 * Returns the underlying descriptor for fake formats like PAL8 whose
750 * descriptors alone do not fully describe the pixel data.
751 */
752 9016899 static inline const AVPixFmtDescriptor *fmt_desc_decoded(enum AVPixelFormat fmt)
753 {
754
2/2
✓ Branch 0 taken 35712 times.
✓ Branch 1 taken 8981187 times.
9016899 if (fmt == AV_PIX_FMT_PAL8)
755 35712 return av_pix_fmt_desc_get(AV_PIX_FMT_RGB32);
756
757 8981187 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8981187 times.
8981187 av_assert0(!(desc->flags & AV_PIX_FMT_FLAG_PAL));
759 8981187 return desc;
760 }
761
762 /* Returns the type suitable for a pixel after fully decoding/unpacking it */
763 4159871 static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt)
764 {
765 4159871 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt);
766 4159871 const int bits = FFALIGN(desc->comp[0].depth, 8);
767
2/2
✓ Branch 0 taken 425664 times.
✓ Branch 1 taken 3734207 times.
4159871 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
768
2/2
✓ Branch 0 taken 361152 times.
✓ Branch 1 taken 64512 times.
425664 switch (bits) {
769 361152 case 32: return SWS_PIXEL_F32;
770 /* TODO: no support for 16-bit float yet */
771 }
772 } else {
773
3/3
✓ Branch 0 taken 1318707 times.
✓ Branch 1 taken 2292552 times.
✓ Branch 2 taken 122948 times.
3734207 switch (bits) {
774 1318707 case 8: return SWS_PIXEL_U8;
775 2292552 case 16: return SWS_PIXEL_U16;
776 /* TODO: AVRational cannot represent UINT32_MAX */
777 }
778 }
779
780 187460 return SWS_PIXEL_NONE;
781 }
782
783 /* A regular format is defined as any format that contains only a single
784 * component per elementary data type (i.e. no sub-byte pack/unpack needed),
785 * and whose components map 1:1 onto elementary data units */
786 2330581 static int is_regular_fmt(enum AVPixelFormat fmt)
787 {
788 2330581 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
789
2/2
✓ Branch 0 taken 73056 times.
✓ Branch 1 taken 2257525 times.
2330581 if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER))
790 73056 return 0; /* no 1:1 correspondence between components and data units */
791
2/2
✓ Branch 0 taken 109947 times.
✓ Branch 1 taken 2147578 times.
2257525 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM))
792 109947 return 0; /* bitstream formats are packed by definition */
793
4/4
✓ Branch 0 taken 1241100 times.
✓ Branch 1 taken 906478 times.
✓ Branch 2 taken 217267 times.
✓ Branch 3 taken 1023833 times.
2147578 if ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) || desc->nb_components == 1)
794 1123745 return 1; /* planar formats are regular by definition */
795
796 1023833 const int step = desc->comp[0].step;
797 1023833 int total_bits = 0;
798
799
2/2
✓ Branch 0 taken 2628273 times.
✓ Branch 1 taken 616225 times.
3244498 for (int i = 0; i < desc->nb_components; i++) {
800
3/4
✓ Branch 0 taken 2220665 times.
✓ Branch 1 taken 407608 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2220665 times.
2628273 if (desc->comp[i].shift || desc->comp[i].step != step)
801 407608 return 0; /* irregular/packed format */
802 2220665 total_bits += desc->comp[i].depth;
803 }
804
805 /* Exclude formats with missing components like RGB0, 0RGB, etc. */
806 616225 return total_bits == step * 8;
807 }
808
809 typedef struct FmtInfo {
810 SwsReadWriteOp rw;
811 SwsSwizzleOp swizzle;
812 SwsPackOp pack;
813 int shift;
814 } FmtInfo;
815
816 #define BITSTREAM_FMT(SWIZ, FRAC, MODE, ...) (FmtInfo) { \
817 .rw = { .elems = 1, .frac = FRAC, .mode = MODE }, \
818 .swizzle = SWIZ, \
819 __VA_ARGS__ \
820 }
821
822 #define SUBPACKED_FMT(SWIZ, ...) (FmtInfo) { \
823 .rw = { .elems = 1, .mode = SWS_RW_PACKED }, \
824 .swizzle = SWIZ, \
825 .pack.pattern = {__VA_ARGS__}, \
826 }
827
828 #define PACKED_FMT(SWIZ, N, ...) (FmtInfo) { \
829 .rw = { .elems = N, .mode = SWS_RW_PACKED }, \
830 .swizzle = SWIZ, \
831 __VA_ARGS__ \
832 }
833
834 #define RGBA SWS_SWIZZLE(0, 1, 2, 3)
835 #define BGRA SWS_SWIZZLE(2, 1, 0, 3)
836 #define ARGB SWS_SWIZZLE(3, 0, 1, 2)
837 #define ABGR SWS_SWIZZLE(3, 2, 1, 0)
838 #define AVYU SWS_SWIZZLE(3, 2, 0, 1)
839 #define VYUA SWS_SWIZZLE(2, 0, 1, 3)
840 #define UYVA SWS_SWIZZLE(1, 0, 2, 3)
841 #define VUYA BGRA
842
843 707833 static FmtInfo fmt_info_irregular(enum AVPixelFormat fmt)
844 {
845
26/26
✓ Branch 0 taken 33255 times.
✓ Branch 1 taken 18976 times.
✓ Branch 2 taken 18972 times.
✓ Branch 3 taken 16970 times.
✓ Branch 4 taken 16380 times.
✓ Branch 5 taken 16503 times.
✓ Branch 6 taken 16559 times.
✓ Branch 7 taken 33202 times.
✓ Branch 8 taken 33210 times.
✓ Branch 9 taken 33699 times.
✓ Branch 10 taken 32987 times.
✓ Branch 11 taken 33343 times.
✓ Branch 12 taken 33403 times.
✓ Branch 13 taken 35230 times.
✓ Branch 14 taken 35618 times.
✓ Branch 15 taken 35819 times.
✓ Branch 16 taken 35868 times.
✓ Branch 17 taken 16582 times.
✓ Branch 18 taken 17014 times.
✓ Branch 19 taken 16662 times.
✓ Branch 20 taken 16861 times.
✓ Branch 21 taken 16739 times.
✓ Branch 22 taken 33391 times.
✓ Branch 23 taken 33364 times.
✓ Branch 24 taken 8544 times.
✓ Branch 25 taken 68682 times.
707833 switch (fmt) {
846 /* Bitstream formats */
847 33255 case AV_PIX_FMT_MONOWHITE:
848 case AV_PIX_FMT_MONOBLACK:
849 33255 return BITSTREAM_FMT(RGBA, 3, SWS_RW_PLANAR);
850 18976 case AV_PIX_FMT_RGB4: return BITSTREAM_FMT(RGBA, 1, SWS_RW_PACKED, .pack = {{ 1, 2, 1 }});
851 18972 case AV_PIX_FMT_BGR4: return BITSTREAM_FMT(BGRA, 1, SWS_RW_PACKED, .pack = {{ 1, 2, 1 }});
852
853 /* Sub-packed 8-bit aligned formats */
854 16970 case AV_PIX_FMT_RGB4_BYTE: return SUBPACKED_FMT(RGBA, 1, 2, 1);
855 16380 case AV_PIX_FMT_BGR4_BYTE: return SUBPACKED_FMT(BGRA, 1, 2, 1);
856 16503 case AV_PIX_FMT_RGB8: return SUBPACKED_FMT(RGBA, 3, 3, 2);
857 16559 case AV_PIX_FMT_BGR8: return SUBPACKED_FMT(BGRA, 2, 3, 3);
858
859 /* Sub-packed 16-bit aligned formats */
860 33202 case AV_PIX_FMT_RGB565LE:
861 case AV_PIX_FMT_RGB565BE:
862 33202 return SUBPACKED_FMT(RGBA, 5, 6, 5);
863 33210 case AV_PIX_FMT_BGR565LE:
864 case AV_PIX_FMT_BGR565BE:
865 33210 return SUBPACKED_FMT(BGRA, 5, 6, 5);
866 33699 case AV_PIX_FMT_RGB555LE:
867 case AV_PIX_FMT_RGB555BE:
868 33699 return SUBPACKED_FMT(RGBA, 5, 5, 5);
869 32987 case AV_PIX_FMT_BGR555LE:
870 case AV_PIX_FMT_BGR555BE:
871 32987 return SUBPACKED_FMT(BGRA, 5, 5, 5);
872 33343 case AV_PIX_FMT_RGB444LE:
873 case AV_PIX_FMT_RGB444BE:
874 33343 return SUBPACKED_FMT(RGBA, 4, 4, 4);
875 33403 case AV_PIX_FMT_BGR444LE:
876 case AV_PIX_FMT_BGR444BE:
877 33403 return SUBPACKED_FMT(BGRA, 4, 4, 4);
878
879 /* Sub-packed 32-bit aligned formats */
880 35230 case AV_PIX_FMT_X2RGB10LE:
881 case AV_PIX_FMT_X2RGB10BE:
882 35230 return SUBPACKED_FMT(ARGB, 2, 10, 10, 10);
883 35618 case AV_PIX_FMT_X2BGR10LE:
884 case AV_PIX_FMT_X2BGR10BE:
885 35618 return SUBPACKED_FMT(ABGR, 2, 10, 10, 10);
886 35819 case AV_PIX_FMT_XV30LE:
887 case AV_PIX_FMT_XV30BE:
888 35819 return SUBPACKED_FMT(AVYU, 2, 10, 10, 10);
889 35868 case AV_PIX_FMT_V30XLE:
890 case AV_PIX_FMT_V30XBE:
891 35868 return SUBPACKED_FMT(VYUA, 10, 10, 10, 2);
892
893 /* 3-component formats with extra padding */
894 16582 case AV_PIX_FMT_RGB0: return PACKED_FMT(RGBA, 4);
895 17014 case AV_PIX_FMT_BGR0: return PACKED_FMT(BGRA, 4);
896 16662 case AV_PIX_FMT_0RGB: return PACKED_FMT(ARGB, 4);
897 16861 case AV_PIX_FMT_0BGR: return PACKED_FMT(ABGR, 4);
898 16739 case AV_PIX_FMT_VUYX: return PACKED_FMT(VUYA, 4);
899 33391 case AV_PIX_FMT_XV36LE:
900 case AV_PIX_FMT_XV36BE:
901 33391 return PACKED_FMT(UYVA, 4, .shift = 4);
902 33364 case AV_PIX_FMT_XV48LE:
903 case AV_PIX_FMT_XV48BE:
904 33364 return PACKED_FMT(UYVA, 4);
905
906 /* Miscellaneous irregular formats */
907 8544 case AV_PIX_FMT_PAL8:
908 8544 return (FmtInfo) {
909 .rw = { .elems = 4, .mode = SWS_RW_PALETTE },
910 /* PAL8 is explicitly defined as endian-dependent */
911 #if AV_HAVE_BIGENDIAN
912 .swizzle = ARGB,
913 #else
914 .swizzle = BGRA,
915 #endif
916 };
917 }
918
919 68682 return (FmtInfo) {0};
920 }
921
922 struct comp {
923 int index;
924 int plane;
925 int offset;
926 };
927
928 /* Compare by (plane, offset) */
929 4504766 static int cmp_comp(const void *a, const void *b) {
930 4504766 const struct comp *ca = a;
931 4504766 const struct comp *cb = b;
932
2/2
✓ Branch 0 taken 2964744 times.
✓ Branch 1 taken 1540022 times.
4504766 if (ca->plane != cb->plane)
933 2964744 return ca->plane - cb->plane;
934 1540022 return ca->offset - cb->offset;
935 }
936
937 1622748 static int fmt_analyze_regular(const AVPixFmtDescriptor *desc, SwsReadWriteOp *rw_op,
938 SwsSwizzleOp *swizzle, SwsShiftOp *shift)
939 {
940
2/2
✓ Branch 0 taken 87192 times.
✓ Branch 1 taken 1535556 times.
1622748 if (desc->nb_components == 2) {
941 /* YA formats */
942 87192 *swizzle = SWS_SWIZZLE(0, 3, 1, 2);
943 } else {
944 /* Sort by increasing component order */
945 1535556 struct comp sorted[4] = { {0}, {1}, {2}, {3} };
946
2/2
✓ Branch 0 taken 4771268 times.
✓ Branch 1 taken 1535556 times.
6306824 for (int i = 0; i < desc->nb_components; i++) {
947 4771268 sorted[i].plane = desc->comp[i].plane;
948 4771268 sorted[i].offset = desc->comp[i].offset;
949 }
950
951 1535556 qsort(sorted, desc->nb_components, sizeof(struct comp), cmp_comp);
952
953 1535556 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
954
2/2
✓ Branch 0 taken 4771268 times.
✓ Branch 1 taken 1535556 times.
6306824 for (int i = 0; i < desc->nb_components; i++)
955 4771268 swiz.in[i] = sorted[i].index;
956 1535556 *swizzle = swiz;
957 }
958
959 1622748 SwsReadWriteMode mode = SWS_RW_PLANAR;
960
4/4
✓ Branch 0 taken 1405481 times.
✓ Branch 1 taken 217267 times.
✓ Branch 2 taken 499003 times.
✓ Branch 3 taken 906478 times.
1622748 if (desc->nb_components > 1 && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR))
961 499003 mode = SWS_RW_PACKED;
962
963 1622748 *shift = (SwsShiftOp) { desc->comp[0].shift };
964 1622748 *rw_op = (SwsReadWriteOp) {
965 1622748 .elems = desc->nb_components,
966 .mode = mode,
967 };
968 1622748 return 0;
969 }
970
971 2864243 static int fmt_analyze(enum AVPixelFormat fmt, SwsReadWriteOp *rw_op,
972 SwsPackOp *pack_op, SwsSwizzleOp *swizzle,
973 SwsShiftOp *shift, SwsPixelType *pixel_type,
974 SwsPixelType *raw_type)
975 {
976 2864243 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2864243 times.
2864243 if (!desc)
978 ✗ return AVERROR(EINVAL);
979
980 /* No support for subsampled formats at the moment */
981
4/4
✓ Branch 0 taken 2546425 times.
✓ Branch 1 taken 317818 times.
✓ Branch 2 taken 25920 times.
✓ Branch 3 taken 2520505 times.
2864243 if (desc->log2_chroma_w || desc->log2_chroma_h)
982 343738 return AVERROR(ENOTSUP);
983
984 /* No support for semi-planar formats at the moment */
985
2/2
✓ Branch 0 taken 974734 times.
✓ Branch 1 taken 1545771 times.
2520505 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR &&
986
2/2
✓ Branch 1 taken 41832 times.
✓ Branch 2 taken 932902 times.
974734 av_pix_fmt_count_planes(fmt) < desc->nb_components)
987 41832 return AVERROR(ENOTSUP);
988
989 2478673 *pixel_type = *raw_type = fmt_pixel_type(fmt);
990
2/2
✓ Branch 0 taken 148092 times.
✓ Branch 1 taken 2330581 times.
2478673 if (!*pixel_type)
991 148092 return AVERROR(ENOTSUP);
992
993
2/2
✓ Branch 1 taken 1622748 times.
✓ Branch 2 taken 707833 times.
2330581 if (is_regular_fmt(fmt)) {
994 1622748 *pack_op = (SwsPackOp) {0};
995 1622748 return fmt_analyze_regular(desc, rw_op, swizzle, shift);
996 }
997
998 707833 FmtInfo info = fmt_info_irregular(fmt);
999
2/2
✓ Branch 0 taken 68682 times.
✓ Branch 1 taken 639151 times.
707833 if (!info.rw.elems)
1000 68682 return AVERROR(ENOTSUP);
1001
1002 639151 *rw_op = info.rw;
1003 639151 *pack_op = info.pack;
1004 639151 *swizzle = info.swizzle;
1005 639151 *shift = (SwsShiftOp) { info.shift };
1006
1007
2/2
✓ Branch 0 taken 446739 times.
✓ Branch 1 taken 192412 times.
639151 if (info.pack.pattern[0]) {
1008 446739 const int sum = info.pack.pattern[0] + info.pack.pattern[1] +
1009 446739 info.pack.pattern[2] + info.pack.pattern[3];
1010
2/2
✓ Branch 0 taken 142535 times.
✓ Branch 1 taken 304204 times.
446739 if (sum > 16)
1011 142535 *raw_type = SWS_PIXEL_U32;
1012
2/2
✓ Branch 0 taken 199844 times.
✓ Branch 1 taken 104360 times.
304204 else if (sum > 8)
1013 199844 *raw_type = SWS_PIXEL_U16;
1014 else
1015 104360 *raw_type = SWS_PIXEL_U8;
1016 }
1017
1018 639151 return 0;
1019 }
1020
1021 939325 static int test_format_ops(enum AVPixelFormat format, int output)
1022 {
1023 SwsReadWriteOp rw;
1024 SwsSwizzleOp swizzle;
1025 SwsPackOp pack;
1026 SwsShiftOp shift;
1027 SwsPixelType pixel_type, raw_type;
1028 939325 int ret = fmt_analyze(format, &rw, &pack, &swizzle, &shift,
1029 &pixel_type, &raw_type);
1030
2/2
✓ Branch 0 taken 217080 times.
✓ Branch 1 taken 722245 times.
939325 if (ret < 0)
1031 217080 return 0;
1032
3/4
✓ Branch 0 taken 2184 times.
✓ Branch 1 taken 720061 times.
✓ Branch 2 taken 2184 times.
✗ Branch 3 not taken.
722245 if (rw.mode == SWS_RW_PALETTE && output)
1033 2184 return 0; /* palettes are currently only supported as input */
1034 720061 return 1;
1035 }
1036
1037 840599 static void swizzle_inv(SwsSwizzleOp *swiz)
1038 {
1039 /* Input[x] =: Output[swizzle.x] */
1040 unsigned tmp[4];
1041 840599 tmp[swiz->x] = 0;
1042 840599 tmp[swiz->y] = 1;
1043 840599 tmp[swiz->z] = 2;
1044 840599 tmp[swiz->w] = 3;
1045 840599 *swiz = (SwsSwizzleOp) {{ .x = tmp[0], tmp[1], tmp[2], tmp[3] }};
1046 840599 }
1047
1048 /**
1049 * This initializes all absent components explicitly to zero. There is no
1050 * need to worry about the correct neutral value as fmt_decode() will
1051 * implicitly ignore and overwrite absent components in any case. This function
1052 * is just to ensure that we don't operate on undefined memory. In most cases,
1053 * it will end up getting pushed towards the output or optimized away entirely
1054 * by the optimization pass.
1055 */
1056 840599 static SwsClearOp fmt_clear(const SwsFormat *fmt)
1057 {
1058 840599 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1059 840599 const bool has_chroma = desc->nb_components >= 3;
1060 840599 const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
1061
1062 840599 SwsClearOp c = {0};
1063
2/2
✓ Branch 0 taken 127049 times.
✓ Branch 1 taken 713550 times.
840599 if (!has_chroma) {
1064 127049 c.mask |= SWS_COMP(1) | SWS_COMP(2);
1065 127049 c.value[1] = c.value[2] = Q(0);
1066 }
1067
1068
2/2
✓ Branch 0 taken 581827 times.
✓ Branch 1 taken 258772 times.
840599 if (!has_alpha) {
1069 581827 c.mask |= SWS_COMP(3);
1070 581827 c.value[3] = Q(0);
1071 }
1072
1073 840599 return c;
1074 }
1075
1076 #if HAVE_BIGENDIAN
1077 # define NATIVE_ENDIAN_FLAG AV_PIX_FMT_FLAG_BE
1078 #else
1079 # define NATIVE_ENDIAN_FLAG 0
1080 #endif
1081
1082 6972607 static inline AVRational64 intmax_q64(int bits)
1083 {
1084 av_assert1(bits >= 0 && bits < 64);
1085 6972607 return Q(UINT64_MAX >> (64 - bits));
1086 }
1087
1088 1123687 int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
1089 {
1090 1123687 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1091 SwsPixelType pixel_type, raw_type;
1092 SwsReadWriteOp rw_op;
1093 SwsSwizzleOp swizzle;
1094 SwsPackOp unpack;
1095 1123687 SwsComps *comps = &ops->comps_src;
1096 SwsShiftOp shift;
1097
1098
2/2
✓ Branch 1 taken 283088 times.
✓ Branch 2 taken 840599 times.
1123687 RET(fmt_analyze(fmt->format, &rw_op, &unpack, &swizzle, &shift,
1099 &pixel_type, &raw_type));
1100
1101 840599 swizzle_inv(&swizzle);
1102
1103 /* Set baseline pixel content flags */
1104 840599 const int integer = ff_sws_pixel_type_is_int(raw_type);
1105
2/2
✓ Branch 0 taken 646334 times.
✓ Branch 1 taken 194265 times.
1486933 const int swapped = ff_sws_pixel_type_size(raw_type) > 1 &&
1106
2/2
✓ Branch 0 taken 324155 times.
✓ Branch 1 taken 322179 times.
646334 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG;
1107
2/2
✓ Branch 0 taken 2253242 times.
✓ Branch 1 taken 840599 times.
3093841 for (int i = 0; i < rw_op.elems; i++) {
1108
2/2
✓ Branch 0 taken 2023436 times.
✓ Branch 1 taken 229806 times.
4506484 comps->flags[i] = (integer ? SWS_COMP_EXACT : 0) |
1109
2/2
✓ Branch 0 taken 850709 times.
✓ Branch 1 taken 1402533 times.
2253242 (swapped ? SWS_COMP_SWAPPED : 0);
1110 }
1111
1112 /* Generate value range information for simple unpacked formats */
1113
4/4
✓ Branch 0 taken 759350 times.
✓ Branch 1 taken 81249 times.
✓ Branch 2 taken 594462 times.
✓ Branch 3 taken 164888 times.
840599 if (integer && !unpack.pattern[0]) {
1114 /* YA formats have desc->comp[] in the order {Y, A} instead of the
1115 * canonical order {Y, U, V, A} */
1116 594462 const int is_ya = desc->nb_components == 2;
1117
2/2
✓ Branch 0 taken 1802001 times.
✓ Branch 1 taken 594462 times.
2396463 for (int c = 0; c < desc->nb_components; c++) {
1118 1802001 const int bits = desc->comp[c].depth + shift.amount;
1119
2/2
✓ Branch 0 taken 37788 times.
✓ Branch 1 taken 1764213 times.
1802001 const int idx = swizzle.in[is_ya ? 3 * c : c];
1120 1802001 comps->min[idx] = Q(0);
1121 1802001 comps->max[idx] = intmax_q64(bits);
1122 }
1123 }
1124
1125 /* TODO: handle subsampled or semipacked input formats */
1126
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 840599 times.
840599 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1127 .op = SWS_OP_READ,
1128 .type = raw_type,
1129 .rw = rw_op,
1130 }));
1131
1132
2/2
✓ Branch 0 taken 324155 times.
✓ Branch 1 taken 516444 times.
840599 if (swapped) {
1133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 324155 times.
324155 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1134 .op = SWS_OP_SWAP_BYTES,
1135 .type = raw_type,
1136 }));
1137 }
1138
1139
2/2
✓ Branch 0 taken 164888 times.
✓ Branch 1 taken 675711 times.
840599 if (unpack.pattern[0]) {
1140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164888 times.
164888 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1141 .op = SWS_OP_UNPACK,
1142 .type = raw_type,
1143 .pack = unpack,
1144 }));
1145
1146
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164888 times.
164888 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1147 .op = SWS_OP_CONVERT,
1148 .type = raw_type,
1149 .convert.to = pixel_type,
1150 }));
1151 }
1152
1153
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 840599 times.
840599 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1154 .op = SWS_OP_SWIZZLE,
1155 .type = pixel_type,
1156 .swizzle = swizzle,
1157 }));
1158
1159
2/2
✓ Branch 0 taken 62894 times.
✓ Branch 1 taken 777705 times.
840599 if (shift.amount) {
1160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 62894 times.
62894 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1161 .op = SWS_OP_RSHIFT,
1162 .type = pixel_type,
1163 .shift = shift,
1164 }));
1165 }
1166
1167
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 840599 times.
840599 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1168 .op = SWS_OP_CLEAR,
1169 .type = pixel_type,
1170 .clear = fmt_clear(fmt),
1171 }));
1172
1173 840599 return 0;
1174 }
1175
1176 801231 int ff_sws_encode_pixfmt(SwsOpList *ops, const SwsFormat *fmt)
1177 {
1178 801231 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1179 SwsPixelType pixel_type, raw_type;
1180 SwsReadWriteOp rw_op;
1181 SwsSwizzleOp swizzle;
1182 SwsPackOp pack;
1183 SwsShiftOp shift;
1184
1185
2/2
✓ Branch 1 taken 102176 times.
✓ Branch 2 taken 699055 times.
801231 RET(fmt_analyze(fmt->format, &rw_op, &pack, &swizzle, &shift,
1186 &pixel_type, &raw_type));
1187
1188
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 697991 times.
699055 if (rw_op.mode == SWS_RW_PALETTE)
1189 1064 return AVERROR(ENOTSUP);
1190
1191
2/2
✓ Branch 0 taken 52351 times.
✓ Branch 1 taken 645640 times.
697991 if (shift.amount) {
1192
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 52351 times.
52351 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1193 .op = SWS_OP_LSHIFT,
1194 .type = pixel_type,
1195 .shift = shift,
1196 }));
1197 }
1198
1199
2/2
✓ Branch 0 taken 47016 times.
✓ Branch 1 taken 650975 times.
697991 if (rw_op.elems > desc->nb_components) {
1200 /* Format writes unused alpha channel, clear it explicitly for sanity */
1201 av_assert1(!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
1202
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 47016 times.
47016 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1203 .op = SWS_OP_CLEAR,
1204 .type = pixel_type,
1205 .clear.mask = SWS_COMP(3),
1206 .clear.value[3] = Q(0),
1207 }));
1208 }
1209
1210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 697991 times.
697991 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1211 .op = SWS_OP_SWIZZLE,
1212 .type = pixel_type,
1213 .swizzle = swizzle,
1214 }));
1215
1216
2/2
✓ Branch 0 taken 135820 times.
✓ Branch 1 taken 562171 times.
697991 if (pack.pattern[0]) {
1217
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135820 times.
135820 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1218 .op = SWS_OP_CONVERT,
1219 .type = pixel_type,
1220 .convert.to = raw_type,
1221 }));
1222
1223
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135820 times.
135820 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1224 .op = SWS_OP_PACK,
1225 .type = raw_type,
1226 .pack = pack,
1227 }));
1228 }
1229
1230
2/2
✓ Branch 0 taken 532850 times.
✓ Branch 1 taken 165141 times.
697991 if (ff_sws_pixel_type_size(raw_type) > 1 &&
1231
2/2
✓ Branch 0 taken 266230 times.
✓ Branch 1 taken 266620 times.
532850 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG) {
1232
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 266230 times.
266230 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1233 .op = SWS_OP_SWAP_BYTES,
1234 .type = raw_type,
1235 }));
1236 }
1237
1238
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 697991 times.
697991 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1239 .op = SWS_OP_WRITE,
1240 .type = raw_type,
1241 .rw = rw_op,
1242 }));
1243
1244 697991 return 0;
1245 }
1246
1247 3373772 static inline AVRational64 av_neg_q64(AVRational64 x)
1248 {
1249 3373772 return (AVRational64) { -x.num, x.den };
1250 }
1251
1252 1641830 static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete)
1253 {
1254 1641830 const AVRational64 q0 = Q(0);
1255 const AVRational64 q1 = Q(1);
1256
1257 1641830 SwsLinearOp c = { .m = {
1258 { q1, q0, q0, q0, q0 },
1259 { q0, q1, q0, q0, q0 },
1260 { q0, q0, q1, q0, q0 },
1261 { q0, q0, q0, q1, q0 },
1262 }};
1263
1264 1641830 const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format);
1265 1641830 const int depth0 = desc->comp[0].depth;
1266 1641830 const int depth1 = desc->comp[1].depth;
1267 1641830 const int depth2 = desc->comp[2].depth;
1268 1641830 const int depth3 = desc->comp[3].depth;
1269
1270
2/2
✓ Branch 0 taken 144123 times.
✓ Branch 1 taken 1497707 times.
1641830 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT)
1271 144123 return c; /* floats are directly output as-is */
1272
1273
4/4
✓ Branch 0 taken 741913 times.
✓ Branch 1 taken 755794 times.
✓ Branch 2 taken 320 times.
✓ Branch 3 taken 741593 times.
1497707 if (fmt->csp == AVCOL_SPC_RGB || (desc->flags & AV_PIX_FMT_FLAG_XYZ)) {
1274 756114 c.m[0][0] = intmax_q64(depth0);
1275 756114 c.m[1][1] = intmax_q64(depth1);
1276 756114 c.m[2][2] = intmax_q64(depth2);
1277
2/2
✓ Branch 0 taken 199226 times.
✓ Branch 1 taken 542367 times.
741593 } else if (fmt->range == AVCOL_RANGE_JPEG) {
1278 /* Full range YUV */
1279 199226 c.m[0][0] = intmax_q64(depth0);
1280
2/2
✓ Branch 0 taken 15644 times.
✓ Branch 1 taken 183582 times.
199226 if (desc->nb_components >= 3) {
1281 /* This follows the ITU-R convention, which is slightly different
1282 * from the JFIF convention. */
1283 15644 c.m[1][1] = intmax_q64(depth1);
1284 15644 c.m[2][2] = intmax_q64(depth2);
1285 15644 c.m[1][4] = Q(1 << (depth1 - 1));
1286 15644 c.m[2][4] = Q(1 << (depth2 - 1));
1287 }
1288 } else {
1289 /* Limited range YUV */
1290
1/2
✓ Branch 0 taken 542367 times.
✗ Branch 1 not taken.
542367 if (fmt->range == AVCOL_RANGE_UNSPECIFIED)
1291 542367 *incomplete = true;
1292 542367 c.m[0][0] = Q(219 << (depth0 - 8));
1293 542367 c.m[0][4] = Q( 16 << (depth0 - 8));
1294
1/2
✓ Branch 0 taken 542367 times.
✗ Branch 1 not taken.
542367 if (desc->nb_components >= 3) {
1295 542367 c.m[1][1] = Q(224 << (depth1 - 8));
1296 542367 c.m[2][2] = Q(224 << (depth2 - 8));
1297 542367 c.m[1][4] = Q(128 << (depth1 - 8));
1298 542367 c.m[2][4] = Q(128 << (depth2 - 8));
1299 }
1300 }
1301
1302
2/2
✓ Branch 0 taken 422825 times.
✓ Branch 1 taken 1074882 times.
1497707 if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) {
1303 422825 const bool is_ya = desc->nb_components == 2;
1304
2/2
✓ Branch 0 taken 34602 times.
✓ Branch 1 taken 388223 times.
422825 c.m[3][3] = intmax_q64(is_ya ? depth1 : depth3);
1305 }
1306
1307
2/2
✓ Branch 0 taken 11376 times.
✓ Branch 1 taken 1486331 times.
1497707 if (fmt->format == AV_PIX_FMT_MONOWHITE) {
1308 /* This format is inverted, 0 = white, 1 = black */
1309 11376 c.m[0][4] = ff_add_q64(c.m[0][4], c.m[0][0]);
1310 11376 c.m[0][0] = av_neg_q64(c.m[0][0]);
1311 }
1312
1313 1497707 return c;
1314 }
1315
1316 840599 static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete)
1317 {
1318 840599 SwsLinearOp c = fmt_encode_range(fmt, incomplete);
1319
1320 /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */
1321
2/2
✓ Branch 0 taken 3362396 times.
✓ Branch 1 taken 840599 times.
4202995 for (int i = 0; i < 4; i++) {
1322 av_assert1(c.m[i][i].num);
1323 3362396 c.m[i][i] = ff_inv_q64(c.m[i][i]);
1324 3362396 c.m[i][4] = ff_mul_q64(c.m[i][4], av_neg_q64(c.m[i][i]));
1325 }
1326
1327 /* Explicitly initialize alpha for sanity */
1328
2/2
✓ Branch 0 taken 581827 times.
✓ Branch 1 taken 258772 times.
840599 if (!(fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA))
1329 581827 c.m[3][4] = Q(1);
1330
1331 840599 return c;
1332 }
1333
1334 449681 static AVRational64 *generate_bayer_matrix(const int size_log2)
1335 {
1336 449681 const int size = 1 << size_log2;
1337 449681 const int num_entries = size * size;
1338 449681 AVRational64 *m = av_refstruct_allocz(sizeof(*m) * num_entries);
1339 av_assert1(size_log2 < 16);
1340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 449681 times.
449681 if (!m)
1341 ✗ return NULL;
1342
1343 /* Start with a 1x1 matrix */
1344 449681 m[0] = Q(0);
1345
1346 /* Generate three copies of the current, appropriately scaled and offset */
1347
2/2
✓ Branch 0 taken 1798724 times.
✓ Branch 1 taken 449681 times.
2248405 for (int sz = 1; sz < size; sz <<= 1) {
1348 1798724 const int den = 4 * sz * sz;
1349
2/2
✓ Branch 0 taken 6745215 times.
✓ Branch 1 taken 1798724 times.
8543939 for (int y = 0; y < sz; y++) {
1350
2/2
✓ Branch 0 taken 38222885 times.
✓ Branch 1 taken 6745215 times.
44968100 for (int x = 0; x < sz; x++) {
1351 38222885 const AVRational64 cur = m[y * size + x];
1352 38222885 m[(y + sz) * size + x + sz] = ff_add_q64(cur, ff_make_q64(1, den));
1353 38222885 m[(y ) * size + x + sz] = ff_add_q64(cur, ff_make_q64(2, den));
1354 38222885 m[(y + sz) * size + x ] = ff_add_q64(cur, ff_make_q64(3, den));
1355 }
1356 }
1357 }
1358
1359 /**
1360 * To correctly round, we need to evenly distribute the result on [0, 1),
1361 * giving an average value of 1/2.
1362 *
1363 * After the above construction, we have a matrix with average value:
1364 * [ 0/N + 1/N + 2/N + ... (N-1)/N ] / N = (N-1)/(2N)
1365 * where N = size * size is the total number of entries.
1366 *
1367 * To make the average value equal to 1/2 = N/(2N), add a bias of 1/(2N).
1368 */
1369
2/2
✓ Branch 0 taken 115118336 times.
✓ Branch 1 taken 449681 times.
115568017 for (int i = 0; i < num_entries; i++)
1370 115118336 m[i] = ff_add_q64(m[i], ff_make_q64(1, 2 * num_entries));
1371
1372 449681 return m;
1373 }
1374
1375 738357 static bool trc_is_hdr(enum AVColorTransferCharacteristic trc)
1376 {
1377 static_assert(AVCOL_TRC_NB == 19, "Update this list when adding TRCs");
1378 static_assert(AVCOL_TRC_EXT_NB == 257, "Update this list when adding TRCs");
1379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 738357 times.
738357 switch (trc) {
1380 ✗ case AVCOL_TRC_LOG:
1381 case AVCOL_TRC_LOG_SQRT:
1382 case AVCOL_TRC_V_LOG:
1383 case AVCOL_TRC_SMPTEST2084:
1384 case AVCOL_TRC_ARIB_STD_B67:
1385 ✗ return true;
1386 738357 default:
1387 738357 return false;
1388 }
1389 }
1390
1391 738357 static int fmt_dither(SwsContext *ctx, SwsOpList *ops,
1392 const SwsPixelType type,
1393 const SwsFormat *src, const SwsFormat *dst)
1394 {
1395 738357 SwsDither mode = ctx->dither;
1396 SwsDitherOp dither;
1397 738357 const int bpc = dst->desc->comp[0].depth;
1398
1399
1/2
✓ Branch 0 taken 738357 times.
✗ Branch 1 not taken.
738357 if (mode == SWS_DITHER_AUTO) {
1400 /* Visual threshold of perception: 12 bits for SDR, 14 bits for HDR */
1401
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738357 times.
738357 const int jnd_bits = trc_is_hdr(dst->color.trc) ? 14 : 12;
1402
2/2
✓ Branch 0 taken 288676 times.
✓ Branch 1 taken 449681 times.
738357 mode = bpc >= jnd_bits ? SWS_DITHER_NONE : SWS_DITHER_BAYER;
1403 }
1404
1405
2/5
✓ Branch 0 taken 288676 times.
✓ Branch 1 taken 449681 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
738357 switch (mode) {
1406 288676 case SWS_DITHER_NONE:
1407
2/2
✓ Branch 0 taken 64072 times.
✓ Branch 1 taken 224604 times.
288676 if (ctx->flags & SWS_ACCURATE_RND) {
1408 /* Add constant 0.5 for correct rounding */
1409 64072 AVRational64 *bias = av_refstruct_allocz(sizeof(*bias));
1410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64072 times.
64072 if (!bias)
1411 ✗ return AVERROR(ENOMEM);
1412 64072 *bias = (AVRational64) {1, 2};
1413 64072 return ff_sws_op_list_append(ops, &(SwsOp) {
1414 .op = SWS_OP_DITHER,
1415 .type = type,
1416 .dither.matrix = bias,
1417 .dither.min = *bias,
1418 .dither.max = *bias,
1419 });
1420 } else {
1421 224604 return 0; /* No-op */
1422 }
1423 449681 case SWS_DITHER_BAYER:
1424 /* Hardcode 16x16 matrix for now; in theory we could adjust this
1425 * based on the expected level of precision in the output, since lower
1426 * bit depth outputs can suffice with smaller dither matrices; however
1427 * in practice we probably want to use error diffusion for such low bit
1428 * depths anyway */
1429 449681 dither.size_log2 = 4;
1430 449681 dither.matrix = generate_bayer_matrix(dither.size_log2);
1431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 449681 times.
449681 if (!dither.matrix)
1432 ✗ return AVERROR(ENOMEM);
1433
1434 449681 const int size = 1 << dither.size_log2;
1435 449681 dither.min = dither.max = dither.matrix[0];
1436
2/2
✓ Branch 0 taken 114668655 times.
✓ Branch 1 taken 449681 times.
115118336 for (int i = 1; i < size * size; i++) {
1437
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 114668655 times.
114668655 if (ff_cmp_q64(dither.min, dither.matrix[i]) > 0)
1438 ✗ dither.min = dither.matrix[i];
1439
2/2
✓ Branch 1 taken 6295534 times.
✓ Branch 2 taken 108373121 times.
114668655 if (ff_cmp_q64(dither.matrix[i], dither.max) > 0)
1440 6295534 dither.max = dither.matrix[i];
1441 }
1442
1443 /* Brute-forced offsets; minimizes quantization error across a 16x16
1444 * bayer dither pattern for standard RGBA and YUVA pixel formats */
1445 449681 const int offsets_16x16[4] = {0, 3, 2, 5};
1446
2/2
✓ Branch 0 taken 1798724 times.
✓ Branch 1 taken 449681 times.
2248405 for (int i = 0; i < 4; i++) {
1447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1798724 times.
1798724 av_assert0(offsets_16x16[i] <= INT8_MAX);
1448 1798724 dither.y_offset[i] = offsets_16x16[i];
1449 }
1450
1451 449681 const AVPixFmtDescriptor *src_desc = fmt_desc_decoded(src->format);
1452
4/4
✓ Branch 0 taken 68395 times.
✓ Branch 1 taken 381286 times.
✓ Branch 2 taken 50741 times.
✓ Branch 3 taken 17654 times.
449681 if (src_desc->nb_components < 3 && bpc >= 8) {
1453 /**
1454 * For high-bit-depth sources without chroma, use same matrix
1455 * offset for all color channels. This prevents introducing color
1456 * noise in grayscale images; and also allows optimizing the dither
1457 * operation. Skipped for low bit depth (<8 bpc) as the loss in
1458 * PSNR, from the inability to diffuse error among all three
1459 * channels, can be substantial.
1460 *
1461 * This shifts: { X, Y, Z, W } -> { X, X, X, Y }
1462 */
1463 50741 dither.y_offset[3] = dither.y_offset[1];
1464 50741 dither.y_offset[1] = dither.y_offset[2] = dither.y_offset[0];
1465 }
1466
1467 449681 return ff_sws_op_list_append(ops, &(SwsOp) {
1468 .op = SWS_OP_DITHER,
1469 .type = type,
1470 .dither = dither,
1471 });
1472 ✗ case SWS_DITHER_ED:
1473 case SWS_DITHER_A_DITHER:
1474 case SWS_DITHER_X_DITHER:
1475 ✗ return AVERROR(ENOTSUP);
1476
1477 ✗ case SWS_DITHER_NB:
1478 ✗ break;
1479 }
1480
1481 ✗ av_unreachable("Invalid dither mode");
1482 return AVERROR(EINVAL);
1483 }
1484
1485 #define Q64(x) ff_make_q64((x).num, (x).den)
1486
1487 static inline SwsLinearOp
1488 789521 linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02,
1489 const AVRational m10, const AVRational m11, const AVRational m12,
1490 const AVRational m20, const AVRational m21, const AVRational m22)
1491 {
1492 789521 return (SwsLinearOp) {{
1493 789521 { Q64(m00), Q64(m01), Q64(m02), Q(0), Q(0) },
1494 789521 { Q64(m10), Q64(m11), Q64(m12), Q(0), Q(0) },
1495 789521 { Q64(m20), Q64(m21), Q64(m22), Q(0), Q(0) },
1496 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1497 }};
1498 }
1499
1500 840599 int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type,
1501 SwsOpList *ops, const SwsFormat *fmt, bool *incomplete)
1502 {
1503 840599 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(fmt->csp);
1504 840599 const SwsPixelType pixel_type = fmt_pixel_type(fmt->format);
1505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 840599 times.
840599 if (!pixel_type)
1506 ✗ return AVERROR(ENOTSUP);
1507
1508 840599 const AVRational q0 = av_make_q(0, 1);
1509 840599 const AVRational q1 = av_make_q(1, 1);
1510 840599 const AVRational q2 = av_make_q(2, 1);
1511
1512
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 840599 times.
840599 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1513 .op = SWS_OP_CONVERT,
1514 .type = pixel_type,
1515 .convert.to = type,
1516 }));
1517
1518 /* Decode pixel format into standardized range */
1519
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 840599 times.
840599 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1520 .type = type,
1521 .op = SWS_OP_LINEAR,
1522 .lin = fmt_decode_range(fmt, incomplete),
1523 }));
1524
1525
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 840439 times.
840599 if (fmt->desc->flags & AV_PIX_FMT_FLAG_XYZ)
1526 160 return 0; /* XYZ formats are treated as colorspaceless */
1527
1528 /* Final step, decode colorspace */
1529
2/8
✓ Branch 0 taken 462116 times.
✓ Branch 1 taken 378323 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.
840439 switch (fmt->csp) {
1530 462116 case AVCOL_SPC_RGB:
1531 840439 return 0;
1532 378323 case AVCOL_SPC_UNSPECIFIED:
1533 378323 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1534 378323 *incomplete = true;
1535 av_fallthrough;
1536 378323 case AVCOL_SPC_FCC:
1537 case AVCOL_SPC_BT470BG:
1538 case AVCOL_SPC_SMPTE170M:
1539 case AVCOL_SPC_BT709:
1540 case AVCOL_SPC_SMPTE240M:
1541 case AVCOL_SPC_BT2020_NCL: {
1542 378323 AVRational crg = av_sub_q(q0, av_div_q(c->cr, c->cg));
1543 378323 AVRational cbg = av_sub_q(q0, av_div_q(c->cb, c->cg));
1544 378323 AVRational m02 = av_mul_q(q2, av_sub_q(q1, c->cr));
1545 378323 AVRational m21 = av_mul_q(q2, av_sub_q(q1, c->cb));
1546 378323 AVRational m11 = av_mul_q(cbg, m21);
1547 378323 AVRational m12 = av_mul_q(crg, m02);
1548
1549 378323 return ff_sws_op_list_append(ops, &(SwsOp) {
1550 .type = type,
1551 .op = SWS_OP_LINEAR,
1552 378323 .lin = linear_mat3(
1553 q1, q0, m02,
1554 q1, m11, m12,
1555 q1, m21, q0
1556 ),
1557 });
1558 }
1559
1560 ✗ case AVCOL_SPC_YCGCO:
1561 ✗ return ff_sws_op_list_append(ops, &(SwsOp) {
1562 .type = type,
1563 .op = SWS_OP_LINEAR,
1564 ✗ .lin = linear_mat3(
1565 q1, av_make_q(-1, 1), av_make_q( 1, 1),
1566 q1, av_make_q( 1, 1), av_make_q( 0, 1),
1567 q1, av_make_q(-1, 1), av_make_q(-1, 1)
1568 ),
1569 });
1570
1571 ✗ case AVCOL_SPC_BT2020_CL:
1572 case AVCOL_SPC_SMPTE2085:
1573 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1574 case AVCOL_SPC_CHROMA_DERIVED_CL:
1575 case AVCOL_SPC_ICTCP:
1576 case AVCOL_SPC_IPT_C2:
1577 case AVCOL_SPC_YCGCO_RE:
1578 case AVCOL_SPC_YCGCO_RO:
1579 ✗ return AVERROR(ENOTSUP);
1580
1581 ✗ case AVCOL_SPC_RESERVED:
1582 ✗ return AVERROR(EINVAL);
1583
1584 ✗ case AVCOL_SPC_NB:
1585 ✗ break;
1586 }
1587
1588 ✗ av_unreachable("Corrupt AVColorSpace value?");
1589 return AVERROR(EINVAL);
1590 }
1591
1592 840599 int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type,
1593 SwsOpList *ops, const SwsFormat *src,
1594 const SwsFormat *dst, bool *incomplete)
1595 {
1596 840599 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(dst->csp);
1597 840599 const SwsPixelType pixel_type = fmt_pixel_type(dst->format);
1598
2/2
✓ Branch 0 taken 39368 times.
✓ Branch 1 taken 801231 times.
840599 if (!pixel_type)
1599 39368 return AVERROR(ENOTSUP);
1600
1601 /* See ff_sws_decode_colors(): XYZ formats have no colorspace matrix */
1602
4/9
✓ Branch 0 taken 801071 times.
✓ Branch 1 taken 160 times.
✓ Branch 2 taken 390033 times.
✓ Branch 3 taken 411198 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
801231 switch (dst->desc->flags & AV_PIX_FMT_FLAG_XYZ ? AVCOL_SPC_RGB : dst->csp) {
1603 390033 case AVCOL_SPC_RGB:
1604 390033 break;
1605 411198 case AVCOL_SPC_UNSPECIFIED:
1606 411198 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1607 411198 *incomplete = true;
1608 av_fallthrough;
1609 411198 case AVCOL_SPC_FCC:
1610 case AVCOL_SPC_BT470BG:
1611 case AVCOL_SPC_SMPTE170M:
1612 case AVCOL_SPC_BT709:
1613 case AVCOL_SPC_SMPTE240M:
1614 case AVCOL_SPC_BT2020_NCL: {
1615 411198 AVRational cb1 = av_sub_q(c->cb, av_make_q(1, 1));
1616 411198 AVRational cr1 = av_sub_q(c->cr, av_make_q(1, 1));
1617 411198 AVRational m20 = av_make_q(1,2);
1618 411198 AVRational m10 = av_mul_q(m20, av_div_q(c->cr, cb1));
1619 411198 AVRational m11 = av_mul_q(m20, av_div_q(c->cg, cb1));
1620 411198 AVRational m21 = av_mul_q(m20, av_div_q(c->cg, cr1));
1621 411198 AVRational m22 = av_mul_q(m20, av_div_q(c->cb, cr1));
1622
1623
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 411198 times.
411198 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1624 .type = type,
1625 .op = SWS_OP_LINEAR,
1626 .lin = linear_mat3(
1627 c->cr, c->cg, c->cb,
1628 m10, m11, m20,
1629 m20, m21, m22
1630 ),
1631 }));
1632 411198 break;
1633 }
1634
1635 ✗ case AVCOL_SPC_YCGCO:
1636 ✗ RET(ff_sws_op_list_append(ops, &(SwsOp) {
1637 .type = type,
1638 .op = SWS_OP_LINEAR,
1639 .lin = linear_mat3(
1640 av_make_q( 1, 4), av_make_q(1, 2), av_make_q( 1, 4),
1641 av_make_q( 1, 2), av_make_q(0, 1), av_make_q(-1, 2),
1642 av_make_q(-1, 4), av_make_q(1, 2), av_make_q(-1, 4)
1643 ),
1644 }));
1645 ✗ break;
1646
1647 ✗ case AVCOL_SPC_BT2020_CL:
1648 case AVCOL_SPC_SMPTE2085:
1649 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1650 case AVCOL_SPC_CHROMA_DERIVED_CL:
1651 case AVCOL_SPC_ICTCP:
1652 case AVCOL_SPC_IPT_C2:
1653 case AVCOL_SPC_YCGCO_RE:
1654 case AVCOL_SPC_YCGCO_RO:
1655 ✗ return AVERROR(ENOTSUP);
1656
1657 ✗ case AVCOL_SPC_RESERVED:
1658 case AVCOL_SPC_NB:
1659 ✗ return AVERROR(EINVAL);
1660 }
1661
1662
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 801231 times.
801231 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1663 .type = type,
1664 .op = SWS_OP_LINEAR,
1665 .lin = fmt_encode_range(dst, incomplete),
1666 }));
1667
1668
2/2
✓ Branch 0 taken 738357 times.
✓ Branch 1 taken 62874 times.
801231 if (!(dst->desc->flags & AV_PIX_FMT_FLAG_FLOAT)) {
1669 738357 SwsClampOp range = {0};
1670
1671 738357 const bool is_ya = dst->desc->nb_components == 2;
1672
2/2
✓ Branch 0 taken 2248925 times.
✓ Branch 1 taken 738357 times.
2987282 for (int i = 0; i < dst->desc->nb_components; i++) {
1673 /* Clamp to legal pixel range */
1674
2/2
✓ Branch 0 taken 31416 times.
✓ Branch 1 taken 2217509 times.
2248925 const int idx = i * (is_ya ? 3 : 1);
1675 2248925 range.limit[idx] = intmax_q64(dst->desc->comp[i].depth);
1676 }
1677
1678
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738357 times.
738357 RET(fmt_dither(ctx, ops, type, src, dst));
1679
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738357 times.
738357 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1680 .op = SWS_OP_MAX,
1681 .type = type,
1682 .clamp = {{ Q(0), Q(0), Q(0), Q(0) }},
1683 }));
1684
1685
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738357 times.
738357 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1686 .op = SWS_OP_MIN,
1687 .type = type,
1688 .clamp = range,
1689 }));
1690 }
1691
1692 801231 return ff_sws_op_list_append(ops, &(SwsOp) {
1693 .type = type,
1694 .op = SWS_OP_CONVERT,
1695 .convert.to = pixel_type,
1696 });
1697 }
1698
1699 669777 static SwsScaler get_scaler_fallback(SwsContext *ctx)
1700 {
1701
2/2
✓ Branch 0 taken 491680 times.
✓ Branch 1 taken 178097 times.
669777 if (ctx->scaler != SWS_SCALE_AUTO)
1702 491680 return ctx->scaler;
1703
1704 /* Backwards compatibility with legacy flags API */
1705
2/2
✓ Branch 0 taken 19360 times.
✓ Branch 1 taken 158737 times.
178097 if (ctx->flags & SWS_BILINEAR) {
1706 19360 return SWS_SCALE_BILINEAR;
1707
2/2
✓ Branch 0 taken 95608 times.
✓ Branch 1 taken 63129 times.
158737 } else if (ctx->flags & (SWS_BICUBIC | SWS_BICUBLIN)) {
1708 95608 return SWS_SCALE_BICUBIC;
1709
2/2
✓ Branch 0 taken 13098 times.
✓ Branch 1 taken 50031 times.
63129 } else if (ctx->flags & SWS_POINT) {
1710 13098 return SWS_SCALE_POINT;
1711
2/2
✓ Branch 0 taken 12795 times.
✓ Branch 1 taken 37236 times.
50031 } else if (ctx->flags & SWS_AREA) {
1712 12795 return SWS_SCALE_AREA;
1713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37236 times.
37236 } else if (ctx->flags & SWS_GAUSS) {
1714 ✗ return SWS_SCALE_GAUSSIAN;
1715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37236 times.
37236 } else if (ctx->flags & SWS_SINC) {
1716 ✗ return SWS_SCALE_SINC;
1717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37236 times.
37236 } else if (ctx->flags & SWS_LANCZOS) {
1718 ✗ return SWS_SCALE_LANCZOS;
1719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37236 times.
37236 } else if (ctx->flags & SWS_SPLINE) {
1720 ✗ return SWS_SCALE_SPLINE;
1721 } else {
1722 37236 return SWS_SCALE_AUTO;
1723 }
1724 }
1725
1726 1681198 static int add_filter(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1727 SwsOpType filter, int src_size, int dst_size)
1728 {
1729
2/2
✓ Branch 0 taken 1011421 times.
✓ Branch 1 taken 669777 times.
1681198 if (src_size == dst_size)
1730 1011421 return 0; /* no-op */
1731
1732 1339554 SwsFilterParams params = {
1733 669777 .scaler = get_scaler_fallback(ctx),
1734 .src_size = src_size,
1735 .dst_size = dst_size,
1736 };
1737
1738
2/2
✓ Branch 0 taken 1339554 times.
✓ Branch 1 taken 669777 times.
2009331 for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
1739 1339554 params.scaler_params[i] = ctx->scaler_params[i];
1740
1741 SwsFilterWeights *kernel;
1742 669777 int ret = ff_sws_filter_generate(ctx, &params, &kernel);
1743
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 669777 times.
669777 if (ret == AVERROR(ENOTSUP)) {
1744 /* Filter size exceeds limit; cascade with geometric mean size */
1745 ✗ int mean = sqrt((int64_t) src_size * dst_size);
1746 ✗ if (mean == src_size || mean == dst_size)
1747 ✗ return AVERROR_BUG; /* sanity, prevent infinite loop */
1748 ✗ ret = add_filter(ctx, type, ops, filter, src_size, mean);
1749 ✗ if (ret < 0)
1750 ✗ return ret;
1751 ✗ return add_filter(ctx, type, ops, filter, mean, dst_size);
1752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 669777 times.
669777 } else if (ret < 0) {
1753 ✗ return ret;
1754 }
1755
1756 669777 return ff_sws_op_list_append(ops, &(SwsOp) {
1757 .type = type,
1758 .op = filter,
1759 .filter.kernel = kernel,
1760 .filter.type = type,
1761 });
1762 }
1763
1764 840599 int ff_sws_add_filters(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1765 const SwsFormat *src, const SwsFormat *dst)
1766 {
1767 /**
1768 * Always perform horizontal scaling first, since it's much more likely to
1769 * benefit from small integer optimizations; we should maybe flip the order
1770 * here if we're downscaling the vertical resolution by a lot, though.
1771 */
1772 840599 int ret = add_filter(ctx, type, ops, SWS_OP_FILTER_H, src->width, dst->width);
1773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 840599 times.
840599 if (ret < 0)
1774 ✗ return ret;
1775
1776 840599 return add_filter(ctx, type, ops, SWS_OP_FILTER_V, src->height, dst->height);
1777 }
1778
1779 176132 int ff_sws_apply_lut3d(SwsContext *ctx, SwsPixelType type, SwsOpList *ops,
1780 const SwsLut3D *lut3d)
1781 {
1782 /* Unnormalize to LUT input domain and clamp */
1783 const AVRational64 domain = Q(INPUT_LUT_SIZE - 1);
1784
1785
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176132 times.
176132 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1786 .type = type,
1787 .op = SWS_OP_LINEAR,
1788 .lin = {{
1789 { domain, Q(0), Q(0), Q(0), Q(0) },
1790 { Q(0), domain, Q(0), Q(0), Q(0) },
1791 { Q(0), Q(0), domain, Q(0), Q(0) },
1792 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1793 }},
1794 }));
1795
1796
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176132 times.
176132 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1797 .op = SWS_OP_MAX,
1798 .type = type,
1799 .clamp = {{ Q(0), Q(0), Q(0) }},
1800 }));
1801
1802
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176132 times.
176132 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1803 .op = SWS_OP_MIN,
1804 .type = type,
1805 .clamp = {{ domain, domain, domain }},
1806 }));
1807
1808 /* Apply the 3DLUT itself */
1809
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 176132 times.
176132 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1810 .op = SWS_OP_LUT_3D,
1811 .type = type,
1812 .lut3d.lut = av_refstruct_ref_c(lut3d),
1813 .lut3d.dynamic = lut3d->dynamic,
1814 }));
1815
1816 /* Normalize back to [0, 1] */
1817 176132 const AVRational64 inv = ff_inv_q64(Q(UINT16_MAX));
1818
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 176132 times.
176132 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1819 .type = type,
1820 .op = SWS_OP_LINEAR,
1821 .lin = {{
1822 { inv, Q(0), Q(0), Q(0), Q(0) },
1823 { Q(0), inv, Q(0), Q(0), Q(0) },
1824 { Q(0), Q(0), inv, Q(0), Q(0) },
1825 { Q(0), Q(0), Q(0), Q(1), Q(0) },
1826 }},
1827 }));
1828
1829 176132 return 0;
1830 }
1831
1832 1144563 int ff_sws_op_list_generate(SwsContext *ctx, const SwsFormat *src,
1833 const SwsFormat *dst, const SwsLut3D *lut3d,
1834 SwsOpList **out_ops, bool *incomplete)
1835 {
1836 /* The new code does not yet support alpha blending */
1837
2/2
✓ Branch 0 taken 318770 times.
✓ Branch 1 taken 825793 times.
1144563 if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
1838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 318770 times.
318770 ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
1839 ✗ return AVERROR(ENOTSUP);
1840
1841 /* XYZ<->RGB conversion requires application of a gamma function which
1842 * are not currently implemented */
1843
2/2
✓ Branch 0 taken 20876 times.
✓ Branch 1 taken 1123687 times.
1144563 if ((src->desc->flags ^ dst->desc->flags) & AV_PIX_FMT_FLAG_XYZ)
1844 20876 return AVERROR(ENOTSUP);
1845
1846 1123687 SwsOpList *ops = ff_sws_op_list_alloc();
1847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1123687 times.
1123687 if (!ops)
1848 ✗ return AVERROR(ENOMEM);
1849 1123687 ops->src = *src;
1850 1123687 ops->dst = *dst;
1851
1852 1123687 const SwsPixelType type = SWS_PIXEL_F32;
1853 1123687 int ret = ff_sws_decode_pixfmt(ops, src);
1854
2/2
✓ Branch 0 taken 283088 times.
✓ Branch 1 taken 840599 times.
1123687 if (ret < 0)
1855 283088 goto fail;
1856 840599 ret = ff_sws_decode_colors(ctx, type, ops, src, incomplete);
1857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 840599 times.
840599 if (ret < 0)
1858 ✗ goto fail;
1859 840599 ret = ff_sws_add_filters(ctx, type, ops, src, dst);
1860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 840599 times.
840599 if (ret < 0)
1861 ✗ goto fail;
1862
2/2
✓ Branch 0 taken 176132 times.
✓ Branch 1 taken 664467 times.
840599 if (lut3d) {
1863 176132 ret = ff_sws_apply_lut3d(ctx, type, ops, lut3d);
1864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176132 times.
176132 if (ret < 0)
1865 ✗ goto fail;
1866 }
1867 840599 ret = ff_sws_encode_colors(ctx, type, ops, src, dst, incomplete);
1868
2/2
✓ Branch 0 taken 39368 times.
✓ Branch 1 taken 801231 times.
840599 if (ret < 0)
1869 39368 goto fail;
1870 801231 ret = ff_sws_encode_pixfmt(ops, dst);
1871
2/2
✓ Branch 0 taken 103240 times.
✓ Branch 1 taken 697991 times.
801231 if (ret < 0)
1872 103240 goto fail;
1873
1874 697991 *out_ops = ops;
1875 697991 return 0;
1876
1877 425696 fail:
1878 425696 ff_sws_op_list_free(&ops);
1879 425696 return ret;
1880 }
1881
1882 #else /* !CONFIG_UNSTABLE */
1883
1884 static int test_format_ops(enum AVPixelFormat format, int output)
1885 {
1886 return 0;
1887 }
1888
1889 #endif
1890