FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/format.c
Date: 2026-05-01 13:04:54
Exec Total Coverage
Lines: 520 581 89.5%
Functions: 38 39 97.4%
Branches: 292 395 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 Q(N) ((AVRational) { N, 1 })
37 #define Q0 Q(0)
38 #define Q1 Q(1)
39
40 #define RET(x) \
41 do { \
42 int _ret = (x); \
43 if (_ret < 0) \
44 return _ret; \
45 } while (0)
46
47 typedef struct LegacyFormatEntry {
48 uint8_t is_supported_in :1;
49 uint8_t is_supported_out :1;
50 uint8_t is_supported_endianness :1;
51 } LegacyFormatEntry;
52
53 /* Format support table for legacy swscale */
54 static const LegacyFormatEntry legacy_format_entries[] = {
55 [AV_PIX_FMT_YUV420P] = { 1, 1 },
56 [AV_PIX_FMT_YUYV422] = { 1, 1 },
57 [AV_PIX_FMT_RGB24] = { 1, 1 },
58 [AV_PIX_FMT_BGR24] = { 1, 1 },
59 [AV_PIX_FMT_YUV422P] = { 1, 1 },
60 [AV_PIX_FMT_YUV444P] = { 1, 1 },
61 [AV_PIX_FMT_YUV410P] = { 1, 1 },
62 [AV_PIX_FMT_YUV411P] = { 1, 1 },
63 [AV_PIX_FMT_GRAY8] = { 1, 1 },
64 [AV_PIX_FMT_MONOWHITE] = { 1, 1 },
65 [AV_PIX_FMT_MONOBLACK] = { 1, 1 },
66 [AV_PIX_FMT_PAL8] = { 1, 0 },
67 [AV_PIX_FMT_YUVJ420P] = { 1, 1 },
68 [AV_PIX_FMT_YUVJ411P] = { 1, 1 },
69 [AV_PIX_FMT_YUVJ422P] = { 1, 1 },
70 [AV_PIX_FMT_YUVJ444P] = { 1, 1 },
71 [AV_PIX_FMT_YVYU422] = { 1, 1 },
72 [AV_PIX_FMT_UYVY422] = { 1, 1 },
73 [AV_PIX_FMT_UYYVYY411] = { 1, 0 },
74 [AV_PIX_FMT_BGR8] = { 1, 1 },
75 [AV_PIX_FMT_BGR4] = { 0, 1 },
76 [AV_PIX_FMT_BGR4_BYTE] = { 1, 1 },
77 [AV_PIX_FMT_RGB8] = { 1, 1 },
78 [AV_PIX_FMT_RGB4] = { 0, 1 },
79 [AV_PIX_FMT_RGB4_BYTE] = { 1, 1 },
80 [AV_PIX_FMT_NV12] = { 1, 1 },
81 [AV_PIX_FMT_NV21] = { 1, 1 },
82 [AV_PIX_FMT_ARGB] = { 1, 1 },
83 [AV_PIX_FMT_RGBA] = { 1, 1 },
84 [AV_PIX_FMT_ABGR] = { 1, 1 },
85 [AV_PIX_FMT_BGRA] = { 1, 1 },
86 [AV_PIX_FMT_0RGB] = { 1, 1 },
87 [AV_PIX_FMT_RGB0] = { 1, 1 },
88 [AV_PIX_FMT_0BGR] = { 1, 1 },
89 [AV_PIX_FMT_BGR0] = { 1, 1 },
90 [AV_PIX_FMT_GRAY9BE] = { 1, 1 },
91 [AV_PIX_FMT_GRAY9LE] = { 1, 1 },
92 [AV_PIX_FMT_GRAY10BE] = { 1, 1 },
93 [AV_PIX_FMT_GRAY10LE] = { 1, 1 },
94 [AV_PIX_FMT_GRAY12BE] = { 1, 1 },
95 [AV_PIX_FMT_GRAY12LE] = { 1, 1 },
96 [AV_PIX_FMT_GRAY14BE] = { 1, 1 },
97 [AV_PIX_FMT_GRAY14LE] = { 1, 1 },
98 [AV_PIX_FMT_GRAY16BE] = { 1, 1 },
99 [AV_PIX_FMT_GRAY16LE] = { 1, 1 },
100 [AV_PIX_FMT_YUV440P] = { 1, 1 },
101 [AV_PIX_FMT_YUVJ440P] = { 1, 1 },
102 [AV_PIX_FMT_YUV440P10LE] = { 1, 1 },
103 [AV_PIX_FMT_YUV440P10BE] = { 1, 1 },
104 [AV_PIX_FMT_YUV440P12LE] = { 1, 1 },
105 [AV_PIX_FMT_YUV440P12BE] = { 1, 1 },
106 [AV_PIX_FMT_YUVA420P] = { 1, 1 },
107 [AV_PIX_FMT_YUVA422P] = { 1, 1 },
108 [AV_PIX_FMT_YUVA444P] = { 1, 1 },
109 [AV_PIX_FMT_YUVA420P9BE] = { 1, 1 },
110 [AV_PIX_FMT_YUVA420P9LE] = { 1, 1 },
111 [AV_PIX_FMT_YUVA422P9BE] = { 1, 1 },
112 [AV_PIX_FMT_YUVA422P9LE] = { 1, 1 },
113 [AV_PIX_FMT_YUVA444P9BE] = { 1, 1 },
114 [AV_PIX_FMT_YUVA444P9LE] = { 1, 1 },
115 [AV_PIX_FMT_YUVA420P10BE] = { 1, 1 },
116 [AV_PIX_FMT_YUVA420P10LE] = { 1, 1 },
117 [AV_PIX_FMT_YUVA422P10BE] = { 1, 1 },
118 [AV_PIX_FMT_YUVA422P10LE] = { 1, 1 },
119 [AV_PIX_FMT_YUVA444P10BE] = { 1, 1 },
120 [AV_PIX_FMT_YUVA444P10LE] = { 1, 1 },
121 [AV_PIX_FMT_YUVA420P16BE] = { 1, 1 },
122 [AV_PIX_FMT_YUVA420P16LE] = { 1, 1 },
123 [AV_PIX_FMT_YUVA422P16BE] = { 1, 1 },
124 [AV_PIX_FMT_YUVA422P16LE] = { 1, 1 },
125 [AV_PIX_FMT_YUVA444P16BE] = { 1, 1 },
126 [AV_PIX_FMT_YUVA444P16LE] = { 1, 1 },
127 [AV_PIX_FMT_RGB48BE] = { 1, 1 },
128 [AV_PIX_FMT_RGB48LE] = { 1, 1 },
129 [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 },
130 [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 },
131 [AV_PIX_FMT_RGB565BE] = { 1, 1 },
132 [AV_PIX_FMT_RGB565LE] = { 1, 1 },
133 [AV_PIX_FMT_RGB555BE] = { 1, 1 },
134 [AV_PIX_FMT_RGB555LE] = { 1, 1 },
135 [AV_PIX_FMT_BGR565BE] = { 1, 1 },
136 [AV_PIX_FMT_BGR565LE] = { 1, 1 },
137 [AV_PIX_FMT_BGR555BE] = { 1, 1 },
138 [AV_PIX_FMT_BGR555LE] = { 1, 1 },
139 [AV_PIX_FMT_YUV420P16LE] = { 1, 1 },
140 [AV_PIX_FMT_YUV420P16BE] = { 1, 1 },
141 [AV_PIX_FMT_YUV422P16LE] = { 1, 1 },
142 [AV_PIX_FMT_YUV422P16BE] = { 1, 1 },
143 [AV_PIX_FMT_YUV444P16LE] = { 1, 1 },
144 [AV_PIX_FMT_YUV444P16BE] = { 1, 1 },
145 [AV_PIX_FMT_RGB444LE] = { 1, 1 },
146 [AV_PIX_FMT_RGB444BE] = { 1, 1 },
147 [AV_PIX_FMT_BGR444LE] = { 1, 1 },
148 [AV_PIX_FMT_BGR444BE] = { 1, 1 },
149 [AV_PIX_FMT_YA8] = { 1, 1 },
150 [AV_PIX_FMT_YA16BE] = { 1, 1 },
151 [AV_PIX_FMT_YA16LE] = { 1, 1 },
152 [AV_PIX_FMT_BGR48BE] = { 1, 1 },
153 [AV_PIX_FMT_BGR48LE] = { 1, 1 },
154 [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 },
155 [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 },
156 [AV_PIX_FMT_YUV420P9BE] = { 1, 1 },
157 [AV_PIX_FMT_YUV420P9LE] = { 1, 1 },
158 [AV_PIX_FMT_YUV420P10BE] = { 1, 1 },
159 [AV_PIX_FMT_YUV420P10LE] = { 1, 1 },
160 [AV_PIX_FMT_YUV420P12BE] = { 1, 1 },
161 [AV_PIX_FMT_YUV420P12LE] = { 1, 1 },
162 [AV_PIX_FMT_YUV420P14BE] = { 1, 1 },
163 [AV_PIX_FMT_YUV420P14LE] = { 1, 1 },
164 [AV_PIX_FMT_YUV422P9BE] = { 1, 1 },
165 [AV_PIX_FMT_YUV422P9LE] = { 1, 1 },
166 [AV_PIX_FMT_YUV422P10BE] = { 1, 1 },
167 [AV_PIX_FMT_YUV422P10LE] = { 1, 1 },
168 [AV_PIX_FMT_YUV422P12BE] = { 1, 1 },
169 [AV_PIX_FMT_YUV422P12LE] = { 1, 1 },
170 [AV_PIX_FMT_YUV422P14BE] = { 1, 1 },
171 [AV_PIX_FMT_YUV422P14LE] = { 1, 1 },
172 [AV_PIX_FMT_YUV444P9BE] = { 1, 1 },
173 [AV_PIX_FMT_YUV444P9LE] = { 1, 1 },
174 [AV_PIX_FMT_YUV444P10BE] = { 1, 1 },
175 [AV_PIX_FMT_YUV444P10LE] = { 1, 1 },
176 [AV_PIX_FMT_YUV444P12BE] = { 1, 1 },
177 [AV_PIX_FMT_YUV444P12LE] = { 1, 1 },
178 [AV_PIX_FMT_YUV444P14BE] = { 1, 1 },
179 [AV_PIX_FMT_YUV444P14LE] = { 1, 1 },
180 [AV_PIX_FMT_YUV444P10MSBBE] = { 1, 1 },
181 [AV_PIX_FMT_YUV444P10MSBLE] = { 1, 1 },
182 [AV_PIX_FMT_YUV444P12MSBBE] = { 1, 1 },
183 [AV_PIX_FMT_YUV444P12MSBLE] = { 1, 1 },
184 [AV_PIX_FMT_GBRP] = { 1, 1 },
185 [AV_PIX_FMT_GBRP9LE] = { 1, 1 },
186 [AV_PIX_FMT_GBRP9BE] = { 1, 1 },
187 [AV_PIX_FMT_GBRP10LE] = { 1, 1 },
188 [AV_PIX_FMT_GBRP10BE] = { 1, 1 },
189 [AV_PIX_FMT_GBRAP10LE] = { 1, 1 },
190 [AV_PIX_FMT_GBRAP10BE] = { 1, 1 },
191 [AV_PIX_FMT_GBRP10MSBLE] = { 1, 1 },
192 [AV_PIX_FMT_GBRP10MSBBE] = { 1, 1 },
193 [AV_PIX_FMT_GBRP12LE] = { 1, 1 },
194 [AV_PIX_FMT_GBRP12BE] = { 1, 1 },
195 [AV_PIX_FMT_GBRP12MSBLE] = { 1, 1 },
196 [AV_PIX_FMT_GBRP12MSBBE] = { 1, 1 },
197 [AV_PIX_FMT_GBRAP12LE] = { 1, 1 },
198 [AV_PIX_FMT_GBRAP12BE] = { 1, 1 },
199 [AV_PIX_FMT_GBRP14LE] = { 1, 1 },
200 [AV_PIX_FMT_GBRP14BE] = { 1, 1 },
201 [AV_PIX_FMT_GBRAP14LE] = { 1, 1 },
202 [AV_PIX_FMT_GBRAP14BE] = { 1, 1 },
203 [AV_PIX_FMT_GBRP16LE] = { 1, 1 },
204 [AV_PIX_FMT_GBRP16BE] = { 1, 1 },
205 [AV_PIX_FMT_GBRPF32LE] = { 1, 1 },
206 [AV_PIX_FMT_GBRPF32BE] = { 1, 1 },
207 [AV_PIX_FMT_GBRAPF32LE] = { 1, 1 },
208 [AV_PIX_FMT_GBRAPF32BE] = { 1, 1 },
209 [AV_PIX_FMT_GBRPF16LE] = { 1, 0 },
210 [AV_PIX_FMT_GBRPF16BE] = { 1, 0 },
211 [AV_PIX_FMT_GBRAPF16LE] = { 1, 0 },
212 [AV_PIX_FMT_GBRAPF16BE] = { 1, 0 },
213 [AV_PIX_FMT_GBRAP] = { 1, 1 },
214 [AV_PIX_FMT_GBRAP16LE] = { 1, 1 },
215 [AV_PIX_FMT_GBRAP16BE] = { 1, 1 },
216 [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 },
217 [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 },
218 [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 },
219 [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 },
220 [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 },
221 [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 },
222 [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 },
223 [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 },
224 [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 },
225 [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 },
226 [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 },
227 [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 },
228 [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 },
229 [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 },
230 [AV_PIX_FMT_AYUV64LE] = { 1, 1},
231 [AV_PIX_FMT_AYUV64BE] = { 1, 1 },
232 [AV_PIX_FMT_P010LE] = { 1, 1 },
233 [AV_PIX_FMT_P010BE] = { 1, 1 },
234 [AV_PIX_FMT_P012LE] = { 1, 1 },
235 [AV_PIX_FMT_P012BE] = { 1, 1 },
236 [AV_PIX_FMT_P016LE] = { 1, 1 },
237 [AV_PIX_FMT_P016BE] = { 1, 1 },
238 [AV_PIX_FMT_GRAYF32LE] = { 1, 1 },
239 [AV_PIX_FMT_GRAYF32BE] = { 1, 1 },
240 [AV_PIX_FMT_GRAYF16LE] = { 1, 0 },
241 [AV_PIX_FMT_GRAYF16BE] = { 1, 0 },
242 [AV_PIX_FMT_YAF32LE] = { 1, 0 },
243 [AV_PIX_FMT_YAF32BE] = { 1, 0 },
244 [AV_PIX_FMT_YAF16LE] = { 1, 0 },
245 [AV_PIX_FMT_YAF16BE] = { 1, 0 },
246 [AV_PIX_FMT_YUVA422P12BE] = { 1, 1 },
247 [AV_PIX_FMT_YUVA422P12LE] = { 1, 1 },
248 [AV_PIX_FMT_YUVA444P12BE] = { 1, 1 },
249 [AV_PIX_FMT_YUVA444P12LE] = { 1, 1 },
250 [AV_PIX_FMT_NV24] = { 1, 1 },
251 [AV_PIX_FMT_NV42] = { 1, 1 },
252 [AV_PIX_FMT_Y210LE] = { 1, 1 },
253 [AV_PIX_FMT_Y212LE] = { 1, 1 },
254 [AV_PIX_FMT_Y216LE] = { 1, 1 },
255 [AV_PIX_FMT_X2RGB10LE] = { 1, 1 },
256 [AV_PIX_FMT_X2BGR10LE] = { 1, 1 },
257 [AV_PIX_FMT_NV20BE] = { 1, 1 },
258 [AV_PIX_FMT_NV20LE] = { 1, 1 },
259 [AV_PIX_FMT_P210BE] = { 1, 1 },
260 [AV_PIX_FMT_P210LE] = { 1, 1 },
261 [AV_PIX_FMT_P212BE] = { 1, 1 },
262 [AV_PIX_FMT_P212LE] = { 1, 1 },
263 [AV_PIX_FMT_P410BE] = { 1, 1 },
264 [AV_PIX_FMT_P410LE] = { 1, 1 },
265 [AV_PIX_FMT_P412BE] = { 1, 1 },
266 [AV_PIX_FMT_P412LE] = { 1, 1 },
267 [AV_PIX_FMT_P216BE] = { 1, 1 },
268 [AV_PIX_FMT_P216LE] = { 1, 1 },
269 [AV_PIX_FMT_P416BE] = { 1, 1 },
270 [AV_PIX_FMT_P416LE] = { 1, 1 },
271 [AV_PIX_FMT_NV16] = { 1, 1 },
272 [AV_PIX_FMT_VUYA] = { 1, 1 },
273 [AV_PIX_FMT_VUYX] = { 1, 1 },
274 [AV_PIX_FMT_RGBAF16BE] = { 1, 0 },
275 [AV_PIX_FMT_RGBAF16LE] = { 1, 0 },
276 [AV_PIX_FMT_RGBF16BE] = { 1, 0 },
277 [AV_PIX_FMT_RGBF16LE] = { 1, 0 },
278 [AV_PIX_FMT_RGBF32BE] = { 1, 0 },
279 [AV_PIX_FMT_RGBF32LE] = { 1, 0 },
280 [AV_PIX_FMT_XV30LE] = { 1, 1 },
281 [AV_PIX_FMT_XV36LE] = { 1, 1 },
282 [AV_PIX_FMT_XV36BE] = { 1, 1 },
283 [AV_PIX_FMT_XV48LE] = { 1, 1 },
284 [AV_PIX_FMT_XV48BE] = { 1, 1 },
285 [AV_PIX_FMT_AYUV] = { 1, 1 },
286 [AV_PIX_FMT_UYVA] = { 1, 1 },
287 [AV_PIX_FMT_VYU444] = { 1, 1 },
288 [AV_PIX_FMT_V30XLE] = { 1, 1 },
289 };
290
291 2013636 int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
292 {
293 2013636 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
294
2/2
✓ Branch 0 taken 2006838 times.
✓ Branch 1 taken 6798 times.
2013636 legacy_format_entries[pix_fmt].is_supported_in : 0;
295 }
296
297 2009968 int sws_isSupportedOutput(enum AVPixelFormat pix_fmt)
298 {
299 2009968 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
300
2/2
✓ Branch 0 taken 2003301 times.
✓ Branch 1 taken 6667 times.
2009968 legacy_format_entries[pix_fmt].is_supported_out : 0;
301 }
302
303 51719 int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
304 {
305 51719 return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ?
306
1/2
✓ Branch 0 taken 51719 times.
✗ Branch 1 not taken.
51719 legacy_format_entries[pix_fmt].is_supported_endianness : 0;
307 }
308
309 676120 static void sanitize_fmt(SwsFormat *fmt, const AVPixFmtDescriptor *desc)
310 {
311
2/2
✓ Branch 0 taken 221107 times.
✓ Branch 1 taken 455013 times.
676120 if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER)) {
312 /* RGB-like family */
313 221107 fmt->csp = AVCOL_SPC_RGB;
314 221107 fmt->range = AVCOL_RANGE_JPEG;
315
2/2
✓ Branch 0 taken 3668 times.
✓ Branch 1 taken 451345 times.
455013 } else if (desc->flags & AV_PIX_FMT_FLAG_XYZ) {
316 3668 fmt->csp = AVCOL_SPC_UNSPECIFIED;
317 3668 fmt->color = (SwsColor) {
318 .prim = AVCOL_PRI_BT709, /* swscale currently hard-codes this XYZ matrix */
319 .trc = AVCOL_TRC_SMPTE428,
320 };
321
2/2
✓ Branch 0 taken 49978 times.
✓ Branch 1 taken 401367 times.
451345 } else if (desc->nb_components < 3) {
322 /* Grayscale formats */
323 49978 fmt->color.prim = AVCOL_PRI_UNSPECIFIED;
324 49978 fmt->csp = AVCOL_SPC_UNSPECIFIED;
325
2/2
✓ Branch 0 taken 5948 times.
✓ Branch 1 taken 44030 times.
49978 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT)
326 5948 fmt->range = AVCOL_RANGE_UNSPECIFIED;
327 else
328 44030 fmt->range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted
329 }
330
331
2/2
✓ Branch 1 taken 14507 times.
✓ Branch 2 taken 661613 times.
676120 switch (av_pix_fmt_desc_get_id(desc)) {
332 14507 case AV_PIX_FMT_YUVJ420P:
333 case AV_PIX_FMT_YUVJ411P:
334 case AV_PIX_FMT_YUVJ422P:
335 case AV_PIX_FMT_YUVJ444P:
336 case AV_PIX_FMT_YUVJ440P:
337 14507 fmt->range = AVCOL_RANGE_JPEG;
338 14507 break;
339 }
340
341
4/4
✓ Branch 0 taken 469786 times.
✓ Branch 1 taken 206334 times.
✓ Branch 2 taken 458950 times.
✓ Branch 3 taken 10836 times.
676120 if (!desc->log2_chroma_w && !desc->log2_chroma_h)
342 458950 fmt->loc = AVCHROMA_LOC_UNSPECIFIED;
343 676120 }
344
345 /**
346 * This function also sanitizes and strips the input data, removing irrelevant
347 * fields for certain formats.
348 */
349 533542 SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field)
350 {
351 const AVColorPrimariesDesc *primaries;
352 AVFrameSideData *sd;
353
354 533542 enum AVPixelFormat format = frame->format;
355 533542 enum AVPixelFormat hw_format = AV_PIX_FMT_NONE;
356
357 #if CONFIG_UNSTABLE
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 533542 times.
533542 if (frame->hw_frames_ctx) {
359 AVHWFramesContext *hwfc = (AVHWFramesContext *)frame->hw_frames_ctx->data;
360 hw_format = frame->format;
361 format = hwfc->sw_format;
362 }
363 #endif
364
365 533542 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
366
367 533542 SwsFormat fmt = {
368 533542 .width = frame->width,
369 533542 .height = frame->height,
370 .format = format,
371 .hw_format = hw_format,
372 533542 .range = frame->color_range,
373 533542 .csp = frame->colorspace,
374 533542 .loc = frame->chroma_location,
375 .desc = desc,
376 .color = {
377 533542 .prim = frame->color_primaries,
378 533542 .trc = frame->color_trc,
379 },
380 };
381
382 av_assert1(fmt.width > 0);
383 av_assert1(fmt.height > 0);
384 av_assert1(fmt.format != AV_PIX_FMT_NONE);
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 533542 times.
533542 av_assert0(desc);
386 533542 sanitize_fmt(&fmt, desc);
387
388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 533542 times.
533542 if (frame->flags & AV_FRAME_FLAG_INTERLACED) {
389 fmt.height = (fmt.height + (field == FIELD_TOP)) >> 1;
390 fmt.interlaced = 1;
391 }
392
393 /* Set luminance and gamut information */
394 533542 fmt.color.min_luma = av_make_q(0, 1);
395
3/3
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 533468 times.
533542 switch (fmt.color.trc) {
396 16 case AVCOL_TRC_SMPTE2084:
397 16 fmt.color.max_luma = av_make_q(10000, 1); break;
398 58 case AVCOL_TRC_ARIB_STD_B67:
399 58 fmt.color.max_luma = av_make_q( 1000, 1); break; /* HLG reference display */
400 533468 default:
401 533468 fmt.color.max_luma = av_make_q( 203, 1); break; /* SDR reference brightness */
402 }
403
404 533542 primaries = av_csp_primaries_desc_from_id(fmt.color.prim);
405
2/2
✓ Branch 0 taken 3396 times.
✓ Branch 1 taken 530146 times.
533542 if (primaries)
406 3396 fmt.color.gamut = primaries->prim;
407
408
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 533538 times.
533542 if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA))) {
409 4 const AVMasteringDisplayMetadata *mdm = (const AVMasteringDisplayMetadata *) sd->data;
410
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (mdm->has_luminance) {
411 4 fmt.color.min_luma = mdm->min_luminance;
412 4 fmt.color.max_luma = mdm->max_luminance;
413 }
414
415
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (mdm->has_primaries) {
416 /* Ignore mastering display white point as it has no bearance on
417 * the underlying content */
418 4 fmt.color.gamut.r.x = mdm->display_primaries[0][0];
419 4 fmt.color.gamut.r.y = mdm->display_primaries[0][1];
420 4 fmt.color.gamut.g.x = mdm->display_primaries[1][0];
421 4 fmt.color.gamut.g.y = mdm->display_primaries[1][1];
422 4 fmt.color.gamut.b.x = mdm->display_primaries[2][0];
423 4 fmt.color.gamut.b.y = mdm->display_primaries[2][1];
424 }
425 }
426
427
2/2
✓ Branch 1 taken 533538 times.
✓ Branch 2 taken 4 times.
533542 if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS))) {
428 4 const AVDynamicHDRPlus *dhp = (const AVDynamicHDRPlus *) sd->data;
429 4 const AVHDRPlusColorTransformParams *pars = &dhp->params[0];
430 4 const AVRational nits = av_make_q(10000, 1);
431 4 AVRational maxrgb = pars->maxscl[0];
432
433
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)
434 goto skip_hdr10;
435
436 /* Maximum of MaxSCL components */
437
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (av_cmp_q(pars->maxscl[1], maxrgb) > 0)
438 maxrgb = pars->maxscl[1];
439
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (av_cmp_q(pars->maxscl[2], maxrgb) > 0)
440 maxrgb = pars->maxscl[2];
441
442
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (maxrgb.num > 0) {
443 /* Estimate true luminance from MaxSCL */
444 4 const AVLumaCoefficients *luma = av_csp_luma_coeffs_from_avcsp(fmt.csp);
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!luma)
446 goto skip_hdr10;
447 4 fmt.color.frame_peak = av_add_q(av_mul_q(luma->cr, pars->maxscl[0]),
448 av_add_q(av_mul_q(luma->cg, pars->maxscl[1]),
449 av_mul_q(luma->cb, pars->maxscl[2])));
450 /* Scale the scene average brightness by the ratio between the
451 * maximum luminance and the MaxRGB values */
452 4 fmt.color.frame_avg = av_mul_q(pars->average_maxrgb,
453 av_div_q(fmt.color.frame_peak, maxrgb));
454 } else {
455 /**
456 * Calculate largest value from histogram to use as fallback for
457 * clips with missing MaxSCL information. Note that this may end
458 * up picking the "reserved" value at the 5% percentile, which in
459 * practice appears to track the brightest pixel in the scene.
460 */
461 for (int i = 0; i < pars->num_distribution_maxrgb_percentiles; i++) {
462 const AVRational pct = pars->distribution_maxrgb[i].percentile;
463 if (av_cmp_q(pct, maxrgb) > 0)
464 maxrgb = pct;
465 fmt.color.frame_peak = maxrgb;
466 fmt.color.frame_avg = pars->average_maxrgb;
467 }
468 }
469
470 /* Rescale to nits */
471 4 fmt.color.frame_peak = av_mul_q(nits, fmt.color.frame_peak);
472 4 fmt.color.frame_avg = av_mul_q(nits, fmt.color.frame_avg);
473 }
474 533538 skip_hdr10:
475
476 /* PQ is always scaled down to absolute zero, so ignore mastering metadata */
477
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 533526 times.
533542 if (fmt.color.trc == AVCOL_TRC_SMPTE2084)
478 16 fmt.color.min_luma = av_make_q(0, 1);
479
480 533542 return fmt;
481 }
482
483 142578 void ff_fmt_from_pixfmt(enum AVPixelFormat pixfmt, SwsFormat *fmt)
484 {
485 142578 ff_fmt_clear(fmt);
486 142578 fmt->format = pixfmt;
487 142578 fmt->desc = av_pix_fmt_desc_get(pixfmt);
488 142578 sanitize_fmt(fmt, fmt->desc);
489 142578 }
490
491 223192 static int infer_prim_ref(SwsColor *csp, const SwsColor *ref)
492 {
493
2/2
✓ Branch 0 taken 2058 times.
✓ Branch 1 taken 221134 times.
223192 if (csp->prim != AVCOL_PRI_UNSPECIFIED)
494 2058 return 0;
495
496 /* Reuse the reference gamut only for "safe", similar primaries */
497
2/2
✓ Branch 0 taken 111476 times.
✓ Branch 1 taken 109658 times.
221134 switch (ref->prim) {
498 111476 case AVCOL_PRI_BT709:
499 case AVCOL_PRI_BT470M:
500 case AVCOL_PRI_BT470BG:
501 case AVCOL_PRI_SMPTE170M:
502 case AVCOL_PRI_SMPTE240M:
503 111476 csp->prim = ref->prim;
504 111476 csp->gamut = ref->gamut;
505 111476 break;
506 109658 default:
507 109658 csp->prim = AVCOL_PRI_BT709;
508 109658 csp->gamut = av_csp_primaries_desc_from_id(csp->prim)->prim;
509 109658 break;
510 }
511
512 221134 return 1;
513 }
514
515 223192 static int infer_trc_ref(SwsColor *csp, const SwsColor *ref)
516 {
517
2/2
✓ Branch 0 taken 2206 times.
✓ Branch 1 taken 220986 times.
223192 if (csp->trc != AVCOL_TRC_UNSPECIFIED)
518 2206 return 0;
519
520 /* Pick a suitable SDR transfer function, to try and minimize conversions */
521
2/2
✓ Branch 0 taken 109584 times.
✓ Branch 1 taken 111402 times.
220986 switch (ref->trc) {
522 109584 case AVCOL_TRC_UNSPECIFIED:
523 /* HDR curves, never default to these */
524 case AVCOL_TRC_SMPTE2084:
525 case AVCOL_TRC_ARIB_STD_B67:
526 109584 csp->trc = AVCOL_TRC_BT709;
527 109584 csp->min_luma = av_make_q(0, 1);
528 109584 csp->max_luma = av_make_q(203, 1);
529 109584 break;
530 111402 default:
531 111402 csp->trc = ref->trc;
532 111402 csp->min_luma = ref->min_luma;
533 111402 csp->max_luma = ref->max_luma;
534 111402 break;
535 }
536
537 220986 return 1;
538 }
539
540 111596 bool ff_infer_colors(SwsColor *src, SwsColor *dst)
541 {
542 111596 int incomplete = 0;
543
544 111596 incomplete |= infer_prim_ref(dst, src);
545 111596 incomplete |= infer_prim_ref(src, dst);
546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111596 times.
111596 av_assert0(src->prim != AVCOL_PRI_UNSPECIFIED);
547
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111596 times.
111596 av_assert0(dst->prim != AVCOL_PRI_UNSPECIFIED);
548
549 111596 incomplete |= infer_trc_ref(dst, src);
550 111596 incomplete |= infer_trc_ref(src, dst);
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111596 times.
111596 av_assert0(src->trc != AVCOL_TRC_UNSPECIFIED);
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111596 times.
111596 av_assert0(dst->trc != AVCOL_TRC_UNSPECIFIED);
553
554 111596 return incomplete;
555 }
556
557 3917654 int sws_test_format(enum AVPixelFormat format, int output)
558 {
559
2/2
✓ Branch 0 taken 1956993 times.
✓ Branch 1 taken 1960661 times.
3917654 return output ? sws_isSupportedOutput(format) : sws_isSupportedInput(format);
560 }
561
562 312684 int sws_test_hw_format(enum AVPixelFormat format)
563 {
564
1/2
✓ Branch 0 taken 312684 times.
✗ Branch 1 not taken.
312684 switch (format) {
565 312684 case AV_PIX_FMT_NONE: return 1;
566 #if CONFIG_VULKAN
567 case AV_PIX_FMT_VULKAN: return 1;
568 #endif
569 default: return 0;
570 }
571 }
572
573 550532 int sws_test_colorspace(enum AVColorSpace csp, int output)
574 {
575
2/2
✓ Branch 0 taken 430562 times.
✓ Branch 1 taken 119970 times.
550532 switch (csp) {
576 430562 case AVCOL_SPC_UNSPECIFIED:
577 case AVCOL_SPC_RGB:
578 case AVCOL_SPC_BT709:
579 case AVCOL_SPC_BT470BG:
580 case AVCOL_SPC_SMPTE170M:
581 case AVCOL_SPC_FCC:
582 case AVCOL_SPC_SMPTE240M:
583 case AVCOL_SPC_BT2020_NCL:
584 430562 return 1;
585 119970 default:
586 119970 return 0;
587 }
588 }
589
590 312684 int sws_test_primaries(enum AVColorPrimaries prim, int output)
591 {
592
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
312684 return ((prim > AVCOL_PRI_RESERVED0 && prim < AVCOL_PRI_NB) ||
593
2/6
✓ Branch 0 taken 312684 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 312684 times.
✗ Branch 5 not taken.
625368 (prim >= AVCOL_PRI_EXT_BASE && prim < AVCOL_PRI_EXT_NB)) &&
594 prim != AVCOL_PRI_RESERVED;
595 }
596
597 312684 int sws_test_transfer(enum AVColorTransferCharacteristic trc, int output)
598 {
599 156342 av_csp_eotf_function eotf = output ? av_csp_itu_eotf_inv(trc)
600
2/2
✓ Branch 0 taken 156342 times.
✓ Branch 1 taken 156342 times.
312684 : av_csp_itu_eotf(trc);
601
3/4
✓ Branch 0 taken 2495 times.
✓ Branch 1 taken 310189 times.
✓ Branch 2 taken 2495 times.
✗ Branch 3 not taken.
312684 return trc == AVCOL_TRC_UNSPECIFIED || eotf != NULL;
602 }
603
604 312684 static int test_range(enum AVColorRange range)
605 {
606 312684 return (unsigned)range < AVCOL_RANGE_NB;
607 }
608
609 312684 static int test_loc(enum AVChromaLocation loc)
610 {
611 312684 return (unsigned)loc < AVCHROMA_LOC_NB;
612 }
613
614 312684 int ff_test_fmt(const SwsFormat *fmt, int output)
615 {
616
2/4
✓ Branch 0 taken 312684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 312684 times.
✗ Branch 3 not taken.
625368 return fmt->width > 0 && fmt->height > 0 &&
617
1/2
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
625368 sws_test_format (fmt->format, output) &&
618
1/2
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
625368 sws_test_colorspace(fmt->csp, output) &&
619
1/2
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
625368 sws_test_primaries (fmt->color.prim, output) &&
620
1/2
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
625368 sws_test_transfer (fmt->color.trc, output) &&
621
1/2
✓ Branch 1 taken 312684 times.
✗ Branch 2 not taken.
625368 sws_test_hw_format (fmt->hw_format) &&
622
2/4
✓ Branch 0 taken 312684 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 312684 times.
✗ Branch 4 not taken.
938052 test_range (fmt->range) &&
623 312684 test_loc (fmt->loc);
624 }
625
626 int sws_test_frame(const AVFrame *frame, int output)
627 {
628 for (int field = 0; field < 2; field++) {
629 const SwsFormat fmt = ff_fmt_from_frame(frame, field);
630 if (!ff_test_fmt(&fmt, output))
631 return 0;
632 if (!fmt.interlaced)
633 break;
634 }
635
636 return 1;
637 }
638
639 110429 int sws_is_noop(const AVFrame *dst, const AVFrame *src)
640 {
641
1/2
✓ Branch 0 taken 110429 times.
✗ Branch 1 not taken.
110429 for (int field = 0; field < 2; field++) {
642 110429 SwsFormat dst_fmt = ff_fmt_from_frame(dst, field);
643 110429 SwsFormat src_fmt = ff_fmt_from_frame(src, field);
644
2/2
✓ Branch 1 taken 105511 times.
✓ Branch 2 taken 4918 times.
110429 if (!ff_fmt_equal(&dst_fmt, &src_fmt))
645 105511 return 0;
646
1/2
✓ Branch 0 taken 4918 times.
✗ Branch 1 not taken.
4918 if (!dst_fmt.interlaced)
647 4918 break;
648 }
649
650 4918 return 1;
651 }
652
653 279715 void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src)
654 {
655 279715 dst->format = src->format;
656 279715 dst->width = src->width;
657 279715 dst->height = src->height;
658 279715 dst->avframe = src;
659
2/2
✓ Branch 0 taken 1118860 times.
✓ Branch 1 taken 279715 times.
1398575 for (int i = 0; i < FF_ARRAY_ELEMS(dst->data); i++) {
660 1118860 dst->data[i] = src->data[i];
661 1118860 dst->linesize[i] = src->linesize[i];
662 }
663 279715 }
664
665 #if CONFIG_UNSTABLE
666
667 /* Returns the type suitable for a pixel after fully decoding/unpacking it */
668 198903 static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt)
669 {
670 198903 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
671 198903 const int bits = FFALIGN(desc->comp[0].depth, 8);
672
2/2
✓ Branch 0 taken 17340 times.
✓ Branch 1 taken 181563 times.
198903 if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
673
2/2
✓ Branch 0 taken 12552 times.
✓ Branch 1 taken 4788 times.
17340 switch (bits) {
674 12552 case 32: return SWS_PIXEL_F32;
675 /* TODO: no support for 16-bit float yet */
676 }
677 } else {
678
3/3
✓ Branch 0 taken 63139 times.
✓ Branch 1 taken 109916 times.
✓ Branch 2 taken 8508 times.
181563 switch (bits) {
679 63139 case 8: return SWS_PIXEL_U8;
680 109916 case 16: return SWS_PIXEL_U16;
681 /* TODO: AVRational cannot represent UINT32_MAX */
682 }
683 }
684
685 13296 return SWS_PIXEL_NONE;
686 }
687
688 /* A regular format is defined as any format that contains only a single
689 * component per elementary data type (i.e. no sub-byte pack/unpack needed),
690 * and whose components map 1:1 onto elementary data units */
691 88911 static int is_regular_fmt(enum AVPixelFormat fmt)
692 {
693 88911 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
694
2/2
✓ Branch 0 taken 5187 times.
✓ Branch 1 taken 83724 times.
88911 if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER))
695 5187 return 0; /* no 1:1 correspondence between components and data units */
696
2/2
✓ Branch 0 taken 2890 times.
✓ Branch 1 taken 80834 times.
83724 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM))
697 2890 return 0; /* bitstream formats are packed by definition */
698
4/4
✓ Branch 0 taken 46543 times.
✓ Branch 1 taken 34291 times.
✓ Branch 2 taken 8411 times.
✓ Branch 3 taken 38132 times.
80834 if ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) || desc->nb_components == 1)
699 42702 return 1; /* planar formats are regular by definition */
700
701 38132 const int step = desc->comp[0].step;
702 38132 int total_bits = 0;
703
704
2/2
✓ Branch 0 taken 95726 times.
✓ Branch 1 taken 21804 times.
117530 for (int i = 0; i < desc->nb_components; i++) {
705
3/4
✓ Branch 0 taken 79398 times.
✓ Branch 1 taken 16328 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 79398 times.
95726 if (desc->comp[i].shift || desc->comp[i].step != step)
706 16328 return 0; /* irregular/packed format */
707 79398 total_bits += desc->comp[i].depth;
708 }
709
710 /* Exclude formats with missing components like RGB0, 0RGB, etc. */
711 21804 return total_bits == step * 8;
712 }
713
714 typedef struct FmtInfo {
715 SwsReadWriteOp rw;
716 SwsSwizzleOp swizzle;
717 SwsPackOp pack;
718 int shift;
719 } FmtInfo;
720
721 #define BITSTREAM_FMT(SWIZ, FRAC, PACKED, ...) (FmtInfo) { \
722 .rw = { .elems = 1, .frac = FRAC, .packed = PACKED }, \
723 .swizzle = SWIZ, \
724 __VA_ARGS__ \
725 }
726
727 #define SUBPACKED_FMT(SWIZ, ...) (FmtInfo) { \
728 .rw = { .elems = 1, .packed = true }, \
729 .swizzle = SWIZ, \
730 .pack.pattern = {__VA_ARGS__}, \
731 }
732
733 #define PACKED_FMT(SWIZ, N, ...) (FmtInfo) { \
734 .rw = { .elems = N, .packed = (N) > 1 }, \
735 .swizzle = SWIZ, \
736 __VA_ARGS__ \
737 }
738
739 #define RGBA SWS_SWIZZLE(0, 1, 2, 3)
740 #define BGRA SWS_SWIZZLE(2, 1, 0, 3)
741 #define ARGB SWS_SWIZZLE(3, 0, 1, 2)
742 #define ABGR SWS_SWIZZLE(3, 2, 1, 0)
743 #define AVYU SWS_SWIZZLE(3, 2, 0, 1)
744 #define VYUA SWS_SWIZZLE(2, 0, 1, 3)
745 #define UYVA SWS_SWIZZLE(1, 0, 2, 3)
746 #define VUYA BGRA
747
748 28934 static FmtInfo fmt_info_irregular(enum AVPixelFormat fmt)
749 {
750
25/25
✓ Branch 0 taken 1294 times.
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 399 times.
✓ Branch 3 taken 647 times.
✓ Branch 4 taken 647 times.
✓ Branch 5 taken 647 times.
✓ Branch 6 taken 647 times.
✓ Branch 7 taken 1294 times.
✓ Branch 8 taken 1294 times.
✓ Branch 9 taken 1294 times.
✓ Branch 10 taken 1294 times.
✓ Branch 11 taken 1294 times.
✓ Branch 12 taken 1294 times.
✓ Branch 13 taken 1046 times.
✓ Branch 14 taken 1046 times.
✓ Branch 15 taken 1046 times.
✓ Branch 16 taken 1046 times.
✓ Branch 17 taken 647 times.
✓ Branch 18 taken 647 times.
✓ Branch 19 taken 647 times.
✓ Branch 20 taken 647 times.
✓ Branch 21 taken 647 times.
✓ Branch 22 taken 1294 times.
✓ Branch 23 taken 1294 times.
✓ Branch 24 taken 6483 times.
28934 switch (fmt) {
751 /* Bitstream formats */
752 1294 case AV_PIX_FMT_MONOWHITE:
753 case AV_PIX_FMT_MONOBLACK:
754 1294 return BITSTREAM_FMT(RGBA, 3, false);
755 399 case AV_PIX_FMT_RGB4: return BITSTREAM_FMT(RGBA, 1, true, .pack = {{ 1, 2, 1 }});
756 399 case AV_PIX_FMT_BGR4: return BITSTREAM_FMT(BGRA, 1, true, .pack = {{ 1, 2, 1 }});
757
758 /* Sub-packed 8-bit aligned formats */
759 647 case AV_PIX_FMT_RGB4_BYTE: return SUBPACKED_FMT(RGBA, 1, 2, 1);
760 647 case AV_PIX_FMT_BGR4_BYTE: return SUBPACKED_FMT(BGRA, 1, 2, 1);
761 647 case AV_PIX_FMT_RGB8: return SUBPACKED_FMT(RGBA, 3, 3, 2);
762 647 case AV_PIX_FMT_BGR8: return SUBPACKED_FMT(BGRA, 2, 3, 3);
763
764 /* Sub-packed 16-bit aligned formats */
765 1294 case AV_PIX_FMT_RGB565LE:
766 case AV_PIX_FMT_RGB565BE:
767 1294 return SUBPACKED_FMT(RGBA, 5, 6, 5);
768 1294 case AV_PIX_FMT_BGR565LE:
769 case AV_PIX_FMT_BGR565BE:
770 1294 return SUBPACKED_FMT(BGRA, 5, 6, 5);
771 1294 case AV_PIX_FMT_RGB555LE:
772 case AV_PIX_FMT_RGB555BE:
773 1294 return SUBPACKED_FMT(RGBA, 5, 5, 5);
774 1294 case AV_PIX_FMT_BGR555LE:
775 case AV_PIX_FMT_BGR555BE:
776 1294 return SUBPACKED_FMT(BGRA, 5, 5, 5);
777 1294 case AV_PIX_FMT_RGB444LE:
778 case AV_PIX_FMT_RGB444BE:
779 1294 return SUBPACKED_FMT(RGBA, 4, 4, 4);
780 1294 case AV_PIX_FMT_BGR444LE:
781 case AV_PIX_FMT_BGR444BE:
782 1294 return SUBPACKED_FMT(BGRA, 4, 4, 4);
783
784 /* Sub-packed 32-bit aligned formats */
785 1046 case AV_PIX_FMT_X2RGB10LE:
786 case AV_PIX_FMT_X2RGB10BE:
787 1046 return SUBPACKED_FMT(ARGB, 2, 10, 10, 10);
788 1046 case AV_PIX_FMT_X2BGR10LE:
789 case AV_PIX_FMT_X2BGR10BE:
790 1046 return SUBPACKED_FMT(ABGR, 2, 10, 10, 10);
791 1046 case AV_PIX_FMT_XV30LE:
792 case AV_PIX_FMT_XV30BE:
793 1046 return SUBPACKED_FMT(AVYU, 2, 10, 10, 10);
794 1046 case AV_PIX_FMT_V30XLE:
795 case AV_PIX_FMT_V30XBE:
796 1046 return SUBPACKED_FMT(VYUA, 10, 10, 10, 2);
797
798 /* 3-component formats with extra padding */
799 647 case AV_PIX_FMT_RGB0: return PACKED_FMT(RGBA, 4);
800 647 case AV_PIX_FMT_BGR0: return PACKED_FMT(BGRA, 4);
801 647 case AV_PIX_FMT_0RGB: return PACKED_FMT(ARGB, 4);
802 647 case AV_PIX_FMT_0BGR: return PACKED_FMT(ABGR, 4);
803 647 case AV_PIX_FMT_VUYX: return PACKED_FMT(VUYA, 4);
804 1294 case AV_PIX_FMT_XV36LE:
805 case AV_PIX_FMT_XV36BE:
806 1294 return PACKED_FMT(UYVA, 4, .shift = 4);
807 1294 case AV_PIX_FMT_XV48LE:
808 case AV_PIX_FMT_XV48BE:
809 1294 return PACKED_FMT(UYVA, 4);
810 }
811
812 6483 return (FmtInfo) {0};
813 }
814
815 struct comp {
816 int index;
817 int plane;
818 int offset;
819 };
820
821 /* Compare by (plane, offset) */
822 167832 static int cmp_comp(const void *a, const void *b) {
823 167832 const struct comp *ca = a;
824 167832 const struct comp *cb = b;
825
2/2
✓ Branch 0 taken 112578 times.
✓ Branch 1 taken 55254 times.
167832 if (ca->plane != cb->plane)
826 112578 return ca->plane - cb->plane;
827 55254 return ca->offset - cb->offset;
828 }
829
830 59977 static int fmt_analyze_regular(const AVPixFmtDescriptor *desc, SwsReadWriteOp *rw_op,
831 SwsSwizzleOp *swizzle, SwsShiftOp *shift)
832 {
833
2/2
✓ Branch 0 taken 2739 times.
✓ Branch 1 taken 57238 times.
59977 if (desc->nb_components == 2) {
834 /* YA formats */
835 2739 *swizzle = SWS_SWIZZLE(0, 3, 1, 2);
836 } else {
837 /* Sort by increasing component order */
838 57238 struct comp sorted[4] = { {0}, {1}, {2}, {3} };
839
2/2
✓ Branch 0 taken 177041 times.
✓ Branch 1 taken 57238 times.
234279 for (int i = 0; i < desc->nb_components; i++) {
840 177041 sorted[i].plane = desc->comp[i].plane;
841 177041 sorted[i].offset = desc->comp[i].offset;
842 }
843
844 57238 qsort(sorted, desc->nb_components, sizeof(struct comp), cmp_comp);
845
846 57238 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
847
2/2
✓ Branch 0 taken 177041 times.
✓ Branch 1 taken 57238 times.
234279 for (int i = 0; i < desc->nb_components; i++)
848 177041 swiz.in[i] = sorted[i].index;
849 57238 *swizzle = swiz;
850 }
851
852 59977 *shift = (SwsShiftOp) { desc->comp[0].shift };
853 59977 *rw_op = (SwsReadWriteOp) {
854 59977 .elems = desc->nb_components,
855
4/4
✓ Branch 0 taken 51566 times.
✓ Branch 1 taken 8411 times.
✓ Branch 2 taken 17275 times.
✓ Branch 3 taken 34291 times.
59977 .packed = desc->nb_components > 1 && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR),
856 };
857 59977 return 0;
858 }
859
860 134031 static int fmt_analyze(enum AVPixelFormat fmt, SwsReadWriteOp *rw_op,
861 SwsPackOp *pack_op, SwsSwizzleOp *swizzle,
862 SwsShiftOp *shift, SwsPixelType *pixel_type,
863 SwsPixelType *raw_type)
864 {
865 134031 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134031 times.
134031 if (!desc)
867 return AVERROR(EINVAL);
868
869 /* No support for subsampled formats at the moment */
870
4/4
✓ Branch 0 taken 105033 times.
✓ Branch 1 taken 28998 times.
✓ Branch 2 taken 2394 times.
✓ Branch 3 taken 102639 times.
134031 if (desc->log2_chroma_w || desc->log2_chroma_h)
871 31392 return AVERROR(ENOTSUP);
872
873 /* No support for semi-planar formats at the moment */
874
2/2
✓ Branch 0 taken 41077 times.
✓ Branch 1 taken 61562 times.
102639 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR &&
875
2/2
✓ Branch 1 taken 5184 times.
✓ Branch 2 taken 35893 times.
41077 av_pix_fmt_count_planes(fmt) < desc->nb_components)
876 5184 return AVERROR(ENOTSUP);
877
878 97455 *pixel_type = *raw_type = fmt_pixel_type(fmt);
879
2/2
✓ Branch 0 taken 8544 times.
✓ Branch 1 taken 88911 times.
97455 if (!*pixel_type)
880 8544 return AVERROR(ENOTSUP);
881
882
2/2
✓ Branch 1 taken 59977 times.
✓ Branch 2 taken 28934 times.
88911 if (is_regular_fmt(fmt)) {
883 59977 *pack_op = (SwsPackOp) {0};
884 59977 return fmt_analyze_regular(desc, rw_op, swizzle, shift);
885 }
886
887 28934 FmtInfo info = fmt_info_irregular(fmt);
888
2/2
✓ Branch 0 taken 6483 times.
✓ Branch 1 taken 22451 times.
28934 if (!info.rw.elems)
889 6483 return AVERROR(ENOTSUP);
890
891 22451 *rw_op = info.rw;
892 22451 *pack_op = info.pack;
893 22451 *swizzle = info.swizzle;
894 22451 *shift = (SwsShiftOp) { info.shift };
895
896
2/2
✓ Branch 0 taken 15334 times.
✓ Branch 1 taken 7117 times.
22451 if (info.pack.pattern[0]) {
897 15334 const int sum = info.pack.pattern[0] + info.pack.pattern[1] +
898 15334 info.pack.pattern[2] + info.pack.pattern[3];
899
2/2
✓ Branch 0 taken 4184 times.
✓ Branch 1 taken 11150 times.
15334 if (sum > 16)
900 4184 *raw_type = SWS_PIXEL_U32;
901
2/2
✓ Branch 0 taken 7764 times.
✓ Branch 1 taken 3386 times.
11150 else if (sum > 8)
902 7764 *raw_type = SWS_PIXEL_U16;
903 else
904 3386 *raw_type = SWS_PIXEL_U8;
905 }
906
907 22451 return 0;
908 }
909
910 50724 static SwsSwizzleOp swizzle_inv(SwsSwizzleOp swiz) {
911 /* Input[x] =: Output[swizzle.x] */
912 unsigned out[4];
913 50724 out[swiz.x] = 0;
914 50724 out[swiz.y] = 1;
915 50724 out[swiz.z] = 2;
916 50724 out[swiz.w] = 3;
917 50724 return (SwsSwizzleOp) {{ .x = out[0], out[1], out[2], out[3] }};
918 }
919
920 /**
921 * This initializes all absent components explicitly to zero. There is no
922 * need to worry about the correct neutral value as fmt_decode() will
923 * implicitly ignore and overwrite absent components in any case. This function
924 * is just to ensure that we don't operate on undefined memory. In most cases,
925 * it will end up getting pushed towards the output or optimized away entirely
926 * by the optimization pass.
927 */
928 50724 static SwsClearOp fmt_clear(enum AVPixelFormat fmt)
929 {
930 50724 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
931 50724 const bool has_chroma = desc->nb_components >= 3;
932 50724 const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
933
934 50724 SwsClearOp c = {0};
935
2/2
✓ Branch 0 taken 7662 times.
✓ Branch 1 taken 43062 times.
50724 if (!has_chroma) {
936 7662 c.mask |= SWS_COMP(1) | SWS_COMP(2);
937 7662 c.value[1] = c.value[2] = Q0;
938 }
939
940
2/2
✓ Branch 0 taken 35400 times.
✓ Branch 1 taken 15324 times.
50724 if (!has_alpha) {
941 35400 c.mask |= SWS_COMP(3);
942 35400 c.value[3] = Q0;
943 }
944
945 50724 return c;
946 }
947
948 #if HAVE_BIGENDIAN
949 # define NATIVE_ENDIAN_FLAG AV_PIX_FMT_FLAG_BE
950 #else
951 # define NATIVE_ENDIAN_FLAG 0
952 #endif
953
954 88059 int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
955 {
956 88059 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
957 SwsPixelType pixel_type, raw_type;
958 SwsReadWriteOp rw_op;
959 SwsSwizzleOp swizzle;
960 SwsPackOp unpack;
961 88059 SwsComps *comps = &ops->comps_src;
962 SwsShiftOp shift;
963
964
2/2
✓ Branch 1 taken 37335 times.
✓ Branch 2 taken 50724 times.
88059 RET(fmt_analyze(fmt, &rw_op, &unpack, &swizzle, &shift,
965 &pixel_type, &raw_type));
966
967 50724 swizzle = swizzle_inv(swizzle);
968
969 /* Set baseline pixel content flags */
970 50724 const int integer = ff_sws_pixel_type_is_int(raw_type);
971
2/2
✓ Branch 0 taken 39102 times.
✓ Branch 1 taken 11622 times.
89826 const int swapped = ff_sws_pixel_type_size(raw_type) > 1 &&
972
2/2
✓ Branch 0 taken 19293 times.
✓ Branch 1 taken 19809 times.
39102 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG;
973
2/2
✓ Branch 0 taken 136692 times.
✓ Branch 1 taken 50724 times.
187416 for (int i = 0; i < rw_op.elems; i++) {
974
2/2
✓ Branch 0 taken 125550 times.
✓ Branch 1 taken 11142 times.
273384 comps->flags[i] = (integer ? SWS_COMP_EXACT : 0) |
975
2/2
✓ Branch 0 taken 51387 times.
✓ Branch 1 taken 85305 times.
136692 (swapped ? SWS_COMP_SWAPPED : 0);
976 }
977
978 /* Generate value range information for simple unpacked formats */
979
4/4
✓ Branch 0 taken 46746 times.
✓ Branch 1 taken 3978 times.
✓ Branch 2 taken 37224 times.
✓ Branch 3 taken 9522 times.
50724 if (integer && !unpack.pattern[0]) {
980 /* YA formats have desc->comp[] in the order {Y, A} instead of the
981 * canonical order {Y, U, V, A} */
982 37224 const int is_ya = desc->nb_components == 2;
983
2/2
✓ Branch 0 taken 112464 times.
✓ Branch 1 taken 37224 times.
149688 for (int c = 0; c < desc->nb_components; c++) {
984 112464 const int bits = desc->comp[c].depth + shift.amount;
985
2/2
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 110088 times.
112464 const int idx = swizzle.in[is_ya ? 3 * c : c];
986 112464 comps->min[idx] = Q0;
987
1/2
✓ Branch 0 taken 112464 times.
✗ Branch 1 not taken.
112464 if (bits < 32) /* FIXME: AVRational is limited to INT_MAX */
988 112464 comps->max[idx] = Q((1ULL << bits) - 1);
989 }
990 }
991
992 /* TODO: handle subsampled or semipacked input formats */
993
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 50724 times.
50724 RET(ff_sws_op_list_append(ops, &(SwsOp) {
994 .op = SWS_OP_READ,
995 .type = raw_type,
996 .rw = rw_op,
997 }));
998
999
2/2
✓ Branch 0 taken 19293 times.
✓ Branch 1 taken 31431 times.
50724 if (swapped) {
1000
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19293 times.
19293 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1001 .op = SWS_OP_SWAP_BYTES,
1002 .type = raw_type,
1003 }));
1004 }
1005
1006
2/2
✓ Branch 0 taken 9522 times.
✓ Branch 1 taken 41202 times.
50724 if (unpack.pattern[0]) {
1007
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9522 times.
9522 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1008 .op = SWS_OP_UNPACK,
1009 .type = raw_type,
1010 .pack = unpack,
1011 }));
1012
1013
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9522 times.
9522 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1014 .op = SWS_OP_CONVERT,
1015 .type = raw_type,
1016 .convert.to = pixel_type,
1017 }));
1018 }
1019
1020
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 50724 times.
50724 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1021 .op = SWS_OP_SWIZZLE,
1022 .type = pixel_type,
1023 .swizzle = swizzle,
1024 }));
1025
1026
2/2
✓ Branch 0 taken 3960 times.
✓ Branch 1 taken 46764 times.
50724 if (shift.amount) {
1027
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3960 times.
3960 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1028 .op = SWS_OP_RSHIFT,
1029 .type = pixel_type,
1030 .shift = shift,
1031 }));
1032 }
1033
1034
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 50724 times.
50724 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1035 .op = SWS_OP_CLEAR,
1036 .type = pixel_type,
1037 .clear = fmt_clear(fmt),
1038 }));
1039
1040 50724 return 0;
1041 }
1042
1043 45972 int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
1044 {
1045 45972 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
1046 SwsPixelType pixel_type, raw_type;
1047 SwsReadWriteOp rw_op;
1048 SwsSwizzleOp swizzle;
1049 SwsPackOp pack;
1050 SwsShiftOp shift;
1051
1052
2/2
✓ Branch 1 taken 14268 times.
✓ Branch 2 taken 31704 times.
45972 RET(fmt_analyze(fmt, &rw_op, &pack, &swizzle, &shift,
1053 &pixel_type, &raw_type));
1054
1055
2/2
✓ Branch 0 taken 2510 times.
✓ Branch 1 taken 29194 times.
31704 if (shift.amount) {
1056
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2510 times.
2510 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1057 .op = SWS_OP_LSHIFT,
1058 .type = pixel_type,
1059 .shift = shift,
1060 }));
1061 }
1062
1063
2/2
✓ Branch 0 taken 2259 times.
✓ Branch 1 taken 29445 times.
31704 if (rw_op.elems > desc->nb_components) {
1064 /* Format writes unused alpha channel, clear it explicitly for sanity */
1065 av_assert1(!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
1066
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2259 times.
2259 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1067 .op = SWS_OP_CLEAR,
1068 .type = pixel_type,
1069 .clear.mask = SWS_COMP(3),
1070 .clear.value[3] = Q0,
1071 }));
1072 }
1073
1074
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31704 times.
31704 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1075 .op = SWS_OP_SWIZZLE,
1076 .type = pixel_type,
1077 .swizzle = swizzle,
1078 }));
1079
1080
2/2
✓ Branch 0 taken 5812 times.
✓ Branch 1 taken 25892 times.
31704 if (pack.pattern[0]) {
1081
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5812 times.
5812 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1082 .op = SWS_OP_CONVERT,
1083 .type = pixel_type,
1084 .convert.to = raw_type,
1085 }));
1086
1087
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5812 times.
5812 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1088 .op = SWS_OP_PACK,
1089 .type = raw_type,
1090 .pack = pack,
1091 }));
1092 }
1093
1094
2/2
✓ Branch 0 taken 24412 times.
✓ Branch 1 taken 7292 times.
31704 if (ff_sws_pixel_type_size(raw_type) > 1 &&
1095
2/2
✓ Branch 0 taken 11968 times.
✓ Branch 1 taken 12444 times.
24412 (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG) {
1096
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11968 times.
11968 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1097 .op = SWS_OP_SWAP_BYTES,
1098 .type = raw_type,
1099 }));
1100 }
1101
1102
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31704 times.
31704 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1103 .op = SWS_OP_WRITE,
1104 .type = raw_type,
1105 .rw = rw_op,
1106 }));
1107
1108 31704 return 0;
1109 }
1110
1111 203543 static inline AVRational av_neg_q(AVRational x)
1112 {
1113 203543 return (AVRational) { -x.num, x.den };
1114 }
1115
1116 96696 static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete)
1117 {
1118 96696 SwsLinearOp c = { .m = {
1119 { Q1, Q0, Q0, Q0, Q0 },
1120 { Q0, Q1, Q0, Q0, Q0 },
1121 { Q0, Q0, Q1, Q0, Q0 },
1122 { Q0, Q0, Q0, Q1, Q0 },
1123 }};
1124
1125 96696 const int depth0 = fmt->desc->comp[0].depth;
1126 96696 const int depth1 = fmt->desc->comp[1].depth;
1127 96696 const int depth2 = fmt->desc->comp[2].depth;
1128 96696 const int depth3 = fmt->desc->comp[3].depth;
1129
1130
2/2
✓ Branch 0 taken 6276 times.
✓ Branch 1 taken 90420 times.
96696 if (fmt->desc->flags & AV_PIX_FMT_FLAG_FLOAT)
1131 6276 return c; /* floats are directly output as-is */
1132
1133
4/8
✓ Branch 0 taken 90420 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90420 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90420 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 90420 times.
90420 av_assert0(depth0 < 32 && depth1 < 32 && depth2 < 32 && depth3 < 32);
1134
4/4
✓ Branch 0 taken 48288 times.
✓ Branch 1 taken 42132 times.
✓ Branch 2 taken 504 times.
✓ Branch 3 taken 47784 times.
90420 if (fmt->csp == AVCOL_SPC_RGB || (fmt->desc->flags & AV_PIX_FMT_FLAG_XYZ)) {
1135 42636 c.m[0][0] = Q((1 << depth0) - 1);
1136 42636 c.m[1][1] = Q((1 << depth1) - 1);
1137 42636 c.m[2][2] = Q((1 << depth2) - 1);
1138
2/2
✓ Branch 0 taken 11527 times.
✓ Branch 1 taken 36257 times.
47784 } else if (fmt->range == AVCOL_RANGE_JPEG) {
1139 /* Full range YUV */
1140 11527 c.m[0][0] = Q((1 << depth0) - 1);
1141
2/2
✓ Branch 0 taken 1175 times.
✓ Branch 1 taken 10352 times.
11527 if (fmt->desc->nb_components >= 3) {
1142 /* This follows the ITU-R convention, which is slightly different
1143 * from the JFIF convention. */
1144 1175 c.m[1][1] = Q((1 << depth1) - 1);
1145 1175 c.m[2][2] = Q((1 << depth2) - 1);
1146 1175 c.m[1][4] = Q(1 << (depth1 - 1));
1147 1175 c.m[2][4] = Q(1 << (depth2 - 1));
1148 }
1149 } else {
1150 /* Limited range YUV */
1151
1/2
✓ Branch 0 taken 36257 times.
✗ Branch 1 not taken.
36257 if (fmt->range == AVCOL_RANGE_UNSPECIFIED)
1152 36257 *incomplete = true;
1153 36257 c.m[0][0] = Q(219 << (depth0 - 8));
1154 36257 c.m[0][4] = Q( 16 << (depth0 - 8));
1155
1/2
✓ Branch 0 taken 36257 times.
✗ Branch 1 not taken.
36257 if (fmt->desc->nb_components >= 3) {
1156 36257 c.m[1][1] = Q(224 << (depth1 - 8));
1157 36257 c.m[2][2] = Q(224 << (depth2 - 8));
1158 36257 c.m[1][4] = Q(128 << (depth1 - 8));
1159 36257 c.m[2][4] = Q(128 << (depth2 - 8));
1160 }
1161 }
1162
1163
2/2
✓ Branch 0 taken 24242 times.
✓ Branch 1 taken 66178 times.
90420 if (fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA) {
1164 24242 const bool is_ya = fmt->desc->nb_components == 2;
1165
2/2
✓ Branch 0 taken 1941 times.
✓ Branch 1 taken 22301 times.
24242 c.m[3][3] = Q((1 << (is_ya ? depth1 : depth3)) - 1);
1166 }
1167
1168
2/2
✓ Branch 0 taken 647 times.
✓ Branch 1 taken 89773 times.
90420 if (fmt->format == AV_PIX_FMT_MONOWHITE) {
1169 /* This format is inverted, 0 = white, 1 = black */
1170 647 c.m[0][4] = av_add_q(c.m[0][4], c.m[0][0]);
1171 647 c.m[0][0] = av_neg_q(c.m[0][0]);
1172 }
1173
1174 90420 c.mask = ff_sws_linear_mask(c);
1175 90420 return c;
1176 }
1177
1178 50724 static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete)
1179 {
1180 50724 SwsLinearOp c = fmt_encode_range(fmt, incomplete);
1181
1182 /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */
1183
2/2
✓ Branch 0 taken 202896 times.
✓ Branch 1 taken 50724 times.
253620 for (int i = 0; i < 4; i++) {
1184 av_assert1(c.m[i][i].num);
1185 202896 c.m[i][i] = av_inv_q(c.m[i][i]);
1186 202896 c.m[i][4] = av_mul_q(c.m[i][4], av_neg_q(c.m[i][i]));
1187 }
1188
1189 /* Explicitly initialize alpha for sanity */
1190
2/2
✓ Branch 0 taken 35400 times.
✓ Branch 1 taken 15324 times.
50724 if (!(fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA))
1191 35400 c.m[3][4] = Q1;
1192
1193 50724 c.mask = ff_sws_linear_mask(c);
1194 50724 return c;
1195 }
1196
1197 25890 static AVRational *generate_bayer_matrix(const int size_log2)
1198 {
1199 25890 const int size = 1 << size_log2;
1200 25890 const int num_entries = size * size;
1201 25890 AVRational *m = av_refstruct_allocz(sizeof(*m) * num_entries);
1202 av_assert1(size_log2 < 16);
1203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25890 times.
25890 if (!m)
1204 return NULL;
1205
1206 /* Start with a 1x1 matrix */
1207 25890 m[0] = Q0;
1208
1209 /* Generate three copies of the current, appropriately scaled and offset */
1210
2/2
✓ Branch 0 taken 103560 times.
✓ Branch 1 taken 25890 times.
129450 for (int sz = 1; sz < size; sz <<= 1) {
1211 103560 const int den = 4 * sz * sz;
1212
2/2
✓ Branch 0 taken 388350 times.
✓ Branch 1 taken 103560 times.
491910 for (int y = 0; y < sz; y++) {
1213
2/2
✓ Branch 0 taken 2200650 times.
✓ Branch 1 taken 388350 times.
2589000 for (int x = 0; x < sz; x++) {
1214 2200650 const AVRational cur = m[y * size + x];
1215 2200650 m[(y + sz) * size + x + sz] = av_add_q(cur, av_make_q(1, den));
1216 2200650 m[(y ) * size + x + sz] = av_add_q(cur, av_make_q(2, den));
1217 2200650 m[(y + sz) * size + x ] = av_add_q(cur, av_make_q(3, den));
1218 }
1219 }
1220 }
1221
1222 /**
1223 * To correctly round, we need to evenly distribute the result on [0, 1),
1224 * giving an average value of 1/2.
1225 *
1226 * After the above construction, we have a matrix with average value:
1227 * [ 0/N + 1/N + 2/N + ... (N-1)/N ] / N = (N-1)/(2N)
1228 * where N = size * size is the total number of entries.
1229 *
1230 * To make the average value equal to 1/2 = N/(2N), add a bias of 1/(2N).
1231 */
1232
2/2
✓ Branch 0 taken 6627840 times.
✓ Branch 1 taken 25890 times.
6653730 for (int i = 0; i < num_entries; i++)
1233 6627840 m[i] = av_add_q(m[i], av_make_q(1, 2 * num_entries));
1234
1235 25890 return m;
1236 }
1237
1238 43674 static bool trc_is_hdr(enum AVColorTransferCharacteristic trc)
1239 {
1240 static_assert(AVCOL_TRC_NB == 19, "Update this list when adding TRCs");
1241 static_assert(AVCOL_TRC_EXT_NB == 257, "Update this list when adding TRCs");
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43674 times.
43674 switch (trc) {
1243 case AVCOL_TRC_LOG:
1244 case AVCOL_TRC_LOG_SQRT:
1245 case AVCOL_TRC_V_LOG:
1246 case AVCOL_TRC_SMPTEST2084:
1247 case AVCOL_TRC_ARIB_STD_B67:
1248 return true;
1249 43674 default:
1250 43674 return false;
1251 }
1252 }
1253
1254 43674 static int fmt_dither(SwsContext *ctx, SwsOpList *ops,
1255 const SwsPixelType type,
1256 const SwsFormat *src, const SwsFormat *dst)
1257 {
1258 43674 SwsDither mode = ctx->dither;
1259 SwsDitherOp dither;
1260 43674 const int bpc = dst->desc->comp[0].depth;
1261
1262
1/2
✓ Branch 0 taken 43674 times.
✗ Branch 1 not taken.
43674 if (mode == SWS_DITHER_AUTO) {
1263 /* Visual threshold of perception: 12 bits for SDR, 14 bits for HDR */
1264
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43674 times.
43674 const int jnd_bits = trc_is_hdr(dst->color.trc) ? 14 : 12;
1265
2/2
✓ Branch 0 taken 17784 times.
✓ Branch 1 taken 25890 times.
43674 mode = bpc >= jnd_bits ? SWS_DITHER_NONE : SWS_DITHER_BAYER;
1266 }
1267
1268
2/5
✓ Branch 0 taken 17784 times.
✓ Branch 1 taken 25890 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
43674 switch (mode) {
1269 17784 case SWS_DITHER_NONE:
1270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17784 times.
17784 if (ctx->flags & SWS_ACCURATE_RND) {
1271 /* Add constant 0.5 for correct rounding */
1272 AVRational *bias = av_refstruct_allocz(sizeof(*bias));
1273 if (!bias)
1274 return AVERROR(ENOMEM);
1275 *bias = (AVRational) {1, 2};
1276 return ff_sws_op_list_append(ops, &(SwsOp) {
1277 .op = SWS_OP_DITHER,
1278 .type = type,
1279 .dither.matrix = bias,
1280 .dither.min = *bias,
1281 .dither.max = *bias,
1282 });
1283 } else {
1284 17784 return 0; /* No-op */
1285 }
1286 25890 case SWS_DITHER_BAYER:
1287 /* Hardcode 16x16 matrix for now; in theory we could adjust this
1288 * based on the expected level of precision in the output, since lower
1289 * bit depth outputs can suffice with smaller dither matrices; however
1290 * in practice we probably want to use error diffusion for such low bit
1291 * depths anyway */
1292 25890 dither.size_log2 = 4;
1293 25890 dither.matrix = generate_bayer_matrix(dither.size_log2);
1294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25890 times.
25890 if (!dither.matrix)
1295 return AVERROR(ENOMEM);
1296
1297 25890 const int size = 1 << dither.size_log2;
1298 25890 dither.min = dither.max = dither.matrix[0];
1299
2/2
✓ Branch 0 taken 6601950 times.
✓ Branch 1 taken 25890 times.
6627840 for (int i = 1; i < size * size; i++) {
1300
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6601950 times.
6601950 if (av_cmp_q(dither.min, dither.matrix[i]) > 0)
1301 dither.min = dither.matrix[i];
1302
2/2
✓ Branch 1 taken 362460 times.
✓ Branch 2 taken 6239490 times.
6601950 if (av_cmp_q(dither.matrix[i], dither.max) > 0)
1303 362460 dither.max = dither.matrix[i];
1304 }
1305
1306 /* Brute-forced offsets; minimizes quantization error across a 16x16
1307 * bayer dither pattern for standard RGBA and YUVA pixel formats */
1308 25890 const int offsets_16x16[4] = {0, 3, 2, 5};
1309
2/2
✓ Branch 0 taken 103560 times.
✓ Branch 1 taken 25890 times.
129450 for (int i = 0; i < 4; i++) {
1310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103560 times.
103560 av_assert0(offsets_16x16[i] <= INT8_MAX);
1311 103560 dither.y_offset[i] = offsets_16x16[i];
1312 }
1313
1314
4/4
✓ Branch 0 taken 3912 times.
✓ Branch 1 taken 21978 times.
✓ Branch 2 taken 2950 times.
✓ Branch 3 taken 962 times.
25890 if (src->desc->nb_components < 3 && bpc >= 8) {
1315 /**
1316 * For high-bit-depth sources without chroma, use same matrix
1317 * offset for all color channels. This prevents introducing color
1318 * noise in grayscale images; and also allows optimizing the dither
1319 * operation. Skipped for low bit depth (<8 bpc) as the loss in
1320 * PSNR, from the inability to diffuse error among all three
1321 * channels, can be substantial.
1322 *
1323 * This shifts: { X, Y, Z, W } -> { X, X, X, Y }
1324 */
1325 2950 dither.y_offset[3] = dither.y_offset[1];
1326 2950 dither.y_offset[1] = dither.y_offset[2] = dither.y_offset[0];
1327 }
1328
1329 25890 return ff_sws_op_list_append(ops, &(SwsOp) {
1330 .op = SWS_OP_DITHER,
1331 .type = type,
1332 .dither = dither,
1333 });
1334 case SWS_DITHER_ED:
1335 case SWS_DITHER_A_DITHER:
1336 case SWS_DITHER_X_DITHER:
1337 return AVERROR(ENOTSUP);
1338
1339 case SWS_DITHER_NB:
1340 break;
1341 }
1342
1343 av_unreachable("Invalid dither mode");
1344 return AVERROR(EINVAL);
1345 }
1346
1347 static inline SwsLinearOp
1348 50380 linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02,
1349 const AVRational m10, const AVRational m11, const AVRational m12,
1350 const AVRational m20, const AVRational m21, const AVRational m22)
1351 {
1352 50380 SwsLinearOp c = {{
1353 { m00, m01, m02, Q0, Q0 },
1354 { m10, m11, m12, Q0, Q0 },
1355 { m20, m21, m22, Q0, Q0 },
1356 { Q0, Q0, Q0, Q1, Q0 },
1357 }};
1358
1359 50380 c.mask = ff_sws_linear_mask(c);
1360 50380 return c;
1361 }
1362
1363 50724 int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type,
1364 SwsOpList *ops, const SwsFormat *fmt, bool *incomplete)
1365 {
1366 50724 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(fmt->csp);
1367 50724 const SwsPixelType pixel_type = fmt_pixel_type(fmt->format);
1368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50724 times.
50724 if (!pixel_type)
1369 return AVERROR(ENOTSUP);
1370
1371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 50724 times.
50724 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1372 .op = SWS_OP_CONVERT,
1373 .type = pixel_type,
1374 .convert.to = type,
1375 }));
1376
1377 /* Decode pixel format into standardized range */
1378
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 50724 times.
50724 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1379 .type = type,
1380 .op = SWS_OP_LINEAR,
1381 .lin = fmt_decode_range(fmt, incomplete),
1382 }));
1383
1384 /* Final step, decode colorspace */
1385
2/8
✓ Branch 0 taken 27480 times.
✓ Branch 1 taken 23244 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.
50724 switch (fmt->csp) {
1386 27480 case AVCOL_SPC_RGB:
1387 50724 return 0;
1388 23244 case AVCOL_SPC_UNSPECIFIED:
1389 23244 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1390 23244 *incomplete = true;
1391 av_fallthrough;
1392 23244 case AVCOL_SPC_FCC:
1393 case AVCOL_SPC_BT470BG:
1394 case AVCOL_SPC_SMPTE170M:
1395 case AVCOL_SPC_BT709:
1396 case AVCOL_SPC_SMPTE240M:
1397 case AVCOL_SPC_BT2020_NCL: {
1398 23244 AVRational crg = av_sub_q(Q0, av_div_q(c->cr, c->cg));
1399 23244 AVRational cbg = av_sub_q(Q0, av_div_q(c->cb, c->cg));
1400 23244 AVRational m02 = av_mul_q(Q(2), av_sub_q(Q1, c->cr));
1401 23244 AVRational m21 = av_mul_q(Q(2), av_sub_q(Q1, c->cb));
1402 23244 AVRational m11 = av_mul_q(cbg, m21);
1403 23244 AVRational m12 = av_mul_q(crg, m02);
1404
1405 23244 return ff_sws_op_list_append(ops, &(SwsOp) {
1406 .type = type,
1407 .op = SWS_OP_LINEAR,
1408 23244 .lin = linear_mat3(
1409 23244 Q1, Q0, m02,
1410 23244 Q1, m11, m12,
1411 23244 Q1, m21, Q0
1412 ),
1413 });
1414 }
1415
1416 case AVCOL_SPC_YCGCO:
1417 return ff_sws_op_list_append(ops, &(SwsOp) {
1418 .type = type,
1419 .op = SWS_OP_LINEAR,
1420 .lin = linear_mat3(
1421 Q1, Q(-1), Q( 1),
1422 Q1, Q( 1), Q( 0),
1423 Q1, Q(-1), Q(-1)
1424 ),
1425 });
1426
1427 case AVCOL_SPC_BT2020_CL:
1428 case AVCOL_SPC_SMPTE2085:
1429 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1430 case AVCOL_SPC_CHROMA_DERIVED_CL:
1431 case AVCOL_SPC_ICTCP:
1432 case AVCOL_SPC_IPT_C2:
1433 case AVCOL_SPC_YCGCO_RE:
1434 case AVCOL_SPC_YCGCO_RO:
1435 return AVERROR(ENOTSUP);
1436
1437 case AVCOL_SPC_RESERVED:
1438 return AVERROR(EINVAL);
1439
1440 case AVCOL_SPC_NB:
1441 break;
1442 }
1443
1444 av_unreachable("Corrupt AVColorSpace value?");
1445 return AVERROR(EINVAL);
1446 }
1447
1448 50724 int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type,
1449 SwsOpList *ops, const SwsFormat *src,
1450 const SwsFormat *dst, bool *incomplete)
1451 {
1452 50724 const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(dst->csp);
1453 50724 const SwsPixelType pixel_type = fmt_pixel_type(dst->format);
1454
2/2
✓ Branch 0 taken 4752 times.
✓ Branch 1 taken 45972 times.
50724 if (!pixel_type)
1455 4752 return AVERROR(ENOTSUP);
1456
1457
2/7
✓ Branch 0 taken 18836 times.
✓ Branch 1 taken 27136 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
45972 switch (dst->csp) {
1458 18836 case AVCOL_SPC_RGB:
1459 18836 break;
1460 27136 case AVCOL_SPC_UNSPECIFIED:
1461 27136 c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG);
1462 27136 *incomplete = true;
1463 av_fallthrough;
1464 27136 case AVCOL_SPC_FCC:
1465 case AVCOL_SPC_BT470BG:
1466 case AVCOL_SPC_SMPTE170M:
1467 case AVCOL_SPC_BT709:
1468 case AVCOL_SPC_SMPTE240M:
1469 case AVCOL_SPC_BT2020_NCL: {
1470 27136 AVRational cb1 = av_sub_q(c->cb, Q1);
1471 27136 AVRational cr1 = av_sub_q(c->cr, Q1);
1472 27136 AVRational m20 = av_make_q(1,2);
1473 27136 AVRational m10 = av_mul_q(m20, av_div_q(c->cr, cb1));
1474 27136 AVRational m11 = av_mul_q(m20, av_div_q(c->cg, cb1));
1475 27136 AVRational m21 = av_mul_q(m20, av_div_q(c->cg, cr1));
1476 27136 AVRational m22 = av_mul_q(m20, av_div_q(c->cb, cr1));
1477
1478
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 27136 times.
27136 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1479 .type = type,
1480 .op = SWS_OP_LINEAR,
1481 .lin = linear_mat3(
1482 c->cr, c->cg, c->cb,
1483 m10, m11, m20,
1484 m20, m21, m22
1485 ),
1486 }));
1487 27136 break;
1488 }
1489
1490 case AVCOL_SPC_YCGCO:
1491 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1492 .type = type,
1493 .op = SWS_OP_LINEAR,
1494 .lin = linear_mat3(
1495 av_make_q( 1, 4), av_make_q(1, 2), av_make_q( 1, 4),
1496 av_make_q( 1, 2), av_make_q(0, 1), av_make_q(-1, 2),
1497 av_make_q(-1, 4), av_make_q(1, 2), av_make_q(-1, 4)
1498 ),
1499 }));
1500 break;
1501
1502 case AVCOL_SPC_BT2020_CL:
1503 case AVCOL_SPC_SMPTE2085:
1504 case AVCOL_SPC_CHROMA_DERIVED_NCL:
1505 case AVCOL_SPC_CHROMA_DERIVED_CL:
1506 case AVCOL_SPC_ICTCP:
1507 case AVCOL_SPC_IPT_C2:
1508 case AVCOL_SPC_YCGCO_RE:
1509 case AVCOL_SPC_YCGCO_RO:
1510 return AVERROR(ENOTSUP);
1511
1512 case AVCOL_SPC_RESERVED:
1513 case AVCOL_SPC_NB:
1514 return AVERROR(EINVAL);
1515 }
1516
1517
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 45972 times.
45972 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1518 .type = type,
1519 .op = SWS_OP_LINEAR,
1520 .lin = fmt_encode_range(dst, incomplete),
1521 }));
1522
1523
2/2
✓ Branch 0 taken 43674 times.
✓ Branch 1 taken 2298 times.
45972 if (!(dst->desc->flags & AV_PIX_FMT_FLAG_FLOAT)) {
1524 43674 SwsClampOp range = {0};
1525
1526 43674 const bool is_ya = dst->desc->nb_components == 2;
1527
2/2
✓ Branch 0 taken 133372 times.
✓ Branch 1 taken 43674 times.
177046 for (int i = 0; i < dst->desc->nb_components; i++) {
1528 /* Clamp to legal pixel range */
1529
2/2
✓ Branch 0 taken 1506 times.
✓ Branch 1 taken 131866 times.
133372 const int idx = i * (is_ya ? 3 : 1);
1530 133372 range.limit[idx] = Q((1 << dst->desc->comp[i].depth) - 1);
1531 }
1532
1533
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43674 times.
43674 RET(fmt_dither(ctx, ops, type, src, dst));
1534
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43674 times.
43674 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1535 .op = SWS_OP_MAX,
1536 .type = type,
1537 .clamp = {{ Q0, Q0, Q0, Q0 }},
1538 }));
1539
1540
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43674 times.
43674 RET(ff_sws_op_list_append(ops, &(SwsOp) {
1541 .op = SWS_OP_MIN,
1542 .type = type,
1543 .clamp = range,
1544 }));
1545 }
1546
1547 45972 return ff_sws_op_list_append(ops, &(SwsOp) {
1548 .type = type,
1549 .op = SWS_OP_CONVERT,
1550 .convert.to = pixel_type,
1551 });
1552 }
1553
1554 #endif /* CONFIG_UNSTABLE */
1555