PR #21210 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21210 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21210.patch
Fixes samples like the one shared in #21997 >From b44ba0848cde7bc74c3132b27ea0f6f2e2fc0521 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Mon, 15 Dec 2025 19:13:02 -0300 Subject: [PATCH 1/2] avcodec/jpegxs_parser: fix bitstream assembly logic JPEG-XS streams can have the bytes corresponding to certain markers as part of slice data, and no considerations were made for it, so we need to add checks for false positives. This fixes assembling several samples. Signed-off-by: James Almer <[email protected]> --- libavcodec/jpegxs_parser.c | 66 +++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/libavcodec/jpegxs_parser.c b/libavcodec/jpegxs_parser.c index a6a3d1fcce..a9750b0a02 100644 --- a/libavcodec/jpegxs_parser.c +++ b/libavcodec/jpegxs_parser.c @@ -16,19 +16,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" + #include "bytestream.h" #include "get_bits.h" #include "jpegxs.h" #include "parser.h" #include "parser_internal.h" +typedef struct JPEGXSParseContext { + ParseContext pc; + + int eoc_found; +} JPEGXSParseContext; + /** * Find the end of the current frame in the bitstream. * @return the position of the first byte of the next frame, or -1 */ -static int jpegxs_find_frame_end(ParseContext *pc, const uint8_t *buf, +static int jpegxs_find_frame_end(JPEGXSParseContext *jpegxs, const uint8_t *buf, int buf_size) { + ParseContext *pc = &jpegxs->pc; int pic_found, i = 0; uint32_t state; @@ -46,15 +55,41 @@ static int jpegxs_find_frame_end(ParseContext *pc, const uint8_t *buf, } } - if (pic_found) { - if (buf_size == 0) - return 0; + if (buf_size == 0) { + if (jpegxs->eoc_found) { + pc->frame_start_found = jpegxs->eoc_found = 0; + pc->state = -1; + } + return 0; + } + + while (pic_found && i < buf_size) { + if (jpegxs->eoc_found) { + for(; i < buf_size; i++) { + state = (state << 8) | buf[i]; + if ((state >> 16) == JPEGXS_MARKER_EOC) { + if ((uint16_t)state == JPEGXS_MARKER_SOC) { + // New image + pc->frame_start_found = jpegxs->eoc_found = 0; + pc->state = -1; + return i - 1; + } else { + // False positive + i++; + jpegxs->eoc_found = 0; + break; + } + } + } + } + for(; i < buf_size; i++) { state = (state << 8) | buf[i]; if ((uint16_t)state == JPEGXS_MARKER_EOC) { - pc->frame_start_found = 0; - pc->state = -1; - return i + 1; + // EOC candidate + i++; + jpegxs->eoc_found = 1; + break; } } } @@ -181,10 +216,11 @@ static int jpegxsvideo_parse(AVCodecParserContext *s, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { - ParseContext *pc = s->priv_data; + JPEGXSParseContext *jpegxs = s->priv_data; + ParseContext *pc = &jpegxs->pc; int next; - next = jpegxs_find_frame_end(pc, buf, buf_size); + next = jpegxs_find_frame_end(jpegxs, buf, buf_size); if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { *poutbuf = NULL; @@ -199,9 +235,17 @@ static int jpegxsvideo_parse(AVCodecParserContext *s, return next; } +static av_cold void jpegxsparse_close(AVCodecParserContext *s) +{ + JPEGXSParseContext *jpegxs = s->priv_data; + ParseContext *pc = &jpegxs->pc; + + av_freep(&pc->buffer); +} + const FFCodecParser ff_jpegxs_parser = { PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXS), - .priv_data_size = sizeof(ParseContext), + .priv_data_size = sizeof(JPEGXSParseContext), .parse = jpegxsvideo_parse, - .close = ff_parse_close, + .close = jpegxsparse_close, }; -- 2.49.1 >From 55fb11f3941e5a9cf5cbdd32b90a7d7b7cf65c44 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Mon, 15 Dec 2025 19:25:49 -0300 Subject: [PATCH 2/2] tests/fate/demux: add a raw JPEG-XS demux test Use the concat protocol, to test the parser's capabilities to differentiate between EOC maker before SOC marker, on top of false EOC marker positives and EOC maker on EOF. Signed-off-by: James Almer <[email protected]> --- tests/fate/demux.mak | 3 +++ tests/ref/fate/jxs-concat-demux | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/ref/fate/jxs-concat-demux diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index ad1046a453..5ad576608e 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -169,6 +169,9 @@ fate-ts-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/ac3/mp3ac325-4864-small.ts FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-timed-id3-demux fate-ts-timed-id3-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/mpegts/id3.ts +FATE_FFPROBE_DEMUX-$(call PARSERDEM, JPEGXS, IMAGE_JPEGXS_PIPE, CONCAT_PROTOCOL) += fate-jxs-concat-demux +fate-jxs-concat-demux: CMD = framecrc "-i concat:$(TARGET_SAMPLES)/jxs/lena.jxs|$(TARGET_SAMPLES)/jxs/lena.jxs -c:v copy" + FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes) FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX) FATE_FFPROBE_DEMUX += $(FATE_FFPROBE_DEMUX-yes) diff --git a/tests/ref/fate/jxs-concat-demux b/tests/ref/fate/jxs-concat-demux new file mode 100644 index 0000000000..bb2378043d --- /dev/null +++ b/tests/ref/fate/jxs-concat-demux @@ -0,0 +1,7 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: jpegxs +#dimensions 0: 256x256 +#sar 0: 0/1 +0, 0, 0, 1, 131072, 0x75165e30 +0, 1, 1, 1, 131072, 0x75165e30 -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
