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 | uint32_t type, name_len = 0; | |
194 | |||
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (!default_alpha) { |
196 | ✗ | type = jxl_enum(gb); | |
197 | ✗ | if (validate && type > 63) | |
198 | ✗ | return AVERROR_INVALIDDATA; /* enum types cannot be 64+ */ | |
199 | ✗ | if (validate && validate < 10 && type == JPEGXL_CT_BLACK) | |
200 | ✗ | return AVERROR_INVALIDDATA; | |
201 | ✗ | jpegxl_get_bit_depth(gb, NULL); | |
202 | ✗ | jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */ | |
203 | /* max of name_len is 1071 = 48 + 2^10 - 1 */ | ||
204 | ✗ | name_len = 8 * jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10); | |
205 | } else { | ||
206 | 7 | type = JPEGXL_CT_ALPHA; | |
207 | } | ||
208 | |||
209 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits_left(gb) < name_len) |
210 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
211 | |||
212 | /* skip over the name */ | ||
213 | 7 | skip_bits_long(gb, name_len); | |
214 | |||
215 |
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) |
216 | ✗ | skip_bits1(gb); | |
217 | |||
218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (type == JPEGXL_CT_SPOT_COLOR) |
219 | ✗ | skip_bits_long(gb, 16 * 4); | |
220 | |||
221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (type == JPEGXL_CT_CFA) |
222 | ✗ | jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8); | |
223 | |||
224 |
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) |
225 | 6 | meta->have_alpha = 1; | |
226 | |||
227 | 7 | return 0; | |
228 | } | ||
229 | |||
230 | 10 | static int jpegxl_skip_extensions(GetBitContext *gb) | |
231 | { | ||
232 | 10 | uint64_t extensions = jxl_u64(gb), extensions_len = 0; | |
233 | |||
234 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (get_bits_left(gb) <= 0) |
235 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
236 | |||
237 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (!extensions) |
238 | 10 | return 0; | |
239 | |||
240 | ✗ | for (int i = 0; i < 64; i++) { | |
241 | ✗ | if (extensions & (UINT64_C(1) << i)) | |
242 | ✗ | extensions_len += jxl_u64(gb); | |
243 | ✗ | if (get_bits_left(gb) <= 0) | |
244 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
245 | } | ||
246 | |||
247 | ✗ | if (extensions_len > INT_MAX || get_bits_left(gb) <= extensions_len) | |
248 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
249 | |||
250 | ✗ | skip_bits_long(gb, extensions_len); | |
251 | |||
252 | ✗ | return 0; | |
253 | } | ||
254 | |||
255 | 31 | int ff_jpegxl_parse_codestream_header(const uint8_t *buf, int buflen, FFJXLMetadata *meta, int validate) | |
256 | { | ||
257 | 31 | GetBitContext gbi, *gb = &gbi; | |
258 | |||
259 | 31 | int all_default, extra_fields = 0; | |
260 | 31 | int xyb_encoded = 1, have_icc_profile = 0; | |
261 | 31 | int animation_offset = 0, have_timecodes = 0; | |
262 | |||
263 | 31 | FFJXLPrimaries primaries = JPEGXL_PR_SRGB; | |
264 | 31 | FFJXLTransferCharacteristic trc = JPEGXL_TR_SRGB + (1U << 24); | |
265 | 31 | FFJXLWhitePoint white_point = JPEGXL_WP_D65; | |
266 | 31 | FFJXLColorSpace color_space = JPEGXL_CS_RGB; | |
267 | |||
268 | AVRational tb; | ||
269 | 31 | uint32_t num_extra_channels = 0; | |
270 | int ret; | ||
271 | |||
272 | 31 | ret = init_get_bits8(gb, buf, buflen); | |
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | if (ret < 0) |
274 | ✗ | return ret; | |
275 | |||
276 |
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) |
277 | ✗ | return AVERROR_INVALIDDATA; | |
278 | |||
279 | 31 | ret = jpegxl_read_size_header(gb, meta, validate); | |
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | if (ret < 0) |
281 | ✗ | return ret; | |
282 | |||
283 | 31 | all_default = get_bits1(gb); | |
284 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 15 times.
|
31 | if (!all_default) |
285 | 16 | extra_fields = get_bits1(gb); | |
286 | |||
287 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 24 times.
|
31 | if (extra_fields) { |
288 | 7 | int orientation = get_bits(gb, 3); | |
289 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7 | if (orientation > 3 && meta) |
290 | ✗ | FFSWAP(uint32_t, meta->width, meta->height); | |
291 | |||
292 | /* | ||
293 | * intrinstic size | ||
294 | * any size header here is valid, but as it | ||
295 | * is variable length we have to read it | ||
296 | */ | ||
297 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits1(gb)) |
298 | ✗ | jpegxl_read_size_header(gb, NULL, 0); | |
299 | |||
300 | /* preview header */ | ||
301 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits1(gb)) { |
302 | ✗ | ret = jpegxl_read_preview_header(gb, 0); | |
303 | ✗ | if (ret < 0) | |
304 | ✗ | return ret; | |
305 | } | ||
306 | |||
307 | /* animation header */ | ||
308 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (get_bits1(gb)) { |
309 | 7 | animation_offset = get_bits_count(gb); | |
310 | 7 | tb.den = jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30); | |
311 | 7 | tb.num = jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10); | |
312 | 7 | jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32); | |
313 | 7 | have_timecodes = get_bits1(gb); | |
314 | } | ||
315 | } | ||
316 | |||
317 |
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) { |
318 | 6 | meta->animation_offset = animation_offset; | |
319 | 6 | meta->timebase = tb; | |
320 | 6 | meta->have_timecodes = have_timecodes; | |
321 | } | ||
322 | |||
323 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 25 times.
|
31 | if (get_bits_left(gb) <= 0) |
324 | 6 | return AVERROR_BUFFER_TOO_SMALL; | |
325 | |||
326 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 15 times.
|
25 | if (!all_default) { |
327 | 10 | jpegxl_get_bit_depth(gb, meta); | |
328 | |||
329 | /* modular_16bit_buffers must equal 1 */ | ||
330 |
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) |
331 | ✗ | return AVERROR_INVALIDDATA; | |
332 | |||
333 | 10 | num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12); | |
334 |
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) |
335 | ✗ | return AVERROR_INVALIDDATA; | |
336 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10 times.
|
17 | for (uint32_t i = 0; i < num_extra_channels; i++) { |
337 | 7 | ret = jpegxl_read_extra_channel_info(gb, meta, validate); | |
338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
339 | ✗ | return ret; | |
340 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if (get_bits_left(gb) <= 0) |
341 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
342 | } | ||
343 | |||
344 | 10 | xyb_encoded = get_bits1(gb); | |
345 | |||
346 | /* color encoding bundle */ | ||
347 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if (!get_bits1(gb)) { |
348 | ✗ | have_icc_profile = get_bits1(gb); | |
349 | ✗ | color_space = jxl_enum(gb); | |
350 | ✗ | if (color_space > 63 && validate) | |
351 | ✗ | return AVERROR_INVALIDDATA; | |
352 | ✗ | if (!have_icc_profile) { | |
353 | ✗ | if (color_space != JPEGXL_CS_XYB) { | |
354 | ✗ | white_point = jxl_enum(gb); | |
355 | ✗ | if (white_point > 63 && validate) | |
356 | ✗ | return AVERROR_INVALIDDATA; | |
357 | ✗ | if (white_point == JPEGXL_WP_CUSTOM) { | |
358 | /* ux and uy values */ | ||
359 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
360 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
361 | } | ||
362 | ✗ | if (color_space != JPEGXL_CS_GRAY) { | |
363 | /* primaries */ | ||
364 | ✗ | primaries = jxl_enum(gb); | |
365 | ✗ | if (primaries > 63 && validate) | |
366 | ✗ | return AVERROR_INVALIDDATA; | |
367 | ✗ | if (primaries == JPEGXL_PR_CUSTOM) { | |
368 | /* ux/uy values for r,g,b */ | ||
369 | ✗ | for (int i = 0; i < 6; i++) { | |
370 | ✗ | jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21); | |
371 | ✗ | if (get_bits_left(gb) <= 0) | |
372 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
373 | } | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /* transfer characteristics */ | ||
379 | ✗ | if (get_bits1(gb)) { | |
380 | /* gamma */ | ||
381 | ✗ | trc = get_bits(gb, 24); | |
382 | } else { | ||
383 | /* transfer function */ | ||
384 | ✗ | trc = jxl_enum(gb); | |
385 | ✗ | if (trc > 63 && validate) | |
386 | ✗ | return AVERROR_INVALIDDATA; | |
387 | ✗ | trc += (1U << 24); | |
388 | } | ||
389 | |||
390 | /* rendering intent */ | ||
391 | ✗ | if (jxl_enum(gb) > 63 && validate) | |
392 | ✗ | return AVERROR_INVALIDDATA; | |
393 | } | ||
394 | } | ||
395 | |||
396 | /* tone mapping bundle */ | ||
397 |
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)) |
398 | ✗ | skip_bits_long(gb, 16 + 16 + 1 + 16); | |
399 | |||
400 | 10 | ret = jpegxl_skip_extensions(gb); | |
401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (ret < 0) |
402 | ✗ | return ret; | |
403 | } | ||
404 | |||
405 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 3 times.
|
25 | if (meta) { |
406 | 22 | meta->xyb_encoded = xyb_encoded; | |
407 | 22 | meta->have_icc_profile = have_icc_profile; | |
408 | 22 | meta->csp = color_space; | |
409 | 22 | meta->primaries = primaries; | |
410 | 22 | meta->wp = white_point; | |
411 | 22 | meta->trc = trc; | |
412 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
|
22 | if (!meta->bit_depth) |
413 | 14 | meta->bit_depth = 8; | |
414 | 22 | meta->num_extra_channels = num_extra_channels; | |
415 | } | ||
416 | |||
417 | /* default transform */ | ||
418 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | if (!get_bits1(gb)) { |
419 | /* opsin inverse matrix */ | ||
420 | ✗ | if (xyb_encoded && !get_bits1(gb)) | |
421 | ✗ | skip_bits_long(gb, 16 * 16); | |
422 | /* cw_mask and default weights */ | ||
423 | ✗ | if (get_bits1(gb)) | |
424 | ✗ | skip_bits_long(gb, 16 * 15); | |
425 | ✗ | if (get_bits1(gb)) | |
426 | ✗ | skip_bits_long(gb, 16 * 55); | |
427 | ✗ | if (get_bits1(gb)) | |
428 | ✗ | skip_bits_long(gb, 16 * 210); | |
429 | } | ||
430 | |||
431 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if (!have_icc_profile) { |
432 | 25 | int bits_remaining = 7 - ((get_bits_count(gb) - 1) & 0x7); | |
433 |
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)) |
434 | ✗ | return AVERROR_INVALIDDATA; | |
435 | } | ||
436 | |||
437 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | if (get_bits_left(gb) < 0) |
438 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
439 | |||
440 | 25 | return get_bits_count(gb); | |
441 | } | ||
442 | |||
443 | /* | ||
444 | * copies as much of the codestream into the buffer as possible | ||
445 | * pass a shorter buflen to request less | ||
446 | * returns the number of bytes consumed from input, may be greater than input_len | ||
447 | * if the input doesn't end on an ISOBMFF-box boundary | ||
448 | */ | ||
449 | 10 | int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len, | |
450 | uint8_t *buffer, int buflen, int *copied) | ||
451 | { | ||
452 | GetByteContext gb; | ||
453 | 10 | int pos = 0, last_box = 0; | |
454 | 10 | bytestream2_init(&gb, input_buffer, input_len); | |
455 | |||
456 | 19 | while (1) { | |
457 | uint64_t size; | ||
458 | uint32_t tag; | ||
459 | 29 | int head_size = 8; | |
460 | |||
461 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | if (bytestream2_get_bytes_left(&gb) < 8) |
462 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
463 | |||
464 | 29 | size = bytestream2_get_be32(&gb); | |
465 | 29 | tag = bytestream2_get_le32(&gb); | |
466 | |||
467 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 24 times.
|
29 | if (size == 1) { |
468 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | if (bytestream2_get_bytes_left(&gb) < 8) |
469 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
470 | 5 | size = bytestream2_get_be64(&gb); | |
471 | 5 | head_size = 16; | |
472 | } | ||
473 | /* invalid ISOBMFF size */ | ||
474 |
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) |
475 | ✗ | return AVERROR_INVALIDDATA; | |
476 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (size) |
477 | 29 | size -= head_size; | |
478 | |||
479 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
|
29 | if (tag == MKTAG('j','x','l','p')) { |
480 | uint32_t idx; | ||
481 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if (bytestream2_get_bytes_left(&gb) < 4) |
482 | ✗ | return AVERROR_BUFFER_TOO_SMALL; | |
483 | 3 | idx = bytestream2_get_be32(&gb); | |
484 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (idx >= UINT32_C(0x80000000)) |
485 | ✗ | last_box = 1; | |
486 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (size) { |
487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (size <= 4) |
488 | ✗ | return AVERROR_INVALIDDATA; | |
489 | 3 | size -= 4; | |
490 | } | ||
491 | } | ||
492 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
|
29 | if (tag == MKTAG('j','x','l','c')) |
493 | 7 | last_box = 1; | |
494 | |||
495 | /* | ||
496 | * size = 0 means "until EOF". this is legal but uncommon | ||
497 | * here we just set it to the remaining size of the probe buffer | ||
498 | */ | ||
499 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!size) |
500 | ✗ | size = bytestream2_get_bytes_left(&gb); | |
501 | else | ||
502 | 29 | pos += size + head_size; | |
503 | |||
504 |
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')) { |
505 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (size > buflen - *copied) |
506 | 5 | size = buflen - *copied; | |
507 | /* | ||
508 | * arbitrary chunking of the payload makes this memcpy hard to avoid | ||
509 | * in practice this will only be performed one or two times at most | ||
510 | */ | ||
511 | 10 | *copied += bytestream2_get_buffer(&gb, buffer + *copied, size); | |
512 | } else { | ||
513 | 19 | bytestream2_skip(&gb, size); | |
514 | } | ||
515 |
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) |
516 | break; | ||
517 | } | ||
518 | |||
519 | 10 | return pos; | |
520 | } | ||
521 |