FFmpeg
jpegxl_probe.c
Go to the documentation of this file.
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 UNCHECKED_BITSTREAM_READER 0
25 #define BITSTREAM_READER_LE
26 #include "libavcodec/get_bits.h"
27 
38 };
39 
45 };
46 
52 };
53 
59 };
60 
61 /* read a U32(c_i + u(u_i)) */
63  uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3,
64  uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3)
65 {
66  const uint32_t constants[4] = {c0, c1, c2, c3};
67  const uint32_t ubits [4] = {u0, u1, u2, u3};
68  uint32_t ret, choice = get_bits(gb, 2);
69 
70  ret = constants[choice];
71  if (ubits[choice])
72  ret += get_bits_long(gb, ubits[choice]);
73 
74  return ret;
75 }
76 
78 {
79  return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
80 }
81 
82 /* read a U64() */
83 static uint64_t jpegxl_u64(GetBitContext *gb)
84 {
85  uint64_t shift = 12, ret;
86 
87  switch (get_bits(gb, 2)) {
88  case 0:
89  ret = 0;
90  break;
91  case 1:
92  ret = 1 + get_bits(gb, 4);
93  break;
94  case 2:
95  ret = 17 + get_bits(gb, 8);
96  break;
97  case 3:
98  ret = get_bits(gb, 12);
99  while (get_bits1(gb)) {
100  if (shift < 60) {
101  ret |= (uint64_t)get_bits(gb, 8) << shift;
102  shift += 8;
103  } else {
104  ret |= (uint64_t)get_bits(gb, 4) << shift;
105  break;
106  }
107  }
108  break;
109  }
110 
111  return ret;
112 }
113 
114 static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
115 {
116  uint64_t height64 = height; /* avoid integer overflow */
117  switch (ratio) {
118  case 1:
119  return height;
120  case 2:
121  return (uint32_t)((height64 * 12) / 10);
122  case 3:
123  return (uint32_t)((height64 * 4) / 3);
124  case 4:
125  return (uint32_t)((height64 * 3) / 2);
126  case 5:
127  return (uint32_t)((height64 * 16) / 9);
128  case 6:
129  return (uint32_t)((height64 * 5) / 4);
130  case 7:
131  return (uint32_t)(height64 * 2);
132  default:
133  break;
134  }
135 
136  return 0; /* manual width */
137 }
138 
139 /**
140  * validate a Jpeg XL Size Header
141  * @return >= 0 upon valid size, < 0 upon invalid size found
142  */
144 {
145  uint32_t width, height;
146 
147  if (get_bits1(gb)) {
148  /* small size header */
149  height = (get_bits(gb, 5) + 1) << 3;
151  if (!width)
152  width = (get_bits(gb, 5) + 1) << 3;
153  } else {
154  /* large size header */
155  height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
157  if (!width)
158  width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
159  }
160  if (width > (1 << 18) || height > (1 << 18)
161  || (width >> 4) * (height >> 4) > (1 << 20))
162  return -1;
163 
164  return 0;
165 }
166 
167 /**
168  * validate a Jpeg XL Preview Header
169  * @return >= 0 upon valid size, < 0 upon invalid size found
170  */
172 {
173  uint32_t width, height;
174 
175  if (get_bits1(gb)) {
176  /* coded height and width divided by eight */
177  height = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
179  if (!width)
180  width = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
181  } else {
182  /* full height and width coded */
183  height = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
185  if (!width)
186  width = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
187  }
188  if (width > 4096 || height > 4096)
189  return -1;
190 
191  return 0;
192 }
193 
194 /**
195  * skip a Jpeg XL BitDepth Header. These cannot be invalid.
196  */
198 {
199  if (get_bits1(gb)) {
200  /* float samples */
201  jxl_u32(gb, 32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */
202  skip_bits_long(gb, 4); /* exponent */
203  } else {
204  /* integer samples */
205  jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6);
206  }
207 }
208 
209 /**
210  * validate a Jpeg XL Extra Channel Info bundle
211  * @return >= 0 upon valid, < 0 upon invalid
212  */
213 static int jpegxl_read_extra_channel_info(GetBitContext *gb, int validate_level)
214 {
215  int all_default = get_bits1(gb);
216  uint32_t type, name_len = 0;
217 
218  if (!all_default) {
219  type = jxl_enum(gb);
220  if (type > 63)
221  return -1; /* enum types cannot be 64+ */
222  if (type == FF_JPEGXL_CT_BLACK && validate_level)
223  return -1;
225  jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */
226  /* max of name_len is 1071 = 48 + 2^10 - 1 */
227  name_len = jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10);
228  } else {
230  }
231 
232  /* skip over the name */
233  skip_bits_long(gb, 8 * name_len);
234 
235  if (!all_default && type == FF_JPEGXL_CT_ALPHA)
236  skip_bits1(gb);
237 
239  skip_bits_long(gb, 16 * 4);
240 
241  if (type == FF_JPEGXL_CT_CFA)
242  jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8);
243 
244  return 0;
245 }
246 
247 int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen, int validate_level)
248 {
249  GetBitContext gbi, *gb = &gbi;
250  int all_default, extra_fields = 0;
251  int xyb_encoded = 1, have_icc_profile = 0;
252  int animation_offset = 0;
253  uint32_t num_extra_channels;
254  uint64_t extensions;
255  int ret;
256 
257  ret = init_get_bits8(gb, buf, buflen);
258  if (ret < 0)
259  return ret;
260 
262  return -1;
263 
264  if ((ret = jpegxl_read_size_header(gb)) < 0 && validate_level)
265  return ret;
266 
267  all_default = get_bits1(gb);
268  if (!all_default)
269  extra_fields = get_bits1(gb);
270 
271  if (extra_fields) {
272  skip_bits_long(gb, 3); /* orientation */
273 
274  /*
275  * intrinstic size
276  * any size header here is valid, but as it
277  * is variable length we have to read it
278  */
279  if (get_bits1(gb))
281 
282  /* preview header */
283  if (get_bits1(gb)) {
285  if (ret < 0)
286  return ret;
287  }
288 
289  /* animation header */
290  if (get_bits1(gb)) {
291  animation_offset = get_bits_count(gb);
292  jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30);
293  jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10);
294  jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32);
295  skip_bits_long(gb, 1);
296  }
297  }
298  if (get_bits_left(gb) < 1)
299  return AVERROR_INVALIDDATA;
300 
301  if (!all_default) {
303 
304  /* modular_16bit_buffers must equal 1 */
305  if (!get_bits1(gb) && validate_level)
306  return -1;
307 
308  num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12);
309  if (num_extra_channels > 4 && validate_level)
310  return -1;
311  for (uint32_t i = 0; i < num_extra_channels; i++) {
312  ret = jpegxl_read_extra_channel_info(gb, validate_level);
313  if (ret < 0)
314  return ret;
315  if (get_bits_left(gb) < 1)
316  return AVERROR_INVALIDDATA;
317  }
318 
319  xyb_encoded = get_bits1(gb);
320 
321  /* color encoding bundle */
322  if (!get_bits1(gb)) {
323  uint32_t color_space;
324  have_icc_profile = get_bits1(gb);
325  color_space = jxl_enum(gb);
326  if (color_space > 63)
327  return -1;
328 
329  if (!have_icc_profile) {
330  if (color_space != FF_JPEGXL_CS_XYB) {
331  uint32_t white_point = jxl_enum(gb);
332  if (white_point > 63)
333  return -1;
334  if (white_point == FF_JPEGXL_WP_CUSTOM) {
335  /* ux and uy values */
336  jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
337  jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
338  }
339  if (color_space != FF_JPEGXL_CS_GRAY) {
340  /* primaries */
341  uint32_t primaries = jxl_enum(gb);
342  if (primaries > 63)
343  return -1;
345  /* ux/uy values for r,g,b */
346  for (int i = 0; i < 6; i++) {
347  jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
348  if (get_bits_left(gb) < 1)
349  return AVERROR_INVALIDDATA;
350  }
351  }
352  }
353  }
354 
355  /* transfer characteristics */
356  if (get_bits1(gb)) {
357  /* gamma */
358  skip_bits_long(gb, 24);
359  } else {
360  /* transfer function */
361  if (jxl_enum(gb) > 63)
362  return -1;
363  }
364 
365  /* rendering intent */
366  if (jxl_enum(gb) > 63)
367  return -1;
368  }
369  }
370 
371  /* tone mapping bundle */
372  if (extra_fields && !get_bits1(gb))
373  skip_bits_long(gb, 16 + 16 + 1 + 16);
374 
375  extensions = jpegxl_u64(gb);
376  if (get_bits_left(gb) < 1)
377  return AVERROR_INVALIDDATA;
378  if (extensions) {
379  for (int i = 0; i < 64; i++) {
380  if (extensions & (UINT64_C(1) << i))
381  jpegxl_u64(gb);
382  if (get_bits_left(gb) < 1)
383  return AVERROR_INVALIDDATA;
384  }
385  }
386  }
387 
388  /* default transform */
389  if (!get_bits1(gb)) {
390  /* opsin inverse matrix */
391  if (xyb_encoded && !get_bits1(gb))
392  skip_bits_long(gb, 16 * 16);
393  /* cw_mask and default weights */
394  if (get_bits1(gb))
395  skip_bits_long(gb, 16 * 15);
396  if (get_bits1(gb))
397  skip_bits_long(gb, 16 * 55);
398  if (get_bits1(gb))
399  skip_bits_long(gb, 16 * 210);
400  }
401 
402  if (!have_icc_profile) {
403  int bits_remaining = 7 - (get_bits_count(gb) - 1) % 8;
404  if (bits_remaining && get_bits(gb, bits_remaining))
405  return -1;
406  }
407 
408  if (get_bits_left(gb) < 0)
409  return -1;
410 
411  return animation_offset;
412 }
JpegXLColorSpace
JpegXLColorSpace
Definition: jpegxl_probe.c:40
FF_JPEGXL_PR_SRGB
@ FF_JPEGXL_PR_SRGB
Definition: jpegxl_probe.c:55
skip_bits_long
static void skip_bits_long(GetBitContext *s, int n)
Skips the specified number of bits.
Definition: get_bits.h:268
jxl_u32
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)
Definition: jpegxl_probe.c:62
get_bits_left
static int get_bits_left(GetBitContext *gb)
Definition: get_bits.h:664
FF_JPEGXL_CS_XYB
@ FF_JPEGXL_CS_XYB
Definition: jpegxl_probe.c:43
jpegxl_u64
static uint64_t jpegxl_u64(GetBitContext *gb)
Definition: jpegxl_probe.c:83
FF_JPEGXL_PR_P3
@ FF_JPEGXL_PR_P3
Definition: jpegxl_probe.c:58
get_bits_long
static unsigned int get_bits_long(GetBitContext *s, int n)
Read 0-32 bits.
Definition: get_bits.h:411
get_bits_count
static int get_bits_count(const GetBitContext *s)
Definition: get_bits.h:256
JpegXLExtraChannelType
JpegXLExtraChannelType
Definition: jpegxl_probe.c:28
FF_JPEGXL_CS_UNKNOWN
@ FF_JPEGXL_CS_UNKNOWN
Definition: jpegxl_probe.c:44
constants
static const struct @328 constants[]
JpegXLWhitePoint
JpegXLWhitePoint
Definition: jpegxl_probe.c:47
FF_JPEGXL_CT_THERMAL
@ FF_JPEGXL_CT_THERMAL
Definition: jpegxl_probe.c:35
JpegXLPrimaries
JpegXLPrimaries
Definition: jpegxl_probe.c:54
c1
static const uint64_t c1
Definition: murmur3.c:51
jpegxl_probe.h
primaries
enum AVColorPrimaries primaries
Definition: mediacodec_wrapper.c:2664
get_bits
static unsigned int get_bits(GetBitContext *s, int n)
Read 1-25 bits.
Definition: get_bits.h:325
jpegxl_skip_bit_depth
static void jpegxl_skip_bit_depth(GetBitContext *gb)
skip a Jpeg XL BitDepth Header.
Definition: jpegxl_probe.c:197
FF_JPEGXL_CT_DEPTH
@ FF_JPEGXL_CT_DEPTH
Definition: jpegxl_probe.c:30
FF_JPEGXL_CT_BLACK
@ FF_JPEGXL_CT_BLACK
Definition: jpegxl_probe.c:33
GetBitContext
Definition: get_bits.h:107
FF_JPEGXL_CS_RGB
@ FF_JPEGXL_CS_RGB
Definition: jpegxl_probe.c:41
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
FF_JPEGXL_CT_SPOT_COLOR
@ FF_JPEGXL_CT_SPOT_COLOR
Definition: jpegxl_probe.c:31
init_get_bits8
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition: get_bits.h:524
width
#define width
FF_JPEGXL_CT_ALPHA
@ FF_JPEGXL_CT_ALPHA
Definition: jpegxl_probe.c:29
ff_jpegxl_verify_codestream_header
int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen, int validate_level)
verify that a codestream header is valid
Definition: jpegxl_probe.c:247
get_bits.h
FF_JPEGXL_CT_CFA
@ FF_JPEGXL_CT_CFA
Definition: jpegxl_probe.c:34
FF_JPEGXL_WP_CUSTOM
@ FF_JPEGXL_WP_CUSTOM
Definition: jpegxl_probe.c:49
get_bits1
static unsigned int get_bits1(GetBitContext *s)
Definition: get_bits.h:378
FF_JPEGXL_WP_D65
@ FF_JPEGXL_WP_D65
Definition: jpegxl_probe.c:48
shift
static int shift(int a, int b)
Definition: bonk.c:262
FF_JPEGXL_CT_SELECTION_MASK
@ FF_JPEGXL_CT_SELECTION_MASK
Definition: jpegxl_probe.c:32
height
#define height
skip_bits1
static void skip_bits1(GetBitContext *s)
Definition: get_bits.h:403
FF_JPEGXL_CT_OPTIONAL
@ FF_JPEGXL_CT_OPTIONAL
Definition: jpegxl_probe.c:37
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:270
FF_JPEGXL_WP_E
@ FF_JPEGXL_WP_E
Definition: jpegxl_probe.c:50
av_always_inline
#define av_always_inline
Definition: attributes.h:49
jpegxl_read_extra_channel_info
static int jpegxl_read_extra_channel_info(GetBitContext *gb, int validate_level)
validate a Jpeg XL Extra Channel Info bundle
Definition: jpegxl_probe.c:213
jpegxl_read_size_header
static int jpegxl_read_size_header(GetBitContext *gb)
validate a Jpeg XL Size Header
Definition: jpegxl_probe.c:143
FF_JPEGXL_PR_CUSTOM
@ FF_JPEGXL_PR_CUSTOM
Definition: jpegxl_probe.c:56
FF_JPEGXL_PR_2100
@ FF_JPEGXL_PR_2100
Definition: jpegxl_probe.c:57
ret
ret
Definition: filter_design.txt:187
c2
static const uint64_t c2
Definition: murmur3.c:52
FF_JPEGXL_CODESTREAM_SIGNATURE_LE
#define FF_JPEGXL_CODESTREAM_SIGNATURE_LE
Definition: jpegxl_probe.h:27
jpegxl_read_preview_header
static int jpegxl_read_preview_header(GetBitContext *gb)
validate a Jpeg XL Preview Header
Definition: jpegxl_probe.c:171
jpegxl_width_from_ratio
static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
Definition: jpegxl_probe.c:114
FF_JPEGXL_CS_GRAY
@ FF_JPEGXL_CS_GRAY
Definition: jpegxl_probe.c:42
FF_JPEGXL_CT_NON_OPTIONAL
@ FF_JPEGXL_CT_NON_OPTIONAL
Definition: jpegxl_probe.c:36
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
FF_JPEGXL_WP_DCI
@ FF_JPEGXL_WP_DCI
Definition: jpegxl_probe.c:51
jxl_enum
static av_always_inline uint32_t jxl_enum(GetBitContext *gb)
Definition: jpegxl_probe.c:77