FFmpeg coverage


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