Coverage Report

Created: 2026-10-28 07:09

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