[FFmpeg-devel] [PATCH v5 3/4] avformat/jpegxl: remove jpegxl_probe, instead call avcodec/jpegxl_parse

Leo Izen leo.izen at gmail.com
Mon Jul 24 02:58:45 EEST 2023


On 7/23/23 06:08, Andreas Rheinhardt wrote:
> Leo Izen:
>> This prevents code duplication in the source form by calling the parse
>> code that was moved to avcodec last commit. The code will be duplicated
>> in binary form for shared builds (it's not that large), but for source
> 
> How large is it?

Whatever the size of jpegxl_parse.c is, which is about 520 LOC including 
all the comments, and the object file is 174k on my system, including 
debug symbols, and about 13k after stripping.

> 
>> code it will only exist in one location now.
>>
>> Signed-off-by: Leo Izen <leo.izen at gmail.com>
>> ---
>>   libavformat/Makefile                          |   6 +-
>>   libavformat/img2dec.c                         |   4 +-
>>   libavformat/jpegxl_anim_dec.c                 | 115 +----
>>   .../{jpegxl_probe.h => jpegxl_parse.c}        |  21 +-
>>   libavformat/jpegxl_probe.c                    | 412 ------------------
>>   libavformat/version.h                         |   2 +-
>>   6 files changed, 31 insertions(+), 529 deletions(-)
>>   rename libavformat/{jpegxl_probe.h => jpegxl_parse.c} (55%)
>>   delete mode 100644 libavformat/jpegxl_probe.c
>>
>> diff --git a/libavformat/Makefile b/libavformat/Makefile
>> index 4cb00f8700..c6f7457ac5 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
>> @@ -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
> 
> The typical way to do these Makefile dependencies is to add SHLIBOBJS to
> the the dependent library (so that this stuff is included in it for
> shared builds) and to add a STLIBOBJS dependency to the lavc Makefile
> (so that it will be included in libavcodec.a even if nothing in
> libavcodec needs it on its own when making a static build).
> 
> As is it, including jpegxl_parse.o in the dependencies above is
> redundant, because it is already in OBJS.

I have both this dependency SHLIOBJS in lavf and STLIBOBJS in lavc, I 
didn't realize that meant I can remove it from OBJS. I will do that.

> 
>> 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..7d0df3820c 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, &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)
>> -        return AVERROR_INVALIDDATA;
>> -    if (init_get_bits8(gb, head, headsize) < 0)
>> +    ret = ff_jpegxl_parse_codestream_header(head, headsize, &meta, 0);
>> +    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 +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;
>>   }
>> @@ -265,7 +192,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,
> 
> Why this change? Seems unrelated to the commit.
> 
>>       .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 at gmail.com>
>> + * JPEG XL Header Parser
>> + * Copyright (c) 2023 Leo Izen <leo.izen at 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 at 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;
>> -}
>> 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, \
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list