diff --git a/libavformat/Makefile b/libavformat/Makefile
index 2b90b788c0..48e1e8ea04 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -283,7 +283,7 @@ OBJS-$(CONFIG_IMAGE_HDR_PIPE_DEMUXER)     += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER)     += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER)    += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER)  += img2dec.o img2.o
-OBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER)  += img2dec.o img2.o jpegxl_probe.o
+OBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER)  += img2dec.o img2.o jpegxl_parse.o
 OBJS-$(CONFIG_IMAGE_PAM_PIPE_DEMUXER)     += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE_PBM_PIPE_DEMUXER)     += img2dec.o img2.o
 OBJS-$(CONFIG_IMAGE_PCX_PIPE_DEMUXER)     += img2dec.o img2.o
@@ -320,7 +320,7 @@ OBJS-$(CONFIG_IVF_MUXER)                 += ivfenc.o
 OBJS-$(CONFIG_IVR_DEMUXER)               += rmdec.o rm.o rmsipr.o
 OBJS-$(CONFIG_JACOSUB_DEMUXER)           += jacosubdec.o subtitles.o
 OBJS-$(CONFIG_JACOSUB_MUXER)             += jacosubenc.o rawenc.o
-OBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER)       += jpegxl_anim_dec.o jpegxl_probe.o
+OBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER)       += jpegxl_anim_dec.o jpegxl_parse.o
 OBJS-$(CONFIG_JV_DEMUXER)                += jvdec.o
 OBJS-$(CONFIG_KUX_DEMUXER)               += flvdec.o
 OBJS-$(CONFIG_KVAG_DEMUXER)              += kvag.o
@@ -715,6 +715,8 @@ SHLIBOBJS                                += log2_tab.o to_upper4.o
 SHLIBOBJS-$(CONFIG_ISO_MEDIA)            += mpegaudiotabs.o
 SHLIBOBJS-$(CONFIG_FLV_MUXER)            += mpeg4audio_sample_rates.o
 SHLIBOBJS-$(CONFIG_HLS_DEMUXER)          += ac3_channel_layout_tab.o
+SHLIBOBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER)    += jpegxl_parse.o
+SHLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER)  += jpegxl_parse.o
 SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER)     += mpeg4audio_sample_rates.o
 SHLIBOBJS-$(CONFIG_MOV_DEMUXER)          += ac3_channel_layout_tab.o
 SHLIBOBJS-$(CONFIG_MP3_MUXER)            += mpegaudiotabs.o
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index b986d3a502..72b2c76405 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -36,7 +36,7 @@
 #include "avio_internal.h"
 #include "internal.h"
 #include "img2.h"
-#include "jpegxl_probe.h"
+#include "libavcodec/jpegxl_parse.h"
 #include "libavcodec/mjpeg.h"
 #include "libavcodec/vbn.h"
 #include "libavcodec/xwd.h"
@@ -850,7 +850,7 @@ static int jpegxl_probe(const AVProbeData *p)
     if (AV_RL16(b) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
         return 0;
 #if CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER
-    if (ff_jpegxl_verify_codestream_header(p->buf, p->buf_size, 1) >= 0)
+    if (ff_jpegxl_parse_codestream_header(p->buf, p->buf_size, 1, NULL) >= 0)
         return AVPROBE_SCORE_MAX - 2;
 #endif
     return 0;
diff --git a/libavformat/jpegxl_anim_dec.c b/libavformat/jpegxl_anim_dec.c
index 956b56c1d8..b178b74ff0 100644
--- a/libavformat/jpegxl_anim_dec.c
+++ b/libavformat/jpegxl_anim_dec.c
@@ -28,96 +28,28 @@
 #include <stdint.h>
 #include <string.h>
 
-#include "libavcodec/bytestream.h"
-#define BITSTREAM_READER_LE
-#include "libavcodec/get_bits.h"
-
+#include "libavcodec/jpegxl.h"
+#include "libavcodec/jpegxl_parse.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/opt.h"
 
 #include "avformat.h"
 #include "internal.h"
-#include "jpegxl_probe.h"
 
 typedef struct JXLAnimDemuxContext {
     AVBufferRef *initial;
 } JXLAnimDemuxContext;
 
-/*
- * copies as much of the codestream into the buffer as possible
- * pass a shorter buflen to request less
- * returns the number of bytes consumed from input, may be greater than input_len
- * if the input doesn't end on an ISOBMFF-box boundary
- */
-static int jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len,
-                                            uint8_t *buffer, int buflen, int *copied) {
-    GetByteContext gb;
-    *copied = 0;
-    bytestream2_init(&gb, input_buffer, input_len);
-
-    while (1) {
-        uint64_t size;
-        uint32_t tag;
-        int head_size = 8;
-
-        if (bytestream2_get_bytes_left(&gb) < 16)
-            break;
-
-        size = bytestream2_get_be32(&gb);
-        if (size == 1) {
-            size = bytestream2_get_be64(&gb);
-            head_size = 16;
-        }
-        /* invalid ISOBMFF size */
-        if (size && size <= head_size)
-            return AVERROR_INVALIDDATA;
-        if (size)
-            size -= head_size;
-
-        tag = bytestream2_get_le32(&gb);
-        if (tag == MKTAG('j', 'x', 'l', 'p')) {
-            if (bytestream2_get_bytes_left(&gb) < 4)
-                break;
-            bytestream2_skip(&gb, 4);
-            if (size) {
-                if (size <= 4)
-                    return AVERROR_INVALIDDATA;
-                size -= 4;
-            }
-        }
-        /*
-         * size = 0 means "until EOF". this is legal but uncommon
-         * here we just set it to the remaining size of the probe buffer
-         */
-        if (!size)
-            size = bytestream2_get_bytes_left(&gb);
-
-        if (tag == MKTAG('j', 'x', 'l', 'c') || tag == MKTAG('j', 'x', 'l', 'p')) {
-            if (size > buflen - *copied)
-                size = buflen - *copied;
-            /*
-             * arbitrary chunking of the payload makes this memcpy hard to avoid
-             * in practice this will only be performed one or two times at most
-             */
-            *copied += bytestream2_get_buffer(&gb, buffer + *copied, size);
-        } else {
-            bytestream2_skip(&gb, size);
-        }
-        if (bytestream2_get_bytes_left(&gb) <= 0 || *copied >= buflen)
-            break;
-    }
-
-    return bytestream2_tell(&gb);
-}
-
 static int jpegxl_anim_probe(const AVProbeData *p)
 {
     uint8_t buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE];
-    int copied;
+    int copied = 0, ret;
+    FFJXLMetadata meta = { 0 };
 
     /* this is a raw codestream */
     if (AV_RL16(p->buf) == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {
-        if (ff_jpegxl_verify_codestream_header(p->buf, p->buf_size, 1) >= 1)
+        ret = ff_jpegxl_parse_codestream_header(p->buf, p->buf_size, 1, &meta);
+        if (ret >= 0 && meta.animation_offset > 0)
             return AVPROBE_SCORE_MAX;
 
         return 0;
@@ -127,10 +59,13 @@ static int jpegxl_anim_probe(const AVProbeData *p)
     if (AV_RL64(p->buf) != FF_JPEGXL_CONTAINER_SIGNATURE_LE)
         return 0;
 
-    if (jpegxl_collect_codestream_header(p->buf, p->buf_size, buffer, sizeof(buffer) - AV_INPUT_BUFFER_PADDING_SIZE, &copied) <= 0 || copied <= 0)
+    if (ff_jpegxl_collect_codestream_header(p->buf, p->buf_size, buffer,
+            sizeof(buffer) - AV_INPUT_BUFFER_PADDING_SIZE, &copied) <= 0
+            || copied <= 0)
         return 0;
 
-    if (ff_jpegxl_verify_codestream_header(buffer, copied, 0) >= 1)
+    ret = ff_jpegxl_parse_codestream_header(buffer, copied, 0, &meta);
+    if (ret >= 0 && meta.animation_offset > 0)
         return AVPROBE_SCORE_MAX;
 
     return 0;
@@ -141,13 +76,10 @@ static int jpegxl_anim_read_header(AVFormatContext *s)
     JXLAnimDemuxContext *ctx = s->priv_data;
     AVIOContext *pb = s->pb;
     AVStream *st;
-    int offset = 0;
     uint8_t head[256 + AV_INPUT_BUFFER_PADDING_SIZE];
     const int sizeofhead = sizeof(head) - AV_INPUT_BUFFER_PADDING_SIZE;
-    int headsize = 0;
-    int ctrl;
-    AVRational tb;
-    GetBitContext gbi, *gb = &gbi;
+    int headsize = 0, ret;
+    FFJXLMetadata meta = { 0 };
 
     uint64_t sig16 = avio_rl16(pb);
     if (sig16 == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {
@@ -167,7 +99,7 @@ static int jpegxl_anim_read_header(AVFormatContext *s)
             return AVERROR_INVALIDDATA;
         avio_skip(pb, 2); // first box always 12 bytes
         while (1) {
-            int copied;
+            int copied = 0;
             uint8_t buf[4096];
             int read = avio_read(pb, buf, sizeof(buf));
             if (read < 0)
@@ -183,7 +115,7 @@ static int jpegxl_anim_read_header(AVFormatContext *s)
                 if (av_buffer_realloc(&ctx->initial, ctx->initial->size + read) < 0)
                     return AVERROR(ENOMEM);
             }
-            jpegxl_collect_codestream_header(buf, read, head + headsize, sizeofhead - headsize, &copied);
+            ff_jpegxl_collect_codestream_header(buf, read, head + headsize, sizeofhead - headsize, &copied);
             memcpy(ctx->initial->data + (ctx->initial->size - read), buf, read);
             headsize += copied;
             if (headsize >= sizeofhead || read < sizeof(buf))
@@ -191,12 +123,9 @@ static int jpegxl_anim_read_header(AVFormatContext *s)
         }
     }
     /* offset in bits of the animation header */
-    offset = ff_jpegxl_verify_codestream_header(head, headsize, 0);
-    if (offset <= 0)
-        return AVERROR_INVALIDDATA;
-    if (init_get_bits8(gb, head, headsize) < 0)
+    ret = ff_jpegxl_parse_codestream_header(head, headsize, 0, &meta);
+    if (ret < 0 || meta.animation_offset <= 0)
         return AVERROR_INVALIDDATA;
-    skip_bits_long(gb, offset);
 
     st = avformat_new_stream(s, NULL);
     if (!st)
@@ -204,11 +133,8 @@ static int jpegxl_anim_read_header(AVFormatContext *s)
 
     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     st->codecpar->codec_id   = AV_CODEC_ID_JPEGXL;
-    ctrl = get_bits(gb, 2);
-    tb.den = (const uint32_t[]){100, 1000, 1, 1}[ctrl] + get_bits_long(gb, (const uint32_t[]){0, 0, 10, 30}[ctrl]);
-    ctrl = get_bits(gb, 2);
-    tb.num = (const uint32_t[]){1, 1001, 1, 1}[ctrl] + get_bits_long(gb, (const uint32_t[]){0, 0, 8, 10}[ctrl]);
-    avpriv_set_pts_info(st, 1, tb.num, tb.den);
+    avpriv_set_pts_info(st, 1, meta.timebase.num, meta.timebase.den);
+    ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
 
     return 0;
 }
@@ -265,7 +191,7 @@ const AVInputFormat ff_jpegxl_anim_demuxer = {
     .read_packet    = jpegxl_anim_read_packet,
     .read_close     = jpegxl_anim_close,
     .flags_internal = FF_FMT_INIT_CLEANUP,
-    .flags          = AVFMT_GENERIC_INDEX,
+    .flags          = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
     .mime_type      = "image/jxl",
     .extensions     = "jxl",
 };
diff --git a/libavformat/jpegxl_probe.h b/libavformat/jpegxl_parse.c
similarity index 55%
rename from libavformat/jpegxl_probe.h
rename to libavformat/jpegxl_parse.c
index 496445fbce..1be5fd716f 100644
--- a/libavformat/jpegxl_probe.h
+++ b/libavformat/jpegxl_parse.c
@@ -1,6 +1,6 @@
 /*
- * Jpeg XL header verification
- * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>
+ * JPEG XL Header Parser
+ * Copyright (c) 2023 Leo Izen <leo.izen@gmail.com>
  *
  * This file is part of FFmpeg.
  *
@@ -19,19 +19,4 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#ifndef AVFORMAT_JPEGXL_PROBE_H
-#define AVFORMAT_JPEGXL_PROBE_H
-
-#include <stdint.h>
-
-#define FF_JPEGXL_CODESTREAM_SIGNATURE_LE 0x0aff
-#define FF_JPEGXL_CONTAINER_SIGNATURE_LE 0x204c584a0c000000
-
-/**
- * @brief verify that a codestream header is valid
- * @return Negative upon error, 0 upon verifying that the codestream is not animated,
- *         and 1 upon verifying that it is animated
- */
-int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen, int validate_level);
-
-#endif /* AVFORMAT_JPEGXL_PROBE_H */
+ #include "libavcodec/jpegxl_parse.c"
diff --git a/libavformat/jpegxl_probe.c b/libavformat/jpegxl_probe.c
deleted file mode 100644
index 88492cb772..0000000000
--- a/libavformat/jpegxl_probe.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Jpeg XL header verification
- * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "jpegxl_probe.h"
-
-#define UNCHECKED_BITSTREAM_READER 0
-#define BITSTREAM_READER_LE
-#include "libavcodec/get_bits.h"
-
-enum JpegXLExtraChannelType {
-    FF_JPEGXL_CT_ALPHA = 0,
-    FF_JPEGXL_CT_DEPTH,
-    FF_JPEGXL_CT_SPOT_COLOR,
-    FF_JPEGXL_CT_SELECTION_MASK,
-    FF_JPEGXL_CT_BLACK,
-    FF_JPEGXL_CT_CFA,
-    FF_JPEGXL_CT_THERMAL,
-    FF_JPEGXL_CT_NON_OPTIONAL = 15,
-    FF_JPEGXL_CT_OPTIONAL
-};
-
-enum JpegXLColorSpace {
-    FF_JPEGXL_CS_RGB = 0,
-    FF_JPEGXL_CS_GRAY,
-    FF_JPEGXL_CS_XYB,
-    FF_JPEGXL_CS_UNKNOWN
-};
-
-enum JpegXLWhitePoint {
-    FF_JPEGXL_WP_D65 = 1,
-    FF_JPEGXL_WP_CUSTOM,
-    FF_JPEGXL_WP_E = 10,
-    FF_JPEGXL_WP_DCI = 11
-};
-
-enum JpegXLPrimaries {
-    FF_JPEGXL_PR_SRGB = 1,
-    FF_JPEGXL_PR_CUSTOM,
-    FF_JPEGXL_PR_2100 = 9,
-    FF_JPEGXL_PR_P3 = 11,
-};
-
-/* read a U32(c_i + u(u_i)) */
-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)
-{
-    const uint32_t constants[4] = {c0, c1, c2, c3};
-    const uint32_t ubits    [4] = {u0, u1, u2, u3};
-    uint32_t ret, choice = get_bits(gb, 2);
-
-    ret = constants[choice];
-    if (ubits[choice])
-        ret += get_bits_long(gb, ubits[choice]);
-
-    return ret;
-}
-
-static av_always_inline uint32_t jxl_enum(GetBitContext *gb)
-{
-    return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
-}
-
-/* read a U64() */
-static uint64_t jpegxl_u64(GetBitContext *gb)
-{
-    uint64_t shift = 12, ret;
-
-    switch (get_bits(gb, 2)) {
-    case 0:
-        ret = 0;
-        break;
-    case 1:
-        ret = 1 + get_bits(gb, 4);
-        break;
-    case 2:
-        ret = 17 + get_bits(gb, 8);
-        break;
-    case 3:
-        ret = get_bits(gb, 12);
-        while (get_bits1(gb)) {
-            if (shift < 60) {
-                ret |= (uint64_t)get_bits(gb, 8) << shift;
-                shift += 8;
-            } else {
-                ret |= (uint64_t)get_bits(gb, 4) << shift;
-                break;
-            }
-        }
-        break;
-    }
-
-    return ret;
-}
-
-static uint32_t jpegxl_width_from_ratio(uint32_t height, int ratio)
-{
-    uint64_t height64 = height; /* avoid integer overflow */
-    switch (ratio) {
-    case 1:
-        return height;
-    case 2:
-        return (uint32_t)((height64 * 12) / 10);
-    case 3:
-        return (uint32_t)((height64 * 4) / 3);
-    case 4:
-        return (uint32_t)((height64 * 3) / 2);
-    case 5:
-        return (uint32_t)((height64 * 16) / 9);
-    case 6:
-        return (uint32_t)((height64 * 5) / 4);
-    case 7:
-        return (uint32_t)(height64 * 2);
-    default:
-        break;
-    }
-
-    return 0; /* manual width */
-}
-
-/**
- * validate a Jpeg XL Size Header
- * @return >= 0 upon valid size, < 0 upon invalid size found
- */
-static int jpegxl_read_size_header(GetBitContext *gb)
-{
-    uint32_t width, height;
-
-    if (get_bits1(gb)) {
-        /* small size header */
-        height = (get_bits(gb, 5) + 1) << 3;
-        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
-        if (!width)
-            width = (get_bits(gb, 5) + 1) << 3;
-    } else {
-        /* large size header */
-        height = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
-        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
-        if (!width)
-            width = 1 + jxl_u32(gb, 0, 0, 0, 0, 9, 13, 18, 30);
-    }
-    if (width > (1 << 18) || height > (1 << 18)
-        || (width >> 4) * (height >> 4) > (1 << 20))
-        return -1;
-
-    return 0;
-}
-
-/**
- * validate a Jpeg XL Preview Header
- * @return >= 0 upon valid size, < 0 upon invalid size found
- */
-static int jpegxl_read_preview_header(GetBitContext *gb)
-{
-    uint32_t width, height;
-
-    if (get_bits1(gb)) {
-        /* coded height and width divided by eight */
-        height = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
-        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
-        if (!width)
-            width = jxl_u32(gb, 16, 32, 1, 33, 0, 0, 5, 9) << 3;
-    } else {
-        /* full height and width coded */
-        height = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
-        width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
-        if (!width)
-            width = jxl_u32(gb, 1, 65, 321, 1345, 6, 8, 10, 12);
-    }
-    if (width > 4096 || height > 4096)
-        return -1;
-
-    return 0;
-}
-
-/**
- * skip a Jpeg XL BitDepth Header. These cannot be invalid.
- */
-static void jpegxl_skip_bit_depth(GetBitContext *gb)
-{
-    if (get_bits1(gb)) {
-        /* float samples */
-        jxl_u32(gb, 32, 16, 24, 1, 0, 0, 0, 6); /* mantissa */
-        skip_bits_long(gb, 4); /* exponent */
-    } else {
-        /* integer samples */
-        jxl_u32(gb, 8, 10, 12, 1, 0, 0, 0, 6);
-    }
-}
-
-/**
- * validate a Jpeg XL Extra Channel Info bundle
- * @return >= 0 upon valid, < 0 upon invalid
- */
-static int jpegxl_read_extra_channel_info(GetBitContext *gb, int validate_level)
-{
-    int all_default = get_bits1(gb);
-    uint32_t type, name_len = 0;
-
-    if (!all_default) {
-        type = jxl_enum(gb);
-        if (type > 63)
-            return -1; /* enum types cannot be 64+ */
-        if (type == FF_JPEGXL_CT_BLACK && validate_level)
-            return -1;
-        jpegxl_skip_bit_depth(gb);
-        jxl_u32(gb, 0, 3, 4, 1, 0, 0, 0, 3); /* dim-shift */
-        /* max of name_len is 1071 = 48 + 2^10 - 1 */
-        name_len = jxl_u32(gb, 0, 0, 16, 48, 0, 4, 5, 10);
-    } else {
-        type = FF_JPEGXL_CT_ALPHA;
-    }
-
-    /* skip over the name */
-    skip_bits_long(gb, 8 * name_len);
-
-    if (!all_default && type == FF_JPEGXL_CT_ALPHA)
-        skip_bits1(gb);
-
-    if (type == FF_JPEGXL_CT_SPOT_COLOR)
-        skip_bits_long(gb, 16 * 4);
-
-    if (type == FF_JPEGXL_CT_CFA)
-        jxl_u32(gb, 1, 0, 3, 19, 0, 2, 4, 8);
-
-    return 0;
-}
-
-int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen, int validate_level)
-{
-    GetBitContext gbi, *gb = &gbi;
-    int all_default, extra_fields = 0;
-    int xyb_encoded = 1, have_icc_profile = 0;
-    int animation_offset = 0;
-    uint32_t num_extra_channels;
-    uint64_t extensions;
-    int ret;
-
-    ret = init_get_bits8(gb, buf, buflen);
-    if (ret < 0)
-        return ret;
-
-    if (get_bits_long(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
-        return -1;
-
-    if ((ret = jpegxl_read_size_header(gb)) < 0 && validate_level)
-        return ret;
-
-    all_default = get_bits1(gb);
-    if (!all_default)
-        extra_fields = get_bits1(gb);
-
-    if (extra_fields) {
-        skip_bits_long(gb, 3); /* orientation */
-
-        /*
-         * intrinstic size
-         * any size header here is valid, but as it
-         * is variable length we have to read it
-         */
-        if (get_bits1(gb))
-            jpegxl_read_size_header(gb);
-
-        /* preview header */
-        if (get_bits1(gb)) {
-            ret = jpegxl_read_preview_header(gb);
-            if (ret < 0)
-                return ret;
-        }
-
-        /* animation header */
-        if (get_bits1(gb)) {
-            animation_offset = get_bits_count(gb);
-            jxl_u32(gb, 100, 1000, 1, 1, 0, 0, 10, 30);
-            jxl_u32(gb, 1, 1001, 1, 1, 0, 0, 8, 10);
-            jxl_u32(gb, 0, 0, 0, 0, 0, 3, 16, 32);
-            skip_bits_long(gb, 1);
-        }
-    }
-    if (get_bits_left(gb) < 1)
-        return AVERROR_INVALIDDATA;
-
-    if (!all_default) {
-        jpegxl_skip_bit_depth(gb);
-
-        /* modular_16bit_buffers must equal 1 */
-        if (!get_bits1(gb) && validate_level)
-            return -1;
-
-        num_extra_channels = jxl_u32(gb, 0, 1, 2, 1, 0, 0, 4, 12);
-        if (num_extra_channels > 4 && validate_level)
-            return -1;
-        for (uint32_t i = 0; i < num_extra_channels; i++) {
-            ret = jpegxl_read_extra_channel_info(gb, validate_level);
-            if (ret < 0)
-                return ret;
-            if (get_bits_left(gb) < 1)
-                return AVERROR_INVALIDDATA;
-        }
-
-        xyb_encoded = get_bits1(gb);
-
-        /* color encoding bundle */
-        if (!get_bits1(gb)) {
-            uint32_t color_space;
-            have_icc_profile = get_bits1(gb);
-            color_space = jxl_enum(gb);
-            if (color_space > 63)
-                return -1;
-
-            if (!have_icc_profile) {
-                if (color_space != FF_JPEGXL_CS_XYB) {
-                    uint32_t white_point = jxl_enum(gb);
-                    if (white_point > 63)
-                        return -1;
-                    if (white_point == FF_JPEGXL_WP_CUSTOM) {
-                        /* ux and uy values */
-                        jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
-                        jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
-                    }
-                    if (color_space != FF_JPEGXL_CS_GRAY) {
-                        /* primaries */
-                        uint32_t primaries = jxl_enum(gb);
-                        if (primaries > 63)
-                            return -1;
-                        if (primaries == FF_JPEGXL_PR_CUSTOM) {
-                            /* ux/uy values for r,g,b */
-                            for (int i = 0; i < 6; i++) {
-                                jxl_u32(gb, 0, 524288, 1048576, 2097152, 19, 19, 20, 21);
-                                if (get_bits_left(gb) < 1)
-                                    return AVERROR_INVALIDDATA;
-                            }
-                        }
-                    }
-                }
-
-                /* transfer characteristics */
-                if (get_bits1(gb)) {
-                    /* gamma */
-                    skip_bits_long(gb, 24);
-                } else {
-                    /* transfer function */
-                    if (jxl_enum(gb) > 63)
-                        return -1;
-                }
-
-                /* rendering intent */
-                if (jxl_enum(gb) > 63)
-                    return -1;
-            }
-        }
-
-        /* tone mapping bundle */
-        if (extra_fields && !get_bits1(gb))
-            skip_bits_long(gb, 16 + 16 + 1 + 16);
-
-        extensions = jpegxl_u64(gb);
-        if (get_bits_left(gb) < 1)
-            return AVERROR_INVALIDDATA;
-        if (extensions) {
-            for (int i = 0; i < 64; i++) {
-                if (extensions & (UINT64_C(1) << i))
-                    jpegxl_u64(gb);
-                if (get_bits_left(gb) < 1)
-                    return AVERROR_INVALIDDATA;
-            }
-        }
-    }
-
-    /* default transform */
-    if (!get_bits1(gb)) {
-        /* opsin inverse matrix */
-        if (xyb_encoded && !get_bits1(gb))
-            skip_bits_long(gb, 16 * 16);
-        /* cw_mask and default weights */
-        if (get_bits1(gb))
-            skip_bits_long(gb, 16 * 15);
-        if (get_bits1(gb))
-            skip_bits_long(gb, 16 * 55);
-        if (get_bits1(gb))
-            skip_bits_long(gb, 16 * 210);
-    }
-
-    if (!have_icc_profile) {
-        int bits_remaining = 7 - (get_bits_count(gb) - 1) % 8;
-        if (bits_remaining && get_bits(gb, bits_remaining))
-            return -1;
-    }
-
-    if (get_bits_left(gb) < 0)
-        return -1;
-
-    return animation_offset;
-}
