FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/jpegxl_probe.c
Date: 2022-11-26 13:19:19
Exec Total Coverage
Lines: 0 187 0.0%
Branches: 0 141 0.0%

Line Branch Exec Source
1 /*
2 * Jpeg XL header verification
3 * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "jpegxl_probe.h"
23
24 #define BITSTREAM_READER_LE
25 #include "libavcodec/get_bits.h"
26
27 enum JpegXLExtraChannelType {
28 FF_JPEGXL_CT_ALPHA = 0,
29 FF_JPEGXL_CT_DEPTH,
30 FF_JPEGXL_CT_SPOT_COLOR,
31 FF_JPEGXL_CT_SELECTION_MASK,
32 FF_JPEGXL_CT_BLACK,
33 FF_JPEGXL_CT_CFA,
34 FF_JPEGXL_CT_THERMAL,
35 FF_JPEGXL_CT_NON_OPTIONAL = 15,
36 FF_JPEGXL_CT_OPTIONAL
37 };
38
39 enum JpegXLColorSpace {
40 FF_JPEGXL_CS_RGB = 0,
41 FF_JPEGXL_CS_GRAY,
42 FF_JPEGXL_CS_XYB,
43 FF_JPEGXL_CS_UNKNOWN
44 };
45
46 enum JpegXLWhitePoint {
47 FF_JPEGXL_WP_D65 = 1,
48 FF_JPEGXL_WP_CUSTOM,
49 FF_JPEGXL_WP_E = 10,
50 FF_JPEGXL_WP_DCI = 11
51 };
52
53 enum JpegXLPrimaries {
54 FF_JPEGXL_PR_SRGB = 1,
55 FF_JPEGXL_PR_CUSTOM,
56 FF_JPEGXL_PR_2100 = 9,
57 FF_JPEGXL_PR_P3 = 11,
58 };
59
60 #define jxl_bits(n) get_bits_long(gb, (n))
61 #define jxl_bits_skip(n) skip_bits_long(gb, (n))
62 #define jxl_u32(c0, c1, c2, c3, u0, u1, u2, u3) jpegxl_u32(gb, \
63 (const uint32_t[]){c0, c1, c2, c3}, (const uint32_t[]){u0, u1, u2, u3})
64 #define jxl_u64() jpegxl_u64(gb)
65 #define jxl_enum() jxl_u32(0, 1, 2, 18, 0, 0, 4, 6)
66
67 /* read a U32(c_i + u(u_i)) */
68 static uint32_t jpegxl_u32(GetBitContext *gb,
69 const uint32_t constants[4], const uint32_t ubits[4])
70 {
71 uint32_t ret, choice = jxl_bits(2);
72
73 ret = constants[choice];
74 if (ubits[choice])
75 ret += jxl_bits(ubits[choice]);
76
77 return ret;
78 }
79
80 /* read a U64() */
81 static uint64_t jpegxl_u64(GetBitContext *gb)
82 {
83 uint64_t shift = 12, ret;
84
85 switch (jxl_bits(2)) {
86 case 0:
87 ret = 0;
88 break;
89 case 1:
90 ret = 1 + jxl_bits(4);
91 break;
92 case 2:
93 ret = 17 + jxl_bits(8);
94 break;
95 case 3:
96 ret = jxl_bits(12);
97 while (jxl_bits(1)) {
98 if (shift < 60) {
99 ret |= (uint64_t)jxl_bits(8) << shift;
100 shift += 8;
101 } else {
102 ret |= (uint64_t)jxl_bits(4) << shift;
103 break;
104 }
105 }
106 break;
107 }
108
109 return ret;
110 }
111
112 static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
113 {
114 uint64_t height64 = height; /* avoid integer overflow */
115 switch (ratio) {
116 case 1:
117 return height;
118 case 2:
119 return (uint32_t)((height64 * 12) / 10);
120 case 3:
121 return (uint32_t)((height64 * 4) / 3);
122 case 4:
123 return (uint32_t)((height64 * 3) / 2);
124 case 5:
125 return (uint32_t)((height64 * 16) / 9);
126 case 6:
127 return (uint32_t)((height64 * 5) / 4);
128 case 7:
129 return (uint32_t)(height64 * 2);
130 default:
131 break;
132 }
133
134 return 0; /* manual width */
135 }
136
137 /**
138 * validate a Jpeg XL Size Header
139 * @return >= 0 upon valid size, < 0 upon invalid size found
140 */
141 static int jpegxl_read_size_header(GetBitContext *gb)
142 {
143 uint32_t width, height;
144
145 if (jxl_bits(1)) {
146 /* small size header */
147 height = (jxl_bits(5) + 1) << 3;
148 width = jpegxl_width_from_ratio(height, jxl_bits(3));
149 if (!width)
150 width = (jxl_bits(5) + 1) << 3;
151 } else {
152 /* large size header */
153 height = 1 + jxl_u32(0, 0, 0, 0, 9, 13, 18, 30);
154 width = jpegxl_width_from_ratio(height, jxl_bits(3));
155 if (!width)
156 width = 1 + jxl_u32(0, 0, 0, 0, 9, 13, 18, 30);
157 }
158 if (width > (1 << 18) || height > (1 << 18)
159 || (width >> 4) * (height >> 4) > (1 << 20))
160 return -1;
161
162 return 0;
163 }
164
165 /**
166 * validate a Jpeg XL Preview Header
167 * @return >= 0 upon valid size, < 0 upon invalid size found
168 */
169 static int jpegxl_read_preview_header(GetBitContext *gb)
170 {
171 uint32_t width, height;
172
173 if (jxl_bits(1)) {
174 /* coded height and width divided by eight */
175 height = jxl_u32(16, 32, 1, 33, 0, 0, 5, 9) << 3;
176 width = jpegxl_width_from_ratio(height, jxl_bits(3));
177 if (!width)
178 width = jxl_u32(16, 32, 1, 33, 0, 0, 5, 9) << 3;
179 } else {
180 /* full height and width coded */
181 height = jxl_u32(1, 65, 321, 1345, 6, 8, 10, 12);
182 width = jpegxl_width_from_ratio(height, jxl_bits(3));
183 if (!width)
184 width = jxl_u32(1, 65, 321, 1345, 6, 8, 10, 12);
185 }
186 if (width > 4096 || height > 4096)
187 return -1;
188
189 return 0;
190 }
191
192 /**
193 * skip a Jpeg XL BitDepth Header. These cannot be invalid.
194 */
195 static void jpegxl_skip_bit_depth(GetBitContext *gb)
196 {
197 if (jxl_bits(1)) {
198 /* float samples */
199 jxl_u32(32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */
200 jxl_bits_skip(4); /* exponent */
201 } else {
202 /* integer samples */
203 jxl_u32(8, 10, 12, 1, 0, 0, 0, 6);
204 }
205 }
206
207 /**
208 * validate a Jpeg XL Extra Channel Info bundle
209 * @return >= 0 upon valid, < 0 upon invalid
210 */
211 static int jpegxl_read_extra_channel_info(GetBitContext *gb)
212 {
213 int all_default = jxl_bits(1);
214 uint32_t type, name_len = 0;
215
216 if (!all_default) {
217 type = jxl_enum();
218 if (type > 63)
219 return -1; /* enum types cannot be 64+ */
220 if (type == FF_JPEGXL_CT_BLACK)
221 return -1;
222 jpegxl_skip_bit_depth(gb);
223 jxl_u32(0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */
224 /* max of name_len is 1071 = 48 + 2^10 - 1 */
225 name_len = jxl_u32(0, 0, 16, 48, 0, 4, 5, 10);
226 } else {
227 type = FF_JPEGXL_CT_ALPHA;
228 }
229
230 /* skip over the name */
231 jxl_bits_skip(8 * name_len);
232
233 if (!all_default && type == FF_JPEGXL_CT_ALPHA)
234 jxl_bits_skip(1);
235
236 if (type == FF_JPEGXL_CT_SPOT_COLOR)
237 jxl_bits_skip(16 * 4);
238
239 if (type == FF_JPEGXL_CT_CFA)
240 jxl_u32(1, 0, 3, 19, 0, 2, 4, 8);
241
242 return 0;
243 }
244
245 /* verify that a codestream header is valid */
246 int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen)
247 {
248 GetBitContext gbi, *gb = &gbi;
249 int all_default, extra_fields = 0;
250 int xyb_encoded = 1, have_icc_profile = 0;
251 uint32_t num_extra_channels;
252 uint64_t extensions;
253 int ret;
254
255 ret = init_get_bits8(gb, buf, buflen);
256 if (ret < 0)
257 return ret;
258
259 if (jxl_bits(16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
260 return -1;
261
262 if (jpegxl_read_size_header(gb) < 0)
263 return -1;
264
265 all_default = jxl_bits(1);
266 if (!all_default)
267 extra_fields = jxl_bits(1);
268
269 if (extra_fields) {
270 jxl_bits_skip(3); /* orientation */
271
272 /*
273 * intrinstic size
274 * any size header here is valid, but as it
275 * is variable length we have to read it
276 */
277 if (jxl_bits(1))
278 jpegxl_read_size_header(gb);
279
280 /* preview header */
281 if (jxl_bits(1)) {
282 if (jpegxl_read_preview_header(gb) < 0)
283 return -1;
284 }
285
286 /* animation header */
287 if (jxl_bits(1)) {
288 jxl_u32(100, 1000, 1, 1, 0, 0, 10, 30);
289 jxl_u32(1, 1001, 1, 1, 0, 0, 8, 10);
290 jxl_u32(0, 0, 0, 0, 0, 3, 16, 32);
291 jxl_bits_skip(1);
292 }
293 }
294
295 if (!all_default) {
296 jpegxl_skip_bit_depth(gb);
297
298 /* modular_16bit_buffers must equal 1 */
299 if (!jxl_bits(1))
300 return -1;
301
302 num_extra_channels = jxl_u32(0, 1, 2, 1, 0, 0, 4, 12);
303 if (num_extra_channels > 4)
304 return -1;
305 for (uint32_t i = 0; i < num_extra_channels; i++) {
306 if (jpegxl_read_extra_channel_info(gb) < 0)
307 return -1;
308 }
309
310 xyb_encoded = jxl_bits(1);
311
312 /* color encoding bundle */
313 if (!jxl_bits(1)) {
314 uint32_t color_space;
315 have_icc_profile = jxl_bits(1);
316 color_space = jxl_enum();
317 if (color_space > 63)
318 return -1;
319
320 if (!have_icc_profile) {
321 if (color_space != FF_JPEGXL_CS_XYB) {
322 uint32_t white_point = jxl_enum();
323 if (white_point > 63)
324 return -1;
325 if (white_point == FF_JPEGXL_WP_CUSTOM) {
326 /* ux and uy values */
327 jxl_u32(0, 524288, 1048576, 2097152, 19, 19, 20, 21);
328 jxl_u32(0, 524288, 1048576, 2097152, 19, 19, 20, 21);
329 }
330 if (color_space != FF_JPEGXL_CS_GRAY) {
331 /* primaries */
332 uint32_t primaries = jxl_enum();
333 if (primaries > 63)
334 return -1;
335 if (primaries == FF_JPEGXL_PR_CUSTOM) {
336 /* ux/uy values for r,g,b */
337 for (int i = 0; i < 6; i++)
338 jxl_u32(0, 524288, 1048576, 2097152, 19, 19, 20, 21);
339 }
340 }
341 }
342
343 /* transfer characteristics */
344 if (jxl_bits(1)) {
345 /* gamma */
346 jxl_bits_skip(24);
347 } else {
348 /* transfer function */
349 if (jxl_enum() > 63)
350 return -1;
351 }
352
353 /* rendering intent */
354 if (jxl_enum() > 63)
355 return -1;
356 }
357 }
358
359 /* tone mapping bundle */
360 if (extra_fields && !jxl_bits(1))
361 jxl_bits_skip(16 + 16 + 1 + 16);
362
363 extensions = jxl_u64();
364 if (extensions) {
365 for (int i = 0; i < 64; i++) {
366 if (extensions & (UINT64_C(1) << i))
367 jxl_u64();
368 }
369 }
370 }
371
372 /* default transform */
373 if (!jxl_bits(1)) {
374 /* opsin inverse matrix */
375 if (xyb_encoded && !jxl_bits(1))
376 jxl_bits_skip(16 * 16);
377 /* cw_mask and default weights */
378 if (jxl_bits(1))
379 jxl_bits_skip(16 * 15);
380 if (jxl_bits(1))
381 jxl_bits_skip(16 * 55);
382 if (jxl_bits(1))
383 jxl_bits_skip(16 * 210);
384 }
385
386 if (!have_icc_profile) {
387 int bits_remaining = 7 - (get_bits_count(gb) - 1) % 8;
388 if (bits_remaining && jxl_bits(bits_remaining))
389 return -1;
390 }
391
392 if (get_bits_left(gb) < 0)
393 return -1;
394
395 return 0;
396 }
397