diff --git a/libavformat/Makefile b/libavformat/Makefile index bd78c206b9..f9944baab9 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 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 OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o OBJS-$(CONFIG_KUX_DEMUXER) += flvdec.o OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o @@ -717,6 +717,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..15fd67927f 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, NULL, 5) >= 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..fc95a1781f 100644 --- a/libavformat/jpegxl_anim_dec.c +++ b/libavformat/jpegxl_anim_dec.c @@ -28,96 +28,28 @@ #include #include -#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, &meta, 5); + 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, &meta, 10); + 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,20 +115,18 @@ 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)) break; } } + /* offset in bits of the animation header */ - offset = ff_jpegxl_verify_codestream_header(head, headsize, 0); - if (offset <= 0) + ret = ff_jpegxl_parse_codestream_header(head, headsize, &meta, 0); + if (ret < 0 || meta.animation_offset <= 0) return AVERROR_INVALIDDATA; - if (init_get_bits8(gb, head, headsize) < 0) - return AVERROR_INVALIDDATA; - skip_bits_long(gb, offset); st = avformat_new_stream(s, NULL); if (!st) @@ -204,11 +134,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_FULL; return 0; } @@ -222,17 +149,17 @@ static int jpegxl_anim_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t size; size_t offset = 0; - if ((size = avio_size(pb)) < 0) + size = avio_size(pb); + if (size < 0) return size; - - /* animated JXL this big should not exist */ - if (size > INT_MAX) - return AVERROR_INVALIDDATA; + if (size == 0) + size = 4096; if (ctx->initial && size < ctx->initial->size) size = ctx->initial->size; - if ((ret = av_new_packet(pkt, size)) < 0) + ret = av_new_packet(pkt, size); + if (ret < 0) return ret; if (ctx->initial) { @@ -241,8 +168,11 @@ static int jpegxl_anim_read_packet(AVFormatContext *s, AVPacket *pkt) av_buffer_unref(&ctx->initial); } - if ((ret = avio_read(pb, pkt->data + offset, size - offset)) < 0) + ret = avio_read(pb, pkt->data + offset, size - offset); + if (ret < 0) return ret; + if (ret < size - offset) + pkt->size = ret + offset; return 0; } @@ -265,7 +195,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..e0d4f96204 100644 --- a/libavformat/jpegxl_probe.h +++ b/libavformat/jpegxl_parse.c @@ -1,6 +1,6 @@ /* - * Jpeg XL header verification - * Copyright (c) 2022 Leo Izen + * JPEG XL Header Parser Stub + * Copyright (c) 2023 Leo Izen * * 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 - -#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 - * - * 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; -} diff --git a/libavformat/version.h b/libavformat/version.h index 979952183c..787ee8c90b 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ #include "version_major.h" #define LIBAVFORMAT_VERSION_MINOR 10 -#define LIBAVFORMAT_VERSION_MICRO 100 +#define LIBAVFORMAT_VERSION_MICRO 101 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \