Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] avcodec/jpegxs_parser: fix bitstream assembly logic (PR #21210)
@ 2025-12-15 22:32 James Almer via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: James Almer via ffmpeg-devel @ 2025-12-15 22:32 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: James Almer

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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
 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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
 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 -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-12-15 22:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-15 22:32 [FFmpeg-devel] [PATCH] avcodec/jpegxs_parser: fix bitstream assembly logic (PR #21210) James Almer via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git