This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 52c097065cb59927c532a09cfbcfbfb7948e3092
Author:     James Almer <[email protected]>
AuthorDate: Mon Dec 1 22:59:01 2025 -0300
Commit:     James Almer <[email protected]>
CommitDate: Sat Dec 13 18:45:17 2025 -0300

    avcodec: add a JPEG-XS parser
    
    Signed-off-by: James Almer <[email protected]>
---
 Changelog                          |   1 +
 libavcodec/Makefile                |   1 +
 libavcodec/{ffv1enc.h => jpegxs.h} |  35 +++----
 libavcodec/jpegxs_parser.c         | 207 +++++++++++++++++++++++++++++++++++++
 libavcodec/parsers.c               |   1 +
 5 files changed, 225 insertions(+), 20 deletions(-)

diff --git a/Changelog b/Changelog
index ef72af1e93..aa0aaaed72 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version <next>:
 - DPX Vulkan hwaccel
 - Rockchip H.264/HEVC hardware encoder
 - Add vf_scale_d3d12 filter
+- JPEG-XS parser
 
 
 version 8.0:
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 40e68116e8..5ed8a27b76 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1272,6 +1272,7 @@ OBJS-$(CONFIG_HDR_PARSER)              += hdr_parser.o
 OBJS-$(CONFIG_IPU_PARSER)              += ipu_parser.o
 OBJS-$(CONFIG_JPEG2000_PARSER)         += jpeg2000_parser.o
 OBJS-$(CONFIG_JPEGXL_PARSER)           += jpegxl_parser.o jpegxl_parse.o
+OBJS-$(CONFIG_JPEGXS_PARSER)           += jpegxs_parser.o
 OBJS-$(CONFIG_MISC4_PARSER)            += misc4_parser.o
 OBJS-$(CONFIG_MJPEG_PARSER)            += mjpeg_parser.o
 OBJS-$(CONFIG_MLP_PARSER)              += mlp_parse.o mlp_parser.o mlp.o
diff --git a/libavcodec/ffv1enc.h b/libavcodec/jpegxs.h
similarity index 50%
copy from libavcodec/ffv1enc.h
copy to libavcodec/jpegxs.h
index 42d521a747..951e2f0d69 100644
--- a/libavcodec/ffv1enc.h
+++ b/libavcodec/jpegxs.h
@@ -1,8 +1,4 @@
 /*
- * FFV1 encoder
- *
- * Copyright (c) 2003-2013 Michael Niedermayer <[email protected]>
- *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
@@ -20,23 +16,22 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#ifndef AVCODEC_FFV1ENC_H
-#define AVCODEC_FFV1ENC_H
-
-#include "avcodec.h"
+#ifndef AVCODEC_JPEGXS_H
+#define AVCODEC_JPEGXS_H
 
 enum {
-    QTABLE_DEFAULT = -1,
-    QTABLE_8BIT,
-    QTABLE_GT8BIT,
+    JPEGXS_MARKER_SOC = 0xff10, // Start of codestream
+    JPEGXS_MARKER_EOC = 0xff11, // End of codestream
+    JPEGXS_MARKER_PIH = 0xff12, // Picture header
+    JPEGXS_MARKER_CDT = 0xff13, // Component table
+    JPEGXS_MARKER_WGT = 0xff14, // Weights table
+    JPEGXS_MARKER_COM = 0xff15, // Extension marker
+    JPEGXS_MARKER_NLT = 0xff16, // Nonlinearity marker
+    JPEGXS_MARKER_CWD = 0xff17, // Component-dependent wavelet decomposition 
marker
+    JPEGXS_MARKER_CTS = 0xff18, // Colour transformation specification marker
+    JPEGXS_MARKER_CRG = 0xff19, // Component registration marker
+    JPEGXS_MARKER_SLH = 0xff20, // Slice header
+    JPEGXS_MARKER_CAP = 0xff50, // Capabilities Marker
 };
 
-av_cold int ff_ffv1_encode_init(AVCodecContext *avctx);
-av_cold int ff_ffv1_encode_determine_slices(AVCodecContext *avctx);
-av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx);
-av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx,
-                                            enum AVPixelFormat pix_fmt);
-
-size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx);
-
-#endif /* AVCODEC_FFV1ENC_H */
+#endif /* AVCODEC_JPEGXS_H */
diff --git a/libavcodec/jpegxs_parser.c b/libavcodec/jpegxs_parser.c
new file mode 100644
index 0000000000..a6a3d1fcce
--- /dev/null
+++ b/libavcodec/jpegxs_parser.c
@@ -0,0 +1,207 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "bytestream.h"
+#include "get_bits.h"
+#include "jpegxs.h"
+#include "parser.h"
+#include "parser_internal.h"
+
+/**
+ * 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,
+                                 int buf_size)
+{
+    int pic_found, i = 0;
+    uint32_t state;
+
+    pic_found = pc->frame_start_found;
+    state = pc->state;
+
+    if (!pic_found) {
+        for (i = 0; i < buf_size; i++) {
+            state = (state << 8) | buf[i];
+            if ((uint16_t)state == JPEGXS_MARKER_SOC) {
+                i++;
+                pic_found = 1;
+                break;
+            }
+        }
+    }
+
+    if (pic_found) {
+        if (buf_size == 0)
+            return 0;
+        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;
+            }
+        }
+    }
+
+    pc->frame_start_found = pic_found;
+    pc->state = state;
+    return END_NOT_FOUND;
+}
+
+static int jpegxs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx,
+                              const uint8_t *buf, int buf_size)
+{
+    GetByteContext gbc;
+    GetBitContext gb;
+    int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3];
+    int size, marker, components;
+
+    s->key_frame = 1;
+    s->pict_type = AV_PICTURE_TYPE_I;
+
+    if (buf_size < 4)
+        return 0;
+
+    bytestream2_init(&gbc, buf, buf_size);
+    marker = bytestream2_get_be16(&gbc);
+    if (marker != JPEGXS_MARKER_SOC)
+        return 0;
+
+    marker = bytestream2_get_be16(&gbc);
+    if (marker != JPEGXS_MARKER_CAP)
+        return 0;
+    size = bytestream2_get_be16(&gbc);
+    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
+
+    marker = bytestream2_get_be16(&gbc);
+    if (marker != JPEGXS_MARKER_PIH)
+        return 0;
+    size = bytestream2_get_be16(&gbc);
+    bytestream2_skip(&gbc, 4); // Lcod
+    bytestream2_skip(&gbc, 2); // Ppih
+    bytestream2_skip(&gbc, 2); // Plev
+    size -= 8;
+
+    s->width  = bytestream2_get_be16(&gbc);
+    s->height = bytestream2_get_be16(&gbc);
+    size -= 4;
+
+    bytestream2_skip(&gbc, 2); // Cw
+    bytestream2_skip(&gbc, 2); // Hsl
+    size -= 4;
+
+    components = bytestream2_get_byte(&gbc);
+    if (components != 1 && components != 3)
+        return 0;
+    size--;
+
+    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
+
+    while (bytestream2_get_bytes_left(&gbc) > 0) {
+        marker = bytestream2_get_be16(&gbc);
+
+        switch(marker) {
+        case JPEGXS_MARKER_CDT:
+            size = bytestream2_get_be16(&gbc);
+            init_get_bits8(&gb, gbc.buffer, FFMIN(FFMAX(size - 2, 0), 
bytestream2_get_bytes_left(&gbc)));
+
+            for (int i = 0; i < components; i++) {
+                bpc[i] = get_bits(&gb, 8);
+                if (i && bpc[i] != bpc[i-1])
+                    return 0;
+
+                log2_chroma_w[i] = get_bits(&gb, 4);
+                log2_chroma_h[i] = get_bits(&gb, 4);
+
+                if (log2_chroma_h[i] > log2_chroma_w[i])
+                    return 0;
+                if (i == 2 && (log2_chroma_h[2] != log2_chroma_h[1] ||
+                               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;
+            }
+            return 0;
+        default:
+            size = bytestream2_get_be16(&gbc);
+            bytestream2_skip(&gbc, FFMAX(size - 2, 0));
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int jpegxsvideo_parse(AVCodecParserContext *s,
+                             AVCodecContext *avctx,
+                             const uint8_t **poutbuf, int *poutbuf_size,
+                             const uint8_t *buf, int buf_size)
+{
+    ParseContext *pc = s->priv_data;
+    int next;
+
+    next = jpegxs_find_frame_end(pc, buf, buf_size);
+
+    if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+        *poutbuf = NULL;
+        *poutbuf_size = 0;
+        return buf_size;
+    }
+
+    jpegxs_parse_frame(s, avctx, buf, buf_size);
+
+    *poutbuf = buf;
+    *poutbuf_size = buf_size;
+    return next;
+}
+
+const FFCodecParser ff_jpegxs_parser = {
+    PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXS),
+    .priv_data_size = sizeof(ParseContext),
+    .parse          = jpegxsvideo_parse,
+    .close          = ff_parse_close,
+};
diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
index cae1f7213e..4561f6eb3d 100644
--- a/libavcodec/parsers.c
+++ b/libavcodec/parsers.c
@@ -77,6 +77,7 @@ extern const FFCodecParser ff_hdr_parser;
 extern const FFCodecParser ff_ipu_parser;
 extern const FFCodecParser ff_jpeg2000_parser;
 extern const FFCodecParser ff_jpegxl_parser;
+extern const FFCodecParser ff_jpegxs_parser;
 extern const FFCodecParser ff_misc4_parser;
 extern const FFCodecParser ff_mjpeg_parser;
 extern const FFCodecParser ff_mlp_parser;

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

Reply via email to