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]

Reply via email to