FFmpeg
Loading...
Searching...
No Matches
jpegxl_parse.c
Go to the documentation of this file.
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)) */
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 const uint32_t constants[4] = {c0, c1, c2, c3};
37 const uint32_t ubits [4] = {u0, u1, u2, u3};
38 uint32_t ret, choice = get_bits(gb, 2);
39
40 ret = constants[choice];
41 if (ubits[choice])
42 ret += get_bits_long(gb, ubits[choice]);
43
44 return ret;
45}
46
48{
49 return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
50}
51
52/* read a U64() */
53static uint64_t jxl_u64(GetBitContext *gb)
54{
55 uint64_t shift = 12, ret;
56
57 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 default:
77 ret = 0;
78 }
79
80 return ret;
81}
82
83static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
84{
85 uint64_t height64 = height; /* avoid integer overflow */
86 switch (ratio) {
87 case 1:
88 return height;
89 case 2:
90 return (uint32_t)((height64 * 12) / 10);
91 case 3:
92 return (uint32_t)((height64 * 4) / 3);
93 case 4:
94 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 default:
102 break;
103 }
104
105 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 */
112static int jpegxl_read_size_header(GetBitContext *gb, FFJXLMetadata *meta, int validate)
113{
114 uint32_t width, height;
115
116 if (get_bits1(gb)) {
117 /* small size header */
118 height = (get_bits(gb, 5) + 1) << 3;
120 if (!width)
121 width = (get_bits(gb, 5) + 1) << 3;
122 } else {
123 /* large size header */
124 height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
126 if (!width)
127 width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
128 }
129 if (validate && (width > (1 << 18) || height > (1 << 18)
130 || (width >> 4) * (height >> 4) > (1 << 20)))
131 return AVERROR_INVALIDDATA;
132
133 if (meta) {
134 meta->width = meta->coded_width = width;
135 meta->height = meta->coded_height = height;
136 }
137
138 return 0;
139}
140
141/**
142 * validate a Jpeg XL Preview Header
143 * @return >= 0 upon valid size, < 0 upon invalid size found
144 */
145static 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;
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);
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 */
172{
173 int bit_depth;
174 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 bit_depth = jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6);
181 }
182 if (meta)
183 meta->bit_depth = bit_depth;
184}
185
186/**
187 * validate a Jpeg XL Extra Channel Info bundle
188 * @return >= 0 upon valid, < 0 upon invalid
189 */
191{
192 int default_alpha = get_bits1(gb);
193 int alpha_associated = 0;
194 uint32_t type, name_len = 0;
195
196 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;
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 {
208 }
209
210 if (get_bits_left(gb) < name_len)
212
213 /* skip over the name */
214 skip_bits_long(gb, name_len);
215
216 if (!default_alpha && type == JPEGXL_CT_ALPHA)
217 alpha_associated = get_bits1(gb);
218
220 skip_bits_long(gb, 16 * 4);
221
222 if (type == JPEGXL_CT_CFA)
223 jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8);
224
225 if (meta && type == JPEGXL_CT_ALPHA) {
226 meta->have_alpha = 1;
227 meta->alpha_associated = alpha_associated;
228 }
229
230 return 0;
231}
232
234{
235 uint64_t extensions = jxl_u64(gb), extensions_len = 0;
236
237 if (get_bits_left(gb) <= 0)
239
240 if (!extensions)
241 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)
248 }
249
250 if (extensions_len > INT_MAX || get_bits_left(gb) <= extensions_len)
252
253 skip_bits_long(gb, extensions_len);
254
255 return 0;
256}
257
258int ff_jpegxl_parse_codestream_header(const uint8_t *buf, int buflen, FFJXLMetadata *meta, int validate)
259{
260 GetBitContext gbi, *gb = &gbi;
261
262 int all_default, extra_fields = 0;
263 int xyb_encoded = 1, have_icc_profile = 0;
264 int animation_offset = 0, have_timecodes = 0;
265
268 FFJXLWhitePoint white_point = JPEGXL_WP_D65;
269 FFJXLColorSpace color_space = JPEGXL_CS_RGB;
270
271 AVRational tb;
272 uint32_t num_extra_channels = 0;
273 int ret;
274
275 ret = init_get_bits8(gb, buf, buflen);
276 if (ret < 0)
277 return ret;
278
279 if (get_bits(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE && validate)
280 return AVERROR_INVALIDDATA;
281
282 ret = jpegxl_read_size_header(gb, meta, validate);
283 if (ret < 0)
284 return ret;
285
286 all_default = get_bits1(gb);
287 if (!all_default)
288 extra_fields = get_bits1(gb);
289
290 if (extra_fields) {
291 int orientation = get_bits(gb, 3);
292 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 if (get_bits1(gb))
302
303 /* preview header */
304 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 if (get_bits1(gb)) {
312 animation_offset = get_bits_count(gb);
313 tb.den = jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30);
314 tb.num = jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10);
315 jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32);
316 have_timecodes = get_bits1(gb);
317 }
318 }
319
320 if (animation_offset && meta) {
321 meta->animation_offset = animation_offset;
322 meta->timebase = tb;
323 meta->have_timecodes = have_timecodes;
324 }
325
326 if (get_bits_left(gb) <= 0)
328
329 if (!all_default) {
330 jpegxl_get_bit_depth(gb, meta);
331
332 /* modular_16bit_buffers must equal 1 */
333 if (!get_bits1(gb) && validate && validate < 10)
334 return AVERROR_INVALIDDATA;
335
336 num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12);
337 if (num_extra_channels > 4 && validate && validate < 10)
338 return AVERROR_INVALIDDATA;
339 for (uint32_t i = 0; i < num_extra_channels; i++) {
340 ret = jpegxl_read_extra_channel_info(gb, meta, validate);
341 if (ret < 0)
342 return ret;
343 if (get_bits_left(gb) <= 0)
345 }
346
347 xyb_encoded = get_bits1(gb);
348
349 /* color encoding bundle */
350 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;
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)
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 if (extra_fields && !get_bits1(gb))
401 skip_bits_long(gb, 16 + 16 + 1 + 16);
402
403 ret = jpegxl_skip_extensions(gb);
404 if (ret < 0)
405 return ret;
406 }
407
408 if (meta) {
409 meta->xyb_encoded = xyb_encoded;
410 meta->have_icc_profile = have_icc_profile;
411 meta->csp = color_space;
412 meta->primaries = primaries;
413 meta->wp = white_point;
414 meta->trc = trc;
415 if (!meta->bit_depth)
416 meta->bit_depth = 8;
417 meta->num_extra_channels = num_extra_channels;
418 }
419
420 /* default transform */
421 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 if (!have_icc_profile) {
435 int bits_remaining = 7 - ((get_bits_count(gb) - 1) & 0x7);
436 if (bits_remaining && get_bits(gb, bits_remaining))
437 return AVERROR_INVALIDDATA;
438 }
439
440 if (get_bits_left(gb) < 0)
442
443 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 */
452int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len,
453 uint8_t *buffer, int buflen, int *copied)
454{
456 int64_t pos = 0;
457 int last_box = 0;
458 bytestream2_init(&gb, input_buffer, input_len);
459
460 while (1) {
461 uint64_t size;
462 uint32_t tag;
463 int head_size = 8;
464
465 if (bytestream2_get_bytes_left(&gb) < 8)
467
468 size = bytestream2_get_be32(&gb);
469 tag = bytestream2_get_le32(&gb);
470
471 if (size == 1) {
472 if (bytestream2_get_bytes_left(&gb) < 8)
474 size = bytestream2_get_be64(&gb);
475 head_size = 16;
476 }
477 /* invalid ISOBMFF size */
478 if (size && size <= head_size)
479 return AVERROR_INVALIDDATA;
480 if (size)
481 size -= head_size;
482
483 if (tag == MKTAG('j','x','l','p')) {
484 uint32_t idx;
485 if (bytestream2_get_bytes_left(&gb) < 4)
487 idx = bytestream2_get_be32(&gb);
488 if (idx >= UINT32_C(0x80000000))
489 last_box = 1;
490 if (size) {
491 if (size <= 4)
492 return AVERROR_INVALIDDATA;
493 size -= 4;
494 }
495 }
496 if (tag == MKTAG('j','x','l','c'))
497 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 if (!size)
505 else
506 pos += size + head_size;
507
508 if (tag == MKTAG('j','x','l','c') || tag == MKTAG('j','x','l','p')) {
509 if (size > buflen - *copied)
510 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 *copied += bytestream2_get_buffer(&gb, buffer + *copied, size);
516 } else {
518 }
519 if (last_box || bytestream2_get_bytes_left(&gb) <= 0 || *copied >= buflen)
520 break;
521 }
522
523 return FFMIN(pos, INT_MAX);
524}
static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth)
Definition af_astats.c:246
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition bytestream.h:267
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition bytestream.h:158
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition bytestream.h:137
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition bytestream.h:168
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static const struct @033145243110221005363036244076252070150076110330 constants[]
bitstream reader API header.
static unsigned int get_bits_long(GetBitContext *s, int n)
Read 0-32 bits.
Definition get_bits.h:424
static int get_bits_left(GetBitContext *gb)
Definition get_bits.h:688
static void skip_bits_long(GetBitContext *s, int n)
Skips the specified number of bits.
Definition get_bits.h:280
static unsigned int get_bits1(GetBitContext *s)
Definition get_bits.h:391
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition get_bits.h:544
static int get_bits_count(const GetBitContext *s)
Definition get_bits.h:254
static unsigned int get_bits(GetBitContext *s, int n)
Read 1-25 bits.
Definition get_bits.h:337
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition error.h:53
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
cl_device_type type
FFJXLWhitePoint
Definition jpegxl.h:69
@ JPEGXL_WP_CUSTOM
Definition jpegxl.h:71
@ JPEGXL_WP_D65
Definition jpegxl.h:70
FFJXLPrimaries
Definition jpegxl.h:76
@ JPEGXL_PR_SRGB
Definition jpegxl.h:77
@ JPEGXL_PR_CUSTOM
Definition jpegxl.h:78
FFJXLColorSpace
Definition jpegxl.h:62
@ JPEGXL_CS_RGB
Definition jpegxl.h:63
@ JPEGXL_CS_GRAY
Definition jpegxl.h:64
@ JPEGXL_CS_XYB
Definition jpegxl.h:65
@ JPEGXL_CT_SPOT_COLOR
Definition jpegxl.h:53
@ JPEGXL_CT_CFA
Definition jpegxl.h:56
@ JPEGXL_CT_ALPHA
Definition jpegxl.h:51
@ JPEGXL_CT_BLACK
Definition jpegxl.h:55
FFJXLTransferCharacteristic
Definition jpegxl.h:83
@ JPEGXL_TR_SRGB
Definition jpegxl.h:87
#define FF_JPEGXL_CODESTREAM_SIGNATURE_LE
Definition jpegxl.h:25
static int shift(int a, int b)
Definition bonk.c:261
static int jpegxl_read_extra_channel_info(GetBitContext *gb, FFJXLMetadata *meta, int validate)
validate a Jpeg XL Extra Channel Info bundle
static av_always_inline uint32_t jxl_u32(GetBitContext *gb, uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3)
static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
static int jpegxl_read_preview_header(GetBitContext *gb, int validate)
validate a Jpeg XL Preview Header
static int jpegxl_read_size_header(GetBitContext *gb, FFJXLMetadata *meta, int validate)
validate a Jpeg XL Size Header
static uint64_t jxl_u64(GetBitContext *gb)
int ff_jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len, uint8_t *buffer, int buflen, int *copied)
static void jpegxl_get_bit_depth(GetBitContext *gb, FFJXLMetadata *meta)
get a Jpeg XL BitDepth Header.
int ff_jpegxl_parse_codestream_header(const uint8_t *buf, int buflen, FFJXLMetadata *meta, int validate)
static int jpegxl_skip_extensions(GetBitContext *gb)
static av_always_inline uint32_t jxl_enum(GetBitContext *gb)
#define av_always_inline
Definition attributes.h:72
#define FFSWAP(type, a, b)
Definition macros.h:52
#define FFMIN(a, b)
Definition macros.h:49
#define MKTAG(a, b, c, d)
Definition macros.h:55
enum AVColorPrimaries primaries
uint32_t tag
Definition movenc.c:2073
static const uint64_t c2
Definition murmur3.c:53
static const uint64_t c1
Definition murmur3.c:52
unsigned int pos
Definition spdifenc.c:431
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
uint32_t height
uint32_t coded_width
uint32_t num_extra_channels
uint32_t width
FFJXLWhitePoint wp
AVRational timebase
FFJXLPrimaries primaries
uint32_t coded_height
FFJXLTransferCharacteristic trc
FFJXLColorSpace csp
static char buffer[20]
Definition seek.c:32
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
int size