On 4/7/2026 9:21 AM, Grzegorz Rys wrote:
Signed-off-by: Grzegorz Rys <[email protected]>
---
  libavcodec/jpegxs_parser.c | 111 +++++++++++++++++++++++++++----------
  1 file changed, 81 insertions(+), 30 deletions(-)

diff --git a/libavcodec/jpegxs_parser.c b/libavcodec/jpegxs_parser.c
index a9750b0a02..1cc6708946 100644
--- a/libavcodec/jpegxs_parser.c
+++ b/libavcodec/jpegxs_parser.c
@@ -106,6 +106,7 @@ static int jpegxs_parse_frame(AVCodecParserContext *s, 
AVCodecContext *avctx,
      GetBitContext gb;
      int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3];
      int size, marker, components;
+    int is_rgb = 0;  // 0 = YUV, 1 = RGB
s->key_frame = 1;
      s->pict_type = AV_PICTURE_TYPE_I;
@@ -170,37 +171,19 @@ static int jpegxs_parse_frame(AVCodecParserContext *s, 
AVCodecContext *avctx,
                                 log2_chroma_w[2] != log2_chroma_w[1]))
                      return 0;
              }
-
-            switch (bpc[0]) {
-            case 8:
-                if (components == 1)                                     
s->format = AV_PIX_FMT_GRAY8;
-                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV444P;
-                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV422P;
-                else                                                     
s->format = AV_PIX_FMT_YUV420P;
-                break;
-            case 10:
-                if (components == 1)                                     
s->format = AV_PIX_FMT_GRAY10;
-                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV444P10;
-                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV422P10;
-                else                                                     
s->format = AV_PIX_FMT_YUV420P10;
-                break;
-            case 12:
-                if (components == 1)                                     
s->format = AV_PIX_FMT_GRAY12;
-                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV444P12;
-                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV422P12;
-                else                                                     
s->format = AV_PIX_FMT_YUV420P12;
-                break;
-            case 14:
-                if (components == 1)                                     
s->format = AV_PIX_FMT_GRAY14;
-                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV444P14;
-                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) 
s->format = AV_PIX_FMT_YUV422P14;
-                else                                                     
s->format = AV_PIX_FMT_YUV420P14;
-                break;
-            default:
-                s->format = AV_PIX_FMT_NONE;
-                break;
+            bytestream2_skip(&gbc, FFMAX(size - 2, 0));
+            break;
+        case JPEGXS_MARKER_CTS:
+            size = bytestream2_get_be16(&gbc);
+            if (size >= 3) {
+                int colour_spec = bytestream2_get_byte(&gbc);
+                // colour_spec: 0=YCbCr, 1=RGB, 2=Gray, ...
+                if (colour_spec == 1)
+                    is_rgb = 1;
              }
-            return 0;
+            bytestream2_skip(&gbc, FFMAX(size - 3, 0));
+            // Format decision after CTS
+            goto format_decision;
          default:
              size = bytestream2_get_be16(&gbc);
              bytestream2_skip(&gbc, FFMAX(size - 2, 0));
@@ -208,6 +191,74 @@ static int jpegxs_parse_frame(AVCodecParserContext *s, 
AVCodecContext *avctx,
          }
      }
+format_decision:
+    // Determine pixel format based on bit depth and chroma subsampling
+    switch (bpc[0]) {

Nothing ensures a CDT was seen before a CTS one, or that either of them were seen at all. If that happens, bpc[0] here will be uninitialized.

Keep the code below inside the while() loop, and add a check for CDT presence before going through with CDT parsing.

+    case 8:
+        if (components == 1) {
+            s->format = AV_PIX_FMT_GRAY8;
+        } else if (is_rgb) {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) {
+                s->format = AV_PIX_FMT_GBRP;
+            } else {
+                s->format = AV_PIX_FMT_NONE;  // Invalid RGB with chroma 
subsampling
+            }
+        } else {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = 
AV_PIX_FMT_YUV444P;
+            else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format 
= AV_PIX_FMT_YUV422P;
+            else                                                     s->format 
= AV_PIX_FMT_YUV420P;
+        }
+        break;
+    case 10:
+        if (components == 1) {
+            s->format = AV_PIX_FMT_GRAY10;
+        } else if (is_rgb) {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) {
+                s->format = AV_PIX_FMT_GBRP10LE;
+            } else {
+                s->format = AV_PIX_FMT_NONE;
+            }
+        } else {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = 
AV_PIX_FMT_YUV444P10;
+            else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format 
= AV_PIX_FMT_YUV422P10;
+            else                                                     s->format 
= AV_PIX_FMT_YUV420P10;
+        }
+        break;
+    case 12:
+        if (components == 1) {
+            s->format = AV_PIX_FMT_GRAY12;
+        } else if (is_rgb) {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) {
+                s->format = AV_PIX_FMT_GBRP12LE;
+            } else {
+                s->format = AV_PIX_FMT_NONE;
+            }
+        } else {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = 
AV_PIX_FMT_YUV444P12;
+            else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format 
= AV_PIX_FMT_YUV422P12;
+            else                                                     s->format 
= AV_PIX_FMT_YUV420P12;
+        }
+        break;
+    case 14:
+        if (components == 1) {
+            s->format = AV_PIX_FMT_GRAY14;
+        } else if (is_rgb) {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) {
+                s->format = AV_PIX_FMT_GBRP14LE;
+            } else {
+                s->format = AV_PIX_FMT_NONE;
+            }
+        } else {
+            if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = 
AV_PIX_FMT_YUV444P14;
+            else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format 
= AV_PIX_FMT_YUV422P14;
+            else                                                     s->format 
= AV_PIX_FMT_YUV420P14;
+        }
+        break;
+    default:
+        s->format = AV_PIX_FMT_NONE;
+        break;
+    }
+
      return 0;
  }

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to