History

avformat/jpegxl: remove jpegxl_probe, instead call avcodec/jpegxl_parse

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 code it will only exist in one location now.

Leo Izen committed 3 years ago

Commit e8a63b41 parent 0c0dd236 files · +41 −536Browse files

Showing the changes to libavformat (6 of 6 files). Show all

Unified · Split

6 files
  1. libavformat/Makefile +4 −2
  2. libavformat/img2dec.c +2 −2
  3. libavformat/jpegxl_anim_dec.c +31 −101
  4. libavformat/jpegxl_parse.c +3 −18
  5. libavformat/jpegxl_probe.c +0 −412
  6. libavformat/version.h +1 −1
libavformat/Makefile+4−2
@@ -283,7 +283,7 @@ OBJS-$(CONFIG_IMAGE_HDR_PIPE_DEMUXER) += img2dec.o img2.o · 282 unmodified lines
283OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o283OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o
284OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER) += img2dec.o img2.o284OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER) += img2dec.o img2.o
285OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER) += img2dec.o img2.o285OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER) += img2dec.o img2.o
286OBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER) += img2dec.o img2.o jpegxl_probe.o286OBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER) += img2dec.o img2.o
287OBJS-$(CONFIG_IMAGE_PAM_PIPE_DEMUXER) += img2dec.o img2.o287OBJS-$(CONFIG_IMAGE_PAM_PIPE_DEMUXER) += img2dec.o img2.o
288OBJS-$(CONFIG_IMAGE_PBM_PIPE_DEMUXER) += img2dec.o img2.o288OBJS-$(CONFIG_IMAGE_PBM_PIPE_DEMUXER) += img2dec.o img2.o
289OBJS-$(CONFIG_IMAGE_PCX_PIPE_DEMUXER) += img2dec.o img2.o289OBJS-$(CONFIG_IMAGE_PCX_PIPE_DEMUXER) += img2dec.o img2.o
@@ -320,7 +320,7 @@ OBJS-$(CONFIG_IVF_MUXER) += ivfenc.o · 30 unmodified lines
320OBJS-$(CONFIG_IVR_DEMUXER) += rmdec.o rm.o rmsipr.o320OBJS-$(CONFIG_IVR_DEMUXER) += rmdec.o rm.o rmsipr.o
321OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o321OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o
322OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o322OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o
323OBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_anim_dec.o jpegxl_probe.o323OBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_anim_dec.o
324OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o324OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o
325OBJS-$(CONFIG_KUX_DEMUXER) += flvdec.o325OBJS-$(CONFIG_KUX_DEMUXER) += flvdec.o
326OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o326OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o
@@ -717,6 +717,8 @@ SHLIBOBJS += log2_tab.o to_upper4.o · 390 unmodified lines
717SHLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o717SHLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o
718SHLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o718SHLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o
719SHLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o719SHLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o
720SHLIBOBJS-$(CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER) += jpegxl_parse.o
721SHLIBOBJS-$(CONFIG_JPEGXL_ANIM_DEMUXER) += jpegxl_parse.o
720SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o722SHLIBOBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio_sample_rates.o
721SHLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o723SHLIBOBJS-$(CONFIG_MOV_DEMUXER) += ac3_channel_layout_tab.o
722SHLIBOBJS-$(CONFIG_MP3_MUXER) += mpegaudiotabs.o724SHLIBOBJS-$(CONFIG_MP3_MUXER) += mpegaudiotabs.o
libavformat/img2dec.c+2−2
@@ -36,7 +36,7 @@ · 35 unmodified lines
36#include "avio_internal.h"36#include "avio_internal.h"
37#include "internal.h"37#include "internal.h"
38#include "img2.h"38#include "img2.h"
39#include "jpegxl_probe.h"39#include "libavcodec/jpegxl_parse.h"
40#include "libavcodec/mjpeg.h"40#include "libavcodec/mjpeg.h"
41#include "libavcodec/vbn.h"41#include "libavcodec/vbn.h"
42#include "libavcodec/xwd.h"42#include "libavcodec/xwd.h"
@@ -850,7 +850,7 @@ static int jpegxl_probe(const AVProbeData *p) · 807 unmodified lines
850 if (AV_RL16(b) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)850 if (AV_RL16(b) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
851 return 0;851 return 0;
852#if CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER852#if CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER
853 if (ff_jpegxl_verify_codestream_header(p->buf, p->buf_size, 1) >= 0)853 if (ff_jpegxl_parse_codestream_header(p->buf, p->buf_size, NULL, 5) >= 0)
854 return AVPROBE_SCORE_MAX - 2;854 return AVPROBE_SCORE_MAX - 2;
855#endif855#endif
856 return 0;856 return 0;
libavformat/jpegxl_anim_dec.c+31−101
@@ -28,96 +28,28 @@ · 27 unmodified lines
28#include <stdint.h>28#include <stdint.h>
29#include <string.h>29#include <string.h>
30 30
31#include "libavcodec/bytestream.h"31#include "libavcodec/jpegxl.h"
32#define BITSTREAM_READER_LE32#include "libavcodec/jpegxl_parse.h"
33#include "libavcodec/get_bits.h"
34
35#include "libavutil/intreadwrite.h"33#include "libavutil/intreadwrite.h"
36#include "libavutil/opt.h"34#include "libavutil/opt.h"
37 35
38#include "avformat.h"36#include "avformat.h"
39#include "internal.h"37#include "internal.h"
40#include "jpegxl_probe.h"
41 38
42typedef struct JXLAnimDemuxContext {39typedef struct JXLAnimDemuxContext {
43 AVBufferRef *initial;40 AVBufferRef *initial;
44} JXLAnimDemuxContext;41} JXLAnimDemuxContext;
45 42
46/*
47 * copies as much of the codestream into the buffer as possible
48 * pass a shorter buflen to request less
49 * returns the number of bytes consumed from input, may be greater than input_len
50 * if the input doesn't end on an ISOBMFF-box boundary
51 */
52static int jpegxl_collect_codestream_header(const uint8_t *input_buffer, int input_len,
53 uint8_t *buffer, int buflen, int *copied) {
54 GetByteContext gb;
55 *copied = 0;
56 bytestream2_init(&gb, input_buffer, input_len);
57
58 while (1) {
59 uint64_t size;
60 uint32_t tag;
61 int head_size = 8;
62
63 if (bytestream2_get_bytes_left(&gb) < 16)
64 break;
65
66 size = bytestream2_get_be32(&gb);
67 if (size == 1) {
68 size = bytestream2_get_be64(&gb);
69 head_size = 16;
70 }
71 /* invalid ISOBMFF size */
72 if (size && size <= head_size)
73 return AVERROR_INVALIDDATA;
74 if (size)
75 size -= head_size;
76
77 tag = bytestream2_get_le32(&gb);
78 if (tag == MKTAG('j', 'x', 'l', 'p')) {
79 if (bytestream2_get_bytes_left(&gb) < 4)
80 break;
81 bytestream2_skip(&gb, 4);
82 if (size) {
83 if (size <= 4)
84 return AVERROR_INVALIDDATA;
85 size -= 4;
86 }
87 }
88 /*
89 * size = 0 means "until EOF". this is legal but uncommon
90 * here we just set it to the remaining size of the probe buffer
91 */
92 if (!size)
93 size = bytestream2_get_bytes_left(&gb);
94
95 if (tag == MKTAG('j', 'x', 'l', 'c') || tag == MKTAG('j', 'x', 'l', 'p')) {
96 if (size > buflen - *copied)
97 size = buflen - *copied;
98 /*
99 * arbitrary chunking of the payload makes this memcpy hard to avoid
100 * in practice this will only be performed one or two times at most
101 */
102 *copied += bytestream2_get_buffer(&gb, buffer + *copied, size);
103 } else {
104 bytestream2_skip(&gb, size);
105 }
106 if (bytestream2_get_bytes_left(&gb) <= 0 || *copied >= buflen)
107 break;
108 }
109
110 return bytestream2_tell(&gb);
111}
112
113static int jpegxl_anim_probe(const AVProbeData *p)43static int jpegxl_anim_probe(const AVProbeData *p)
114{44{
115 uint8_t buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE];45 uint8_t buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE];
116 int copied;46 int copied = 0, ret;
47 FFJXLMetadata meta = { 0 };
117 48
118 /* this is a raw codestream */49 /* this is a raw codestream */
119 if (AV_RL16(p->buf) == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {50 if (AV_RL16(p->buf) == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {
120 if (ff_jpegxl_verify_codestream_header(p->buf, p->buf_size, 1) >= 1)51 ret = ff_jpegxl_parse_codestream_header(p->buf, p->buf_size, &meta, 5);
52 if (ret >= 0 && meta.animation_offset > 0)
121 return AVPROBE_SCORE_MAX;53 return AVPROBE_SCORE_MAX;
122 54
123 return 0;55 return 0;
@@ -127,10 +59,13 @@ static int jpegxl_anim_probe(const AVProbeData *p) · 3 unmodified lines
127 if (AV_RL64(p->buf) != FF_JPEGXL_CONTAINER_SIGNATURE_LE)59 if (AV_RL64(p->buf) != FF_JPEGXL_CONTAINER_SIGNATURE_LE)
128 return 0;60 return 0;
129 61
130 if (jpegxl_collect_codestream_header(p->buf, p->buf_size, buffer, sizeof(buffer) - AV_INPUT_BUFFER_PADDING_SIZE, &copied) <= 0 || copied <= 0)62 if (ff_jpegxl_collect_codestream_header(p->buf, p->buf_size, buffer,
63 sizeof(buffer) - AV_INPUT_BUFFER_PADDING_SIZE, &copied) <= 0
64 || copied <= 0)
131 return 0;65 return 0;
132 66
133 if (ff_jpegxl_verify_codestream_header(buffer, copied, 0) >= 1)67 ret = ff_jpegxl_parse_codestream_header(buffer, copied, &meta, 10);
68 if (ret >= 0 && meta.animation_offset > 0)
134 return AVPROBE_SCORE_MAX;69 return AVPROBE_SCORE_MAX;
135 70
136 return 0;71 return 0;
@@ -141,13 +76,10 @@ static int jpegxl_anim_read_header(AVFormatContext *s) · 4 unmodified lines
141 JXLAnimDemuxContext *ctx = s->priv_data;76 JXLAnimDemuxContext *ctx = s->priv_data;
142 AVIOContext *pb = s->pb;77 AVIOContext *pb = s->pb;
143 AVStream *st;78 AVStream *st;
144 int offset = 0;
145 uint8_t head[256 + AV_INPUT_BUFFER_PADDING_SIZE];79 uint8_t head[256 + AV_INPUT_BUFFER_PADDING_SIZE];
146 const int sizeofhead = sizeof(head) - AV_INPUT_BUFFER_PADDING_SIZE;80 const int sizeofhead = sizeof(head) - AV_INPUT_BUFFER_PADDING_SIZE;
147 int headsize = 0;81 int headsize = 0, ret;
148 int ctrl;82 FFJXLMetadata meta = { 0 };
149 AVRational tb;
150 GetBitContext gbi, *gb = &gbi;
151 83
152 uint64_t sig16 = avio_rl16(pb);84 uint64_t sig16 = avio_rl16(pb);
153 if (sig16 == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {85 if (sig16 == FF_JPEGXL_CODESTREAM_SIGNATURE_LE) {
@@ -167,7 +99,7 @@ static int jpegxl_anim_read_header(AVFormatContext *s) · 13 unmodified lines
167 return AVERROR_INVALIDDATA;99 return AVERROR_INVALIDDATA;
168 avio_skip(pb, 2); // first box always 12 bytes100 avio_skip(pb, 2); // first box always 12 bytes
169 while (1) {101 while (1) {
170 int copied;102 int copied = 0;
171 uint8_t buf[4096];103 uint8_t buf[4096];
172 int read = avio_read(pb, buf, sizeof(buf));104 int read = avio_read(pb, buf, sizeof(buf));
173 if (read < 0)105 if (read < 0)
@@ -183,20 +115,18 @@ static int jpegxl_anim_read_header(AVFormatContext *s) · 9 unmodified lines
183 if (av_buffer_realloc(&ctx->initial, ctx->initial->size + read) < 0)115 if (av_buffer_realloc(&ctx->initial, ctx->initial->size + read) < 0)
184 return AVERROR(ENOMEM);116 return AVERROR(ENOMEM);
185 }117 }
186 jpegxl_collect_codestream_header(buf, read, head + headsize, sizeofhead - headsize, &copied);118 ff_jpegxl_collect_codestream_header(buf, read, head + headsize, sizeofhead - headsize, &copied);
187 memcpy(ctx->initial->data + (ctx->initial->size - read), buf, read);119 memcpy(ctx->initial->data + (ctx->initial->size - read), buf, read);
188 headsize += copied;120 headsize += copied;
189 if (headsize >= sizeofhead || read < sizeof(buf))121 if (headsize >= sizeofhead || read < sizeof(buf))
190 break;122 break;
191 }123 }
192 }124 }
125
193 /* offset in bits of the animation header */126 /* offset in bits of the animation header */
194 offset = ff_jpegxl_verify_codestream_header(head, headsize, 0);127 ret = ff_jpegxl_parse_codestream_header(head, headsize, &meta, 0);
195 if (offset <= 0)128 if (ret < 0 || meta.animation_offset <= 0)
196 return AVERROR_INVALIDDATA;
197 if (init_get_bits8(gb, head, headsize) < 0)
198 return AVERROR_INVALIDDATA;129 return AVERROR_INVALIDDATA;
199 skip_bits_long(gb, offset);
200 130
201 st = avformat_new_stream(s, NULL);131 st = avformat_new_stream(s, NULL);
202 if (!st)132 if (!st)
@@ -204,11 +134,8 @@ static int jpegxl_anim_read_header(AVFormatContext *s) · 1 unmodified line
204 134
205 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;135 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
206 st->codecpar->codec_id = AV_CODEC_ID_JPEGXL;136 st->codecpar->codec_id = AV_CODEC_ID_JPEGXL;
207 ctrl = get_bits(gb, 2);137 avpriv_set_pts_info(st, 1, meta.timebase.num, meta.timebase.den);
208 tb.den = (const uint32_t[]){100, 1000, 1, 1}[ctrl] + get_bits_long(gb, (const uint32_t[]){0, 0, 10, 30}[ctrl]);138 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL;
209 ctrl = get_bits(gb, 2);
210 tb.num = (const uint32_t[]){1, 1001, 1, 1}[ctrl] + get_bits_long(gb, (const uint32_t[]){0, 0, 8, 10}[ctrl]);
211 avpriv_set_pts_info(st, 1, tb.num, tb.den);
212 139
213 return 0;140 return 0;
214}141}
@@ -222,17 +149,17 @@ static int jpegxl_anim_read_packet(AVFormatContext *s, AVPacket *pkt) · 7 unmodified lines
222 int64_t size;149 int64_t size;
223 size_t offset = 0;150 size_t offset = 0;
224 151
225 if ((size = avio_size(pb)) < 0)152 size = avio_size(pb);
153 if (size < 0)
226 return size;154 return size;
227 155 if (size == 0)
228 /* animated JXL this big should not exist */156 size = 4096;
229 if (size > INT_MAX)
230 return AVERROR_INVALIDDATA;
231 157
232 if (ctx->initial && size < ctx->initial->size)158 if (ctx->initial && size < ctx->initial->size)
233 size = ctx->initial->size;159 size = ctx->initial->size;
234 160
235 if ((ret = av_new_packet(pkt, size)) < 0)161 ret = av_new_packet(pkt, size);
162 if (ret < 0)
236 return ret;163 return ret;
237 164
238 if (ctx->initial) {165 if (ctx->initial) {
@@ -241,8 +168,11 @@ static int jpegxl_anim_read_packet(AVFormatContext *s, AVPacket *pkt) · 2 unmodified lines
241 av_buffer_unref(&ctx->initial);168 av_buffer_unref(&ctx->initial);
242 }169 }
243 170
244 if ((ret = avio_read(pb, pkt->data + offset, size - offset)) < 0)171 ret = avio_read(pb, pkt->data + offset, size - offset);
172 if (ret < 0)
245 return ret;173 return ret;
174 if (ret < size - offset)
175 pkt->size = ret + offset;
246 176
247 return 0;177 return 0;
248}178}
@@ -265,7 +195,7 @@ const AVInputFormat ff_jpegxl_anim_demuxer = { · 16 unmodified lines
265 .read_packet = jpegxl_anim_read_packet,195 .read_packet = jpegxl_anim_read_packet,
266 .read_close = jpegxl_anim_close,196 .read_close = jpegxl_anim_close,
267 .flags_internal = FF_FMT_INIT_CLEANUP,197 .flags_internal = FF_FMT_INIT_CLEANUP,
268 .flags = AVFMT_GENERIC_INDEX,198 .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
269 .mime_type = "image/jxl",199 .mime_type = "image/jxl",
270 .extensions = "jxl",200 .extensions = "jxl",
271};201};
libavformat/jpegxl_parse.crenamed from libavformat/jpegxl_probe.h+3−18
@@ -1,6 +1,6 @@
1/*1/*
2 * Jpeg XL header verification2 * JPEG XL Header Parser Stub
3 * Copyright (c) 2022 Leo Izen <leo.izen@gmail.com>3 * Copyright (c) 2023 Leo Izen <leo.izen@gmail.com>
4 *4 *
5 * This file is part of FFmpeg.5 * This file is part of FFmpeg.
6 *6 *
@@ -19,19 +19,4 @@ · 12 unmodified lines
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */20 */
21 21
22#ifndef AVFORMAT_JPEGXL_PROBE_H22#include "libavcodec/jpegxl_parse.c"
23#define AVFORMAT_JPEGXL_PROBE_H
24
25#include <stdint.h>
26
27#define FF_JPEGXL_CODESTREAM_SIGNATURE_LE 0x0aff
28#define FF_JPEGXL_CONTAINER_SIGNATURE_LE 0x204c584a0c000000
29
30/**
31 * @brief verify that a codestream header is valid
32 * @return Negative upon error, 0 upon verifying that the codestream is not animated,
33 * and 1 upon verifying that it is animated
34 */
35int ff_jpegxl_verify_codestream_header(const uint8_t *buf, int buflen, int validate_level);
36
37#endif /* AVFORMAT_JPEGXL_PROBE_H */
libavformat/jpegxl_probe.c+0−412
@@ -1,412 +0,0 @@
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
28enum JpegXLExtraChannelType {
29 FF_JPEGXL_CT_ALPHA = 0,
30 FF_JPEGXL_CT_DEPTH,
31 FF_JPEGXL_CT_SPOT_COLOR,
32 FF_JPEGXL_CT_SELECTION_MASK,
33 FF_JPEGXL_CT_BLACK,
34 FF_JPEGXL_CT_CFA,
35 FF_JPEGXL_CT_THERMAL,
36 FF_JPEGXL_CT_NON_OPTIONAL = 15,
37 FF_JPEGXL_CT_OPTIONAL
38};
39
40enum JpegXLColorSpace {
41 FF_JPEGXL_CS_RGB = 0,
42 FF_JPEGXL_CS_GRAY,
43 FF_JPEGXL_CS_XYB,
44 FF_JPEGXL_CS_UNKNOWN
45};
46
47enum JpegXLWhitePoint {
48 FF_JPEGXL_WP_D65 = 1,
49 FF_JPEGXL_WP_CUSTOM,
50 FF_JPEGXL_WP_E = 10,
51 FF_JPEGXL_WP_DCI = 11
52};
53
54enum JpegXLPrimaries {
55 FF_JPEGXL_PR_SRGB = 1,
56 FF_JPEGXL_PR_CUSTOM,
57 FF_JPEGXL_PR_2100 = 9,
58 FF_JPEGXL_PR_P3 = 11,
59};
60
61/* read a U32(c_i + u(u_i)) */
62static av_always_inline uint32_t jxl_u32(GetBitContext *gb,
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
77static av_always_inline uint32_t jxl_enum(GetBitContext *gb)
78{
79 return jxl_u32(gb, 0, 1, 2, 18, 0, 0, 4, 6);
80}
81
82/* read a U64() */
83static 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
114static 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 */
143static int jpegxl_read_size_header(GetBitContext *gb)
144{
145 uint32_t width, height;
146
147 if (get_bits1(gb)) {
148 /* small size header */
149 height = (get_bits(gb, 5) + 1) << 3;
150 width = jpegxl_width_from_ratio(height, get_bits(gb, 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);
156 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
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 */
171static int jpegxl_read_preview_header(GetBitContext *gb)
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;
178 width = jpegxl_width_from_ratio(height, get_bits(gb, 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);
184 width = jpegxl_width_from_ratio(height, get_bits(gb, 3));
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 */
197static void jpegxl_skip_bit_depth(GetBitContext *gb)
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 */
213static 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;
224 jpegxl_skip_bit_depth(gb);
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 {
229 type = FF_JPEGXL_CT_ALPHA;
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
238 if (type == FF_JPEGXL_CT_SPOT_COLOR)
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
247int 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
261 if (get_bits_long(gb, 16) != FF_JPEGXL_CODESTREAM_SIGNATURE_LE)
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))
280 jpegxl_read_size_header(gb);
281
282 /* preview header */
283 if (get_bits1(gb)) {
284 ret = jpegxl_read_preview_header(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) {
302 jpegxl_skip_bit_depth(gb);
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;
344 if (primaries == FF_JPEGXL_PR_CUSTOM) {
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}
libavformat/version.h+1−1
@@ -32,7 +32,7 @@ · 31 unmodified lines
32#include "version_major.h"32#include "version_major.h"
33 33
34#define LIBAVFORMAT_VERSION_MINOR 1034#define LIBAVFORMAT_VERSION_MINOR 10
35#define LIBAVFORMAT_VERSION_MICRO 10035#define LIBAVFORMAT_VERSION_MICRO 101
36 36
37#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \37#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
38 LIBAVFORMAT_VERSION_MINOR, \38 LIBAVFORMAT_VERSION_MINOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t