Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * JPEG XL Header Parser | ||
3 | * Copyright (c) 2023 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 <stdint.h> | ||
23 | |||
24 | #include "bytestream.h" | ||
25 | #define UNCHECKED_BITSTREAM_READER 0 | ||
26 | #define BITSTREAM_READER_LE | ||
27 | #include "get_bits.h" | ||
28 | #include "jpegxl.h" | ||
29 | #include "jpegxl_parse.h" | ||
30 | |||
31 | /* read a U32(c_i + u(u_i)) */ | ||
32 | 72 | static av_always_inline uint32_t jxl_u32(GetBitContext *gb, | |
33 | uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3, | ||
34 | uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) | ||
35 | { | ||
36 | 72 | const uint32_t constants[4] = {c0, c1, c2, c3}; | |
37 | 72 | const uint32_t ubits [4] = {u0, u1, u2, u3}; | |
38 | 72 | uint32_t ret, choice = get_bits(gb, 2); | |
39 | |||
40 | 72 | ret = constants[choice]; | |
41 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 38 times.
|
72 | if (ubits[choice]) |
42 | 34 | ret += get_bits_long(gb, ubits[choice]); | |
43 | |||
44 | 72 | return ret; | |
45 | } | ||
46 | |||
47 | ✗ | static av_always_inline uint32_t jxl_enum(GetBitContext *gb) | |
48 | { | ||
49 | ✗ | return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6); | |
50 | } | ||
51 | |||
52 | /* read a U64() */ | ||
53 | 10 | static uint64_t jxl_u64(GetBitContext *gb) | |
54 | { | ||
55 | 10 | uint64_t shift = 12, ret; | |
56 | |||
57 |
1/4✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
|
10 | switch (get_bits(gb, 2)) { |
58 | ✗ | case 1: | |
59 | ✗ | ret = 1 + get_bits(gb, 4); | |
60 | ✗ | break; | |
61 | ✗ | case 2: | |
62 | ✗ | ret = 17 + get_bits(gb, 8); | |
63 | ✗ | break; | |
64 | ✗ | case 3: | |
65 | ✗ | ret = get_bits(gb, 12); | |
66 | ✗ | while (get_bits1(gb)) { | |
67 | ✗ | if (shift < 60) { | |
68 | ✗ | ret |= (uint64_t)get_bits(gb, 8) << shift; | |
69 | ✗ | shift += 8; | |
70 | } else { | ||
71 | ✗ | ret |= (uint64_t)get_bits(gb, 4) << shift; | |
72 | ✗ | break; | |
73 | } | ||
74 | } | ||
75 | ✗ | break; | |
76 | 10 | default: | |
77 | 10 | ret = 0; | |
78 | } | ||
79 | |||
80 | 10 | return ret; | |
81 | } | ||
82 | |||
83 | 31 | static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio) | |
84 | { | ||
85 | 31 | uint64_t height64 = height; /* avoid integer overflow */ | |
86 |
4/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 14 times.
|
31 | switch (ratio) { |
87 | 11 | case 1: | |
88 | 11 | return height; | |
89 | ✗ | case 2: | |
90 | ✗ | return (uint32_t)((height64 * 12) / 10); | |
91 | 3 | case 3: | |
92 | 3 | return (uint32_t)((height64 * 4) / 3); | |
93 | 3 | case 4: | |
94 | 3 | return (uint32_t)((height64 * 3) / 2); | |
95 | ✗ | case 5: | |
96 | ✗ | return (uint32_t)((height64 * 16) / 9); | |
97 | ✗ | case 6: | |
98 | ✗ | return (uint32_t)((height64 * 5) / 4); | |
99 | ✗ | case 7: | |
100 | ✗ | return (uint32_t)(height64 * 2); | |
101 | 14 | default: | |
102 | 14 | break; | |
103 | } | ||
104 | |||
105 | 14 | return 0; /* manual width */ | |
106 | } | ||
107 | |||
108 | /** | ||
109 | * validate a Jpeg XL Size Header | ||
110 | * @return >= 0 upon valid size, < 0 upon invalid size found | ||
111 | */ | ||
112 | 31 | static int jpegxl_read_size_header(GetBitContext *gb, FFJXLMetadata *meta, int validate) | |
113 | { | ||
114 | uint32_t width, height; | ||
115 | |||
116 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 17 times.
|
31 | if (get_bits1(gb)) { |
117 | /* small size header */ | ||
118 | 14 | height = (get_bits(gb, 5) + 1) << 3; | |
119 | 14 | width = jpegxl_width_from_ratio(height, get_bits(gb, 3)); | |
120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!width) |
121 | ✗ | width = (get_bits(gb, 5) + 1) << 3; | |
122 | } else { | ||
123 | /* large size header */ | ||
124 | 17 | height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30); | |
125 | 17 | width = jpegxl_width_from_ratio(height, get_bits(gb, 3)); | |
126 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 3 times.
|
17 | if (!width) |
127 | 14 | width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30); | |
128 | } | ||
129 |
4/6✓ Branch 0 taken 9 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
31 | if (validate && (width > (1 << 18) || height > (1 << 18) |
130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | || (width >> 4) * (height >> 4) > (1 << 20))) |
131 | ✗ | return AVERROR_INVALIDDATA; | |
132 | |||
133 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 3 times.
|
31 | if (meta) { |
134 | 28 | meta->width = meta->coded_width = width; | |
135 | 28 | meta->height = meta->coded_height = height; | |
136 | } | ||
137 | |||
138 | 31 | return 0; | |
139 | } | ||
140 | |||
141 | /** | ||
142 | * validate a Jpeg XL Preview Header | ||
143 | * @return >= 0 upon valid size, < 0 upon invalid size found | ||
144 | */ | ||
145 | ✗ | static int jpegxl_read_preview_header(GetBitContext *gb, int validate) | |
146 | { | ||
147 | uint32_t width, height; | ||
148 | |||
149 | ✗ | if (get_bits1(gb)) { | |
150 | /* coded height and width divided by eight */ | ||
151 | ✗ | height = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3; | |
152 | ✗ | width = jpegxl_width_from_ratio(height, get_bits(gb, 3)); | |
153 | ✗ | if (!width) | |
154 | ✗ | width = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3; | |
155 | } else { | ||
156 | /* full height and width coded */ | ||
157 | ✗ | height = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12); | |
158 | ✗ | width = jpegxl_width_from_ratio(height, get_bits(gb, 3)); | |
159 | ✗ | if (!width) | |
160 | ✗ | width = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12); | |
161 | } | ||
162 | ✗ | if (validate && (width > 4096 || height > 4096)) | |
163 | ✗ | return AVERROR_INVALIDDATA; | |
164 | |||
165 | ✗ | return 0; | |
166 | } | ||
167 | |||
168 | /** | ||
169 | * get a Jpeg XL BitDepth Header. These cannot be invalid. | ||
170 | */ | ||
171 | 10 | static void jpegxl_get_bit_depth(GetBitContext *gb, FFJXLMetadata *meta) | |
172 | { | ||
173 | int bit_depth; | ||
174 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (get_bits1(gb)) { |
175 | /* float samples */ | ||
176 | ✗ | bit_depth = jxl_u32(gb, 32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */ | |
177 | ✗ | skip_bits_long(gb, 4); /* exponent */ | |
178 | } else { | ||
179 | /* integer samples */ | ||
180 | 10 | bit_depth = jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6); | |
181 | } | ||
182 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
|
10 | if (meta) |
183 | 8 | meta->bit_depth = bit_depth; | |
184 | 10 | } | |
185 | |||
186 | /** | ||
187 | * validate a Jpeg XL Extra Channel Info bundle | ||
188 | * @return >= 0 upon valid, < 0 upon invalid | ||
189 | */ | ||
190 | 7 | static int jpegxl_read_extra_channel_info(GetBitContext *gb, FFJXLMetadata *meta, int validate) | |
191 | { | ||
192 | 7 | int default_alpha = get_bits1(gb); | |
193 | 7 | int alpha_associated = 0; | |
194 | 7 | uint32_t type, name_len = 0; | |
195 | |||
196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (!default_alpha) { |
197 | ✗ | type = jxl_enum(gb); | |
198 | ✗ | if (validate && type > 63) | |
199 | ✗ | return AVERROR_INVALIDDATA; /* enum types cannot be 64+ */ | |
200 | ✗ | if (validate && validate < 10 && type == JPEGXL_CT_BLACK) | |
201 | ✗ | return AVERROR_INVALIDDATA; | |
202 | ✗ | jpegxl_get_bit_depth(gb, NULL); | |
203 | ✗ | jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */ | |
204 | /* max of name_len is 1071 = 48 + 2^10 - 1 */ | ||
205 | ✗ | name_len = 8 * jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10); | |
206 | } else { | ||
207 | 7 | type = JPEGXL_CT_ALPHA; | |
208 | } | ||
209 | |||
210 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits_left(gb) < name_len) |
211 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
212 | |||
213 | /* skip over the name */ | ||
214 | 7 | skip_bits_long(gb, name_len); | |
215 | |||
216 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 | if (!default_alpha && type == JPEGXL_CT_ALPHA) |
217 | ✗ | alpha_associated = get_bits1(gb); | |
218 | |||
219 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (type == JPEGXL_CT_SPOT_COLOR) |
220 | ✗ | skip_bits_long(gb, 16 * 4); | |
221 | |||
222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (type == JPEGXL_CT_CFA) |
223 | ✗ | jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8); | |
224 | |||
225 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
7 | if (meta && type == JPEGXL_CT_ALPHA) { |
226 | 6 | meta->have_alpha = 1; | |
227 | 6 | meta->alpha_associated = alpha_associated; | |
228 | } | ||
229 | |||
230 | 7 | return 0; | |
231 | } | ||
232 | |||
233 | 10 | static int jpegxl_skip_extensions(GetBitContext *gb) | |
234 | { | ||
235 | 10 | uint64_t extensions = jxl_u64(gb), extensions_len = 0; | |
236 | |||
237 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (get_bits_left(gb) <= 0) |
238 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
239 | |||
240 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (!extensions) |
241 | 10 | return 0; | |
242 | |||
243 | ✗ | for (int i = 0; i < 64; i++) { | |
244 | ✗ | if (extensions & (UINT64_C(1) << i)) | |
245 | ✗ | extensions_len += jxl_u64(gb); | |
246 | ✗ | if (get_bits_left(gb) <= 0) | |
247 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
248 | } | ||
249 | |||
250 | ✗ | if (extensions_len > INT_MAX || get_bits_left(gb) <= extensions_len) | |
251 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
252 | |||
253 | ✗ | skip_bits_long(gb, extensions_len); | |
254 | |||
255 | ✗ | return 0; | |
256 | } | ||
257 | |||
258 | 31 | int ff_jpegxl_parse_codestream_header(const uint8_t *buf, int buflen, FFJXLMetadata *meta, int validate) | |
259 | { | ||
260 | 31 | GetBitContext gbi, *gb = &gbi; | |
261 | |||
262 | 31 | int all_default, extra_fields = 0; | |
263 | 31 | int xyb_encoded = 1, have_icc_profile = 0; | |
264 | 31 | int animation_offset = 0, have_timecodes = 0; | |
265 | |||
266 | 31 | FFJXLPrimaries primaries = JPEGXL_PR_SRGB; | |
267 | 31 | FFJXLTransferCharacteristic trc = JPEGXL_TR_SRGB + (1U << 24); | |
268 | 31 | FFJXLWhitePoint white_point = JPEGXL_WP_D65; | |
269 | 31 | FFJXLColorSpace color_space = JPEGXL_CS_RGB; | |
270 | |||
271 | AVRational tb; | ||
272 | 31 | uint32_t num_extra_channels = 0; | |
273 | int ret; | ||
274 | |||
275 | 31 | ret = init_get_bits8(gb, buf, buflen); | |
276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | if (ret < 0) |
277 | ✗ | return ret; | |
278 | |||
279 |
3/4✓ Branch 1 taken 6 times.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
|
31 | if (get_bits(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE && validate) |
280 | ✗ | return AVERROR_INVALIDDATA; | |
281 | |||
282 | 31 | ret = jpegxl_read_size_header(gb, meta, validate); | |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | if (ret < 0) |
284 | ✗ | return ret; | |
285 | |||
286 | 31 | all_default = get_bits1(gb); | |
287 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 15 times.
|
31 | if (!all_default) |
288 | 16 | extra_fields = get_bits1(gb); | |
289 | |||
290 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 24 times.
|
31 | if (extra_fields) { |
291 | 7 | int orientation = get_bits(gb, 3); | |
292 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 | if (orientation > 3 && meta) |
293 | ✗ | FFSWAP(uint32_t, meta->width, meta->height); | |
294 | |||
295 | /* | ||
296 | * intrinstic size | ||
297 | * any size header here is valid, but as it | ||
298 | * is variable length we have to read it | ||
299 | */ | ||
300 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits1(gb)) |
301 | ✗ | jpegxl_read_size_header(gb, NULL, 0); | |
302 | |||
303 | /* preview header */ | ||
304 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits1(gb)) { |
305 | ✗ | ret = jpegxl_read_preview_header(gb, 0); | |
306 | ✗ | if (ret < 0) | |
307 | ✗ | return ret; | |
308 | } | ||
309 | |||
310 | /* animation header */ | ||
311 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (get_bits1(gb)) { |
312 | 7 | animation_offset = get_bits_count(gb); | |
313 | 7 | tb.den = jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30); | |
314 | 7 | tb.num = jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10); | |
315 | 7 | jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32); | |
316 | 7 | have_timecodes = get_bits1(gb); | |
317 | } | ||
318 | } | ||
319 | |||
320 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
|
31 | if (animation_offset && meta) { |
321 | 6 | meta->animation_offset = animation_offset; | |
322 | 6 | meta->timebase = tb; | |
323 | 6 | meta->have_timecodes = have_timecodes; | |
324 | } | ||
325 | |||
326 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 25 times.
|
31 | if (get_bits_left(gb) <= 0) |
327 | 6 | return AVERROR_BUFFER_TOO_SMALL; | |
328 | |||
329 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 15 times.
|
25 | if (!all_default) { |
330 | 10 | jpegxl_get_bit_depth(gb, meta); | |
331 | |||
332 | /* modular_16bit_buffers must equal 1 */ | ||
333 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
10 | if (!get_bits1(gb) && validate && validate < 10) |
334 | ✗ | return AVERROR_INVALIDDATA; | |
335 | |||
336 | 10 | num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12); | |
337 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
10 | if (num_extra_channels > 4 && validate && validate < 10) |
338 | ✗ | return AVERROR_INVALIDDATA; | |
339 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
|
17 | for (uint32_t i = 0; i < num_extra_channels; i++) { |
340 | 7 | ret = jpegxl_read_extra_channel_info(gb, meta, validate); | |
341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
342 | ✗ | return ret; | |
343 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits_left(gb) <= 0) |
344 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
345 | } | ||
346 | |||
347 | 10 | xyb_encoded = get_bits1(gb); | |
348 | |||
349 | /* color encoding bundle */ | ||
350 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (!get_bits1(gb)) { |
351 | ✗ | have_icc_profile = get_bits1(gb); | |
352 | ✗ | color_space = jxl_enum(gb); | |
353 | ✗ | if (color_space > 63 && validate) | |
354 | ✗ | return AVERROR_INVALIDDATA; | |
355 | ✗ | if (!have_icc_profile) { | |
356 | ✗ | if (color_space != JPEGXL_CS_XYB) { | |
357 | ✗ | white_point = jxl_enum(gb); | |
358 | ✗ | if (white_point > 63 && validate) | |
359 | ✗ | return AVERROR_INVALIDDATA; | |
360 | ✗ | if (white_point == JPEGXL_WP_CUSTOM) { | |
361 | /* ux and uy values */ | ||
362 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
363 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
364 | } | ||
365 | ✗ | if (color_space != JPEGXL_CS_GRAY) { | |
366 | /* primaries */ | ||
367 | ✗ | primaries = jxl_enum(gb); | |
368 | ✗ | if (primaries > 63 && validate) | |
369 | ✗ | return AVERROR_INVALIDDATA; | |
370 | ✗ | if (primaries == JPEGXL_PR_CUSTOM) { | |
371 | /* ux/uy values for r,g,b */ | ||
372 | ✗ | for (int i = 0; i < 6; i++) { | |
373 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
374 | ✗ | if (get_bits_left(gb) <= 0) | |
375 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
376 | } | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | /* transfer characteristics */ | ||
382 | ✗ | if (get_bits1(gb)) { | |
383 | /* gamma */ | ||
384 | ✗ | trc = get_bits(gb, 24); | |
385 | } else { | ||
386 | /* transfer function */ | ||
387 | ✗ | trc = jxl_enum(gb); | |
388 | ✗ | if (trc > 63 && validate) | |
389 | ✗ | return AVERROR_INVALIDDATA; | |
390 | ✗ | trc += (1U << 24); | |
391 | } | ||
392 | |||
393 | /* rendering intent */ | ||
394 | ✗ | if (jxl_enum(gb) > 63 && validate) | |
395 | ✗ | return AVERROR_INVALIDDATA; | |
396 | } | ||
397 | } | ||
398 | |||
399 | /* tone mapping bundle */ | ||
400 |
3/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
|
10 | if (extra_fields && !get_bits1(gb)) |
401 | ✗ | skip_bits_long(gb, 16 + 16 + 1 + 16); | |
402 | |||
403 | 10 | ret = jpegxl_skip_extensions(gb); | |
404 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (ret < 0) |
405 | ✗ | return ret; | |
406 | } | ||
407 | |||
408 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3 times.
|
25 | if (meta) { |
409 | 22 | meta->xyb_encoded = xyb_encoded; | |
410 | 22 | meta->have_icc_profile = have_icc_profile; | |
411 | 22 | meta->csp = color_space; | |
412 | 22 | meta->primaries = primaries; | |
413 | 22 | meta->wp = white_point; | |
414 | 22 | meta->trc = trc; | |
415 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
|
22 | if (!meta->bit_depth) |
416 | 14 | meta->bit_depth = 8; | |
417 | 22 | meta->num_extra_channels = num_extra_channels; | |
418 | } | ||
419 | |||
420 | /* default transform */ | ||
421 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | if (!get_bits1(gb)) { |
422 | /* opsin inverse matrix */ | ||
423 | ✗ | if (xyb_encoded && !get_bits1(gb)) | |
424 | ✗ | skip_bits_long(gb, 16 * 16); | |
425 | /* cw_mask and default weights */ | ||
426 | ✗ | if (get_bits1(gb)) | |
427 | ✗ | skip_bits_long(gb, 16 * 15); | |
428 | ✗ | if (get_bits1(gb)) | |
429 | ✗ | skip_bits_long(gb, 16 * 55); | |
430 | ✗ | if (get_bits1(gb)) | |
431 | ✗ | skip_bits_long(gb, 16 * 210); | |
432 | } | ||
433 | |||
434 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if (!have_icc_profile) { |
435 | 25 | int bits_remaining = 7 - ((get_bits_count(gb) - 1) & 0x7); | |
436 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
|
25 | if (bits_remaining && get_bits(gb, bits_remaining)) |
437 | ✗ | return AVERROR_INVALIDDATA; | |
438 | } | ||
439 | |||
440 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | if (get_bits_left(gb) < 0) |
441 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
442 | |||
443 | 25 | return get_bits_count(gb); | |
444 | } | ||
445 | |||
446 | /* | ||
447 | * copies as much of the codestream into the buffer as possible | ||
448 | * pass a shorter buflen to request less | ||
449 | * returns the number of bytes consumed from input, may be greater than input_len | ||
450 | * if the input doesn't end on an ISOBMFF-box boundary | ||
451 | */ | ||
452 | 10 | int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len, | |
453 | uint8_t *buffer, int buflen, int *copied) | ||
454 | { | ||
455 | GetByteContext gb; | ||
456 | 10 | int64_t pos = 0; | |
457 | 10 | int last_box = 0; | |
458 | 10 | bytestream2_init(&gb, input_buffer, input_len); | |
459 | |||
460 | 19 | while (1) { | |
461 | uint64_t size; | ||
462 | uint32_t tag; | ||
463 | 29 | int head_size = 8; | |
464 | |||
465 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (bytestream2_get_bytes_left(&gb) < 8) |
466 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
467 | |||
468 | 29 | size = bytestream2_get_be32(&gb); | |
469 | 29 | tag = bytestream2_get_le32(&gb); | |
470 | |||
471 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 24 times.
|
29 | if (size == 1) { |
472 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | if (bytestream2_get_bytes_left(&gb) < 8) |
473 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
474 | 5 | size = bytestream2_get_be64(&gb); | |
475 | 5 | head_size = 16; | |
476 | } | ||
477 | /* invalid ISOBMFF size */ | ||
478 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | if (size && size <= head_size) |
479 | ✗ | return AVERROR_INVALIDDATA; | |
480 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (size) |
481 | 29 | size -= head_size; | |
482 | |||
483 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
|
29 | if (tag == MKTAG('j','x','l','p')) { |
484 | uint32_t idx; | ||
485 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if (bytestream2_get_bytes_left(&gb) < 4) |
486 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
487 | 3 | idx = bytestream2_get_be32(&gb); | |
488 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (idx >= UINT32_C(0x80000000)) |
489 | ✗ | last_box = 1; | |
490 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (size) { |
491 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (size <= 4) |
492 | ✗ | return AVERROR_INVALIDDATA; | |
493 | 3 | size -= 4; | |
494 | } | ||
495 | } | ||
496 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
|
29 | if (tag == MKTAG('j','x','l','c')) |
497 | 7 | last_box = 1; | |
498 | |||
499 | /* | ||
500 | * size = 0 means "until EOF". this is legal but uncommon | ||
501 | * here we just set it to the remaining size of the probe buffer | ||
502 | */ | ||
503 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!size) |
504 | ✗ | size = bytestream2_get_bytes_left(&gb); | |
505 | else | ||
506 | 29 | pos += size + head_size; | |
507 | |||
508 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 19 times.
|
29 | if (tag == MKTAG('j','x','l','c') || tag == MKTAG('j','x','l','p')) { |
509 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (size > buflen - *copied) |
510 | 5 | size = buflen - *copied; | |
511 | /* | ||
512 | * arbitrary chunking of the payload makes this memcpy hard to avoid | ||
513 | * in practice this will only be performed one or two times at most | ||
514 | */ | ||
515 | 10 | *copied += bytestream2_get_buffer(&gb, buffer + *copied, size); | |
516 | } else { | ||
517 | 19 | bytestream2_skip(&gb, size); | |
518 | } | ||
519 |
6/6✓ Branch 0 taken 22 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 2 times.
|
29 | if (last_box || bytestream2_get_bytes_left(&gb) <= 0 || *copied >= buflen) |
520 | break; | ||
521 | } | ||
522 | |||
523 | 10 | return FFMIN(pos, INT_MAX); | |
524 | } | ||
525 |