PR #21084 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21084
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21084.patch

Starting with a native parser (simple header parsing to get dimensions and 
pixel format), a decoder and encoder using an external library, and a demuxer 
for raw bitstreams.


>From 6c5c23d3c75fa16b4d46eebf21aa44cfe2be8f59 Mon Sep 17 00:00:00 2001
From: Tomasz Szumski <[email protected]>
Date: Tue, 9 Jul 2024 10:04:16 +0200
Subject: [PATCH 1/4] avcodec/codec_id: add JPEG-XS

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/codec_desc.c | 9 +++++++++
 libavcodec/codec_id.h   | 1 +
 2 files changed, 10 insertions(+)

diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index c72271bfad..b3f4e73e1d 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2000,6 +2000,15 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
         .profiles  = NULL_IF_CONFIG_SMALL(ff_prores_raw_profiles),
     },
+    {
+        .id        = AV_CODEC_ID_JPEGXS,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "jpegxs",
+        .long_name = NULL_IF_CONFIG_SMALL("JPEG XS"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+                     AV_CODEC_PROP_LOSSLESS,
+        .mime_types= MT("image/jxs"),
+    },
 
     /* various PCM "codecs" */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 8c98ac6335..6529f0a6bc 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -331,6 +331,7 @@ enum AVCodecID {
     AV_CODEC_ID_JPEGXL_ANIM,
     AV_CODEC_ID_APV,
     AV_CODEC_ID_PRORES_RAW,
+    AV_CODEC_ID_JPEGXS,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the 
start of audio codecs
-- 
2.49.1


>From 5a92be5fe64dbb7e086e66f12670127e406c2b93 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Mon, 1 Dec 2025 22:59:01 -0300
Subject: [PATCH 2/4] avcodec: add a JPEG-XS parser

Signed-off-by: James Almer <[email protected]>
---
 Changelog                  |   1 +
 libavcodec/Makefile        |   1 +
 libavcodec/jpegxs.h        |  37 +++++++
 libavcodec/jpegxs_parser.c | 207 +++++++++++++++++++++++++++++++++++++
 libavcodec/parsers.c       |   1 +
 5 files changed, 247 insertions(+)
 create mode 100644 libavcodec/jpegxs.h
 create mode 100644 libavcodec/jpegxs_parser.c

diff --git a/Changelog b/Changelog
index cda59ebc90..663c232e70 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ version <next>:
 - ProRes Vulkan hwaccel
 - DPX Vulkan hwaccel
 - Rockchip H.264/HEVC hardware encoder
+- 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/jpegxs.h b/libavcodec/jpegxs.h
new file mode 100644
index 0000000000..951e2f0d69
--- /dev/null
+++ b/libavcodec/jpegxs.h
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_JPEGXS_H
+#define AVCODEC_JPEGXS_H
+
+enum {
+    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
+};
+
+#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;
-- 
2.49.1


>From 758ccd447ef24617395b74e5bf61683e38038ec2 Mon Sep 17 00:00:00 2001
From: Tomasz Szumski <[email protected]>
Date: Tue, 24 Oct 2023 12:42:00 +0200
Subject: [PATCH 3/4] avcodec: add JPEG-XS decoder and encoder using
 libsvtjpegxs

Co-Authored-by: James Almer <[email protected]>
Signed-off-by: James Almer <[email protected]>
---
 Changelog                    |   1 +
 configure                    |   5 +
 libavcodec/Makefile          |   2 +
 libavcodec/allcodecs.c       |   2 +
 libavcodec/libsvtjpegxsdec.c | 288 +++++++++++++++++++++++++++++++++
 libavcodec/libsvtjpegxsenc.c | 298 +++++++++++++++++++++++++++++++++++
 6 files changed, 596 insertions(+)
 create mode 100644 libavcodec/libsvtjpegxsdec.c
 create mode 100644 libavcodec/libsvtjpegxsenc.c

diff --git a/Changelog b/Changelog
index 663c232e70..e98d0db07d 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version <next>:
 - DPX Vulkan hwaccel
 - Rockchip H.264/HEVC hardware encoder
 - JPEG-XS parser
+- JPEG-XS decoder and encoder through libsvtjpegxs
 
 
 version 8.0:
diff --git a/configure b/configure
index 883539e361..98841a79fb 100755
--- a/configure
+++ b/configure
@@ -281,6 +281,7 @@ External library support:
   --enable-libsrt          enable Haivision SRT protocol via libsrt [no]
   --enable-libssh          enable SFTP protocol via libssh [no]
   --enable-libsvtav1       enable AV1 encoding via SVT [no]
+  --enable-libsvtjpegxs    enable JPEGXS encoding/decoding via SVT [no]
   --enable-libtensorflow   enable TensorFlow as a DNN module backend
                            for DNN based filters like sr [no]
   --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
@@ -2010,6 +2011,7 @@ EXTERNAL_LIBRARY_LIST="
     libsrt
     libssh
     libsvtav1
+    libsvtjpegxs
     libtensorflow
     libtesseract
     libtheora
@@ -3702,6 +3704,8 @@ libspeex_decoder_deps="libspeex"
 libspeex_encoder_deps="libspeex"
 libspeex_encoder_select="audio_frame_queue"
 libsvtav1_encoder_deps="libsvtav1"
+libsvtjpegxs_encoder_deps="libsvtjpegxs"
+libsvtjpegxs_decoder_deps="libsvtjpegxs"
 libsvtav1_encoder_select="dovi_rpuenc"
 libtheora_encoder_deps="libtheora"
 libtwolame_encoder_deps="libtwolame"
@@ -7247,6 +7251,7 @@ enabled libssh            && require_pkg_config libssh 
"libssh >= 0.6.0" libssh/
 enabled libspeex          && require_pkg_config libspeex speex speex/speex.h 
speex_decoder_init
 enabled libsrt            && require_pkg_config libsrt "srt >= 1.3.0" 
srt/srt.h srt_socket
 enabled libsvtav1         && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" 
EbSvtAv1Enc.h svt_av1_enc_init_handle
+enabled libsvtjpegxs      && require_pkg_config libsvtjpegxs "SvtJpegxs >= 
0.10.0" SvtJpegxsEnc.h svt_jpeg_xs_encoder_init
 enabled libtensorflow     && require libtensorflow tensorflow/c/c_api.h 
TF_Version -ltensorflow
 enabled libtesseract      && require_pkg_config libtesseract tesseract 
tesseract/capi.h TessBaseAPICreate
 enabled libtheora         && require libtheora theora/theoraenc.h th_info_init 
-ltheoraenc -ltheoradec -logg
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 5ed8a27b76..28ad85afb4 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1206,6 +1206,8 @@ OBJS-$(CONFIG_LIBSHINE_ENCODER)           += libshine.o
 OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
 OBJS-$(CONFIG_LIBSVTAV1_ENCODER)          += libsvtav1.o
+OBJS-$(CONFIG_LIBSVTJPEGXS_DECODER)       += libsvtjpegxsdec.o
+OBJS-$(CONFIG_LIBSVTJPEGXS_ENCODER)       += libsvtjpegxsenc.o
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
 OBJS-$(CONFIG_LIBTWOLAME_ENCODER)         += libtwolame.o
 OBJS-$(CONFIG_LIBUAVS3D_DECODER)          += libuavs3d.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index a335e2bb82..042b07c895 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -815,6 +815,8 @@ extern const FFCodec ff_libshine_encoder;
 extern const FFCodec ff_libspeex_encoder;
 extern const FFCodec ff_libspeex_decoder;
 extern const FFCodec ff_libsvtav1_encoder;
+extern const FFCodec ff_libsvtjpegxs_encoder;
+extern const FFCodec ff_libsvtjpegxs_decoder;
 extern const FFCodec ff_libtheora_encoder;
 extern const FFCodec ff_libtwolame_encoder;
 extern const FFCodec ff_libuavs3d_decoder;
diff --git a/libavcodec/libsvtjpegxsdec.c b/libavcodec/libsvtjpegxsdec.c
new file mode 100644
index 0000000000..373bf26dab
--- /dev/null
+++ b/libavcodec/libsvtjpegxsdec.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright(c) 2024 Intel Corporation
+ *
+ * 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
+ */
+
+/*
+* Copyright(c) 2024 Intel Corporation
+* SPDX - License - Identifier: BSD - 2 - Clause - Patent
+*/
+
+#include <SvtJpegxsDec.h>
+
+#include "libavutil/mem.h"
+#include "libavutil/common.h"
+#include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "profiles.h"
+
+typedef struct SvtJpegXsDecodeContext {
+    AVClass* class;
+    svt_jpeg_xs_image_config_t config;
+    svt_jpeg_xs_decoder_api_t decoder;
+    uint32_t decoder_initialized;
+
+    /*0- AVPacket* avpkt have full frame*/
+    /*1- AVPacket* avpkt have chunk of frame, need another buffer to merge 
packets*/
+    uint32_t chunk_decoding;
+    uint32_t frame_size;
+    uint32_t buffer_filled_len;
+    uint8_t* bitstream_buffer;
+    int proxy_mode;
+} SvtJpegXsDecodeContext;
+
+static int set_pix_fmt(AVCodecContext* avctx, svt_jpeg_xs_image_config_t 
config)
+{
+    int ret = 0;
+
+    switch (config.format) {
+    case COLOUR_FORMAT_PLANAR_YUV420:
+        if (config.bit_depth == 8)
+            avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+        else if (config.bit_depth == 10)
+            avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE;
+        else if (config.bit_depth == 12)
+            avctx->pix_fmt = AV_PIX_FMT_YUV420P12LE;
+        else
+            avctx->pix_fmt = AV_PIX_FMT_YUV420P14LE;
+        break;
+    case COLOUR_FORMAT_PLANAR_YUV422:
+        if (config.bit_depth == 8)
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+        else if (config.bit_depth == 10)
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
+        else if (config.bit_depth == 12)
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P12LE;
+        else
+            avctx->pix_fmt = AV_PIX_FMT_YUV422P14LE;
+        break;
+    case COLOUR_FORMAT_PLANAR_YUV444_OR_RGB:
+        if (config.bit_depth == 8)
+            avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+        else if (config.bit_depth == 10)
+            avctx->pix_fmt = AV_PIX_FMT_YUV444P10LE;
+        else if (config.bit_depth == 12)
+            avctx->pix_fmt = AV_PIX_FMT_YUV444P12LE;
+        else
+            avctx->pix_fmt = AV_PIX_FMT_YUV444P14LE;
+        break;
+    default:
+        av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
+        ret = AVERROR_INVALIDDATA;
+        break;
+    }
+
+    return ret;
+}
+
+static int svt_jpegxs_dec_decode(AVCodecContext* avctx, AVFrame* picture, int* 
got_frame, AVPacket* avpkt)
+{
+    SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
+    SvtJxsErrorType_t err = SvtJxsErrorNone;
+    int ret;
+    svt_jpeg_xs_frame_t dec_input;
+    svt_jpeg_xs_frame_t dec_output;
+    uint32_t pixel_size;
+
+    if (!svt_dec->decoder_initialized) {
+        err = svt_jpeg_xs_decoder_get_single_frame_size_with_proxy(
+            avpkt->data, avpkt->size, NULL, &svt_dec->frame_size, 1 /*quick 
search*/, svt_dec->decoder.proxy_mode);
+        if (err) {
+            av_log(avctx, AV_LOG_ERROR, 
"svt_jpeg_xs_decoder_get_single_frame_size_with_proxy failed, err=%d\n", err);
+            return err;
+        }
+        if (avpkt->size < svt_dec->frame_size) {
+            svt_dec->chunk_decoding = 1;
+            svt_dec->bitstream_buffer = av_malloc(svt_dec->frame_size);
+            if (!svt_dec->bitstream_buffer) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to allocate 
svt_dec->bitstream_buffer.\n");
+                return AVERROR(ENOMEM);
+            }
+            av_log(avctx, AV_LOG_DEBUG, "svt_jpegxs_dec_decode, 
bitstream_size=%d, chunk = %d\n", svt_dec->frame_size, avpkt->size);
+        }
+        if (avpkt->size > svt_dec->frame_size) {
+            av_log(avctx, AV_LOG_ERROR, "Single packet have data for more than 
one frame.\n");
+            return AVERROR_EXTERNAL;
+        }
+
+        err = svt_jpeg_xs_decoder_init(SVT_JPEGXS_API_VER_MAJOR, 
SVT_JPEGXS_API_VER_MINOR,
+                                       &svt_dec->decoder, avpkt->data, 
avpkt->size, &svt_dec->config);
+        if (err) {
+            av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_init failed, 
err=%d\n", err);
+            return err;
+        }
+
+        ret = set_pix_fmt(avctx, svt_dec->config);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "set_pix_fmt failed, err=%d\n", ret);
+            return ret;
+        }
+
+        ret = ff_set_dimensions(avctx, svt_dec->config.width, 
svt_dec->config.height);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "ff_set_dimensions failed, err=%d\n", 
ret);
+            return ret;
+        }
+
+        svt_dec->decoder_initialized = 1;
+    }
+
+    if (svt_dec->chunk_decoding) {
+        uint8_t* bitstrream_addr = svt_dec->bitstream_buffer + 
svt_dec->buffer_filled_len;
+        int bytes_to_copy = avpkt->size;
+        //Do not copy more data than allocation
+        if ((bytes_to_copy + svt_dec->buffer_filled_len) > 
svt_dec->frame_size) {
+            bytes_to_copy = svt_dec->frame_size - svt_dec->buffer_filled_len;
+        }
+
+        memcpy(bitstrream_addr, avpkt->data, bytes_to_copy);
+        svt_dec->buffer_filled_len += avpkt->size;
+        if (svt_dec->buffer_filled_len >= svt_dec->frame_size) {
+            dec_input.bitstream.buffer = svt_dec->bitstream_buffer;
+            dec_input.bitstream.allocation_size = svt_dec->frame_size;
+            dec_input.bitstream.used_size = svt_dec->frame_size;
+        } else {
+            *got_frame = 0;
+            return avpkt->size;
+        }
+    } else {
+        dec_input.bitstream.buffer = avpkt->data;
+        dec_input.bitstream.allocation_size = avpkt->size;
+        dec_input.bitstream.used_size = avpkt->size;
+    }
+    dec_input.user_prv_ctx_ptr = avpkt;
+
+    ret = ff_get_buffer(avctx, picture, 0);
+    if (ret < 0)
+        return ret;
+
+    pixel_size = svt_dec->config.bit_depth <= 8 ? 1 : 2;
+
+    for (int comp = 0; comp < svt_dec->config.components_num; comp++) {
+        dec_input.image.data_yuv[comp] = picture->data[comp];
+        dec_input.image.stride[comp] = picture->linesize[comp]/pixel_size;
+        dec_input.image.alloc_size[comp] = picture->linesize[comp] * 
svt_dec->config.components[comp].height;
+    }
+
+    err = svt_jpeg_xs_decoder_send_frame(&svt_dec->decoder, &dec_input, 1 
/*blocking*/);
+    if (err) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_send_frame failed, 
err=%d\n", err);
+        return err;
+    }
+
+    err = svt_jpeg_xs_decoder_get_frame(&svt_dec->decoder, &dec_output, 1 
/*blocking*/);
+    if (err == SvtJxsErrorDecoderConfigChange) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_frame return 
SvtJxsErrorDecoderConfigChange\n");
+        return AVERROR_INPUT_CHANGED;
+    }
+    if (err) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_frame failed, 
err=%d\n", err);
+        return err;
+    }
+
+    if (dec_output.user_prv_ctx_ptr != avpkt) {
+        av_log(avctx, AV_LOG_ERROR, "Returned different user_prv_ctx_ptr than 
expected\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    //Copy leftover from AVPacket if it contain data from two frames
+    if (svt_dec->chunk_decoding) {
+        int bytes_to_copy = svt_dec->buffer_filled_len % svt_dec->frame_size;
+        int packet_offset = avpkt->size - bytes_to_copy;
+        uint8_t* packet_addr = avpkt->data + packet_offset;
+
+        memcpy(svt_dec->bitstream_buffer, packet_addr, bytes_to_copy);
+        svt_dec->buffer_filled_len = bytes_to_copy;
+    }
+
+    *got_frame = 1;
+
+    return avpkt->size;
+}
+
+static av_cold int svt_jpegxs_dec_free(AVCodecContext* avctx)
+{
+    SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
+
+    svt_jpeg_xs_decoder_close(&svt_dec->decoder);
+    av_freep(&svt_dec->bitstream_buffer);
+
+    return 0;
+}
+
+static av_cold int svt_jpegxs_dec_init(AVCodecContext* avctx)
+{
+    SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
+
+    if (av_log_get_level() < AV_LOG_DEBUG)
+        svt_dec->decoder.verbose = VERBOSE_ERRORS;
+    else if (av_log_get_level() == AV_LOG_DEBUG)
+        svt_dec->decoder.verbose = VERBOSE_SYSTEM_INFO;
+    else
+        svt_dec->decoder.verbose = VERBOSE_WARNINGS;
+
+    if (svt_dec->proxy_mode == 1)
+        svt_dec->decoder.proxy_mode = proxy_mode_half;
+    else if (svt_dec->proxy_mode == 2)
+        svt_dec->decoder.proxy_mode = proxy_mode_quarter;
+    else
+        svt_dec->decoder.proxy_mode = proxy_mode_full;
+
+    svt_dec->decoder.threads_num = FFMIN(avctx->thread_count ? 
avctx->thread_count : av_cpu_count(), 64);
+    svt_dec->decoder.use_cpu_flags = CPU_FLAGS_ALL;
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(SvtJpegXsDecodeContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption svtjpegxs_dec_options[] = {
+    { "proxy_mode", "Resolution scaling mode", OFFSET(proxy_mode), 
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, VE, .unit = "proxy_mode" },
+      { "full",     NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, 
VE, .unit = "proxy_mode" },
+      { "half",     NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, 
VE, .unit = "proxy_mode" },
+      { "quarter",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, INT_MIN, INT_MAX, 
VE, .unit = "proxy_mode" },
+    {NULL},
+};
+
+static const AVClass svtjpegxs_dec_class = {
+    .class_name = "libsvtjpegxsdec",
+    .item_name = av_default_item_name,
+    .option = svtjpegxs_dec_options,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+const FFCodec ff_libsvtjpegxs_decoder = {
+    .p.name         = "libsvtjpegxs",
+    CODEC_LONG_NAME("SVT JPEG XS(Scalable Video Technology for JPEG XS) 
decoder"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_JPEGXS,
+    .priv_data_size = sizeof(SvtJpegXsDecodeContext),
+    .init           = svt_jpegxs_dec_init,
+    .close          = svt_jpegxs_dec_free,
+    FF_CODEC_DECODE_CB(svt_jpegxs_dec_decode),
+    .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
+                      FF_CODEC_CAP_AUTO_THREADS,
+    .p.wrapper_name = "libsvtjpegxs",
+    .p.priv_class = &svtjpegxs_dec_class,
+};
diff --git a/libavcodec/libsvtjpegxsenc.c b/libavcodec/libsvtjpegxsenc.c
new file mode 100644
index 0000000000..d296e03170
--- /dev/null
+++ b/libavcodec/libsvtjpegxsenc.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright(c) 2024 Intel Corporation
+ *
+ * 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
+ */
+
+/*
+* Copyright(c) 2024 Intel Corporation
+* SPDX - License - Identifier: BSD - 2 - Clause - Patent
+*/
+
+#include <SvtJpegxsEnc.h>
+
+#include "libavutil/common.h"
+#include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/rational.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "encode.h"
+#include "profiles.h"
+
+typedef struct SvtJpegXsEncodeContext {
+    AVClass* class;
+
+    int decomp_v;
+    int decomp_h;
+    int quant;
+    int coding_signs_handling;
+    int coding_significance;
+    int coding_vpred;
+
+    svt_jpeg_xs_encoder_api_t encoder;
+    int bitstream_frame_size;
+} SvtJpegXsEncodeContext;
+
+static int svt_jpegxs_enc_encode(AVCodecContext* avctx, AVPacket* pkt,
+                                 const AVFrame* frame, int* got_packet)
+{
+    SvtJpegXsEncodeContext* svt_enc = avctx->priv_data;
+
+    svt_jpeg_xs_bitstream_buffer_t out_buf;
+    svt_jpeg_xs_image_buffer_t in_buf;
+    svt_jpeg_xs_frame_t enc_input;
+    svt_jpeg_xs_frame_t enc_output;
+
+    SvtJxsErrorType_t err = SvtJxsErrorNone;
+    uint32_t pixel_size = svt_enc->encoder.input_bit_depth <= 8 ? 1 : 2;
+
+    int ret = ff_get_encode_buffer(avctx, pkt, svt_enc->bitstream_frame_size, 
0);
+    if (ret < 0)
+        return ret;
+
+    out_buf.buffer = pkt->data;// output bitstream ptr
+    out_buf.allocation_size = pkt->size;// output bitstream size
+    out_buf.used_size = 0;
+
+    for (int comp = 0; comp < 3; comp++) {
+        // svt-jpegxs require stride in pixel's not in bytes, this means that 
for 10 bit-depth, stride is half the linesize
+        in_buf.stride[comp] = frame->linesize[comp] / pixel_size;
+        in_buf.data_yuv[comp] = frame->data[comp];
+        in_buf.alloc_size[comp] = in_buf.stride[comp] * 
svt_enc->encoder.source_height * pixel_size;
+    }
+
+    enc_input.bitstream = out_buf;
+    enc_input.image = in_buf;
+    enc_input.user_prv_ctx_ptr = pkt;
+
+    err = svt_jpeg_xs_encoder_send_picture(&svt_enc->encoder, &enc_input, 1 
/*blocking*/);
+    if (err != SvtJxsErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_send_picture 
failed\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    err = svt_jpeg_xs_encoder_get_packet(&svt_enc->encoder, &enc_output, 1 
/*blocking*/);
+    if (err != SvtJxsErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_get_packet failed\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    if (enc_output.user_prv_ctx_ptr != pkt) {
+        av_log(avctx, AV_LOG_ERROR, "Returned different user_prv_ctx_ptr than 
expected\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    pkt->size = enc_output.bitstream.used_size;
+
+    *got_packet = 1;
+
+    return 0;
+}
+
+static av_cold int svt_jpegxs_enc_free(AVCodecContext* avctx) {
+    SvtJpegXsEncodeContext* svt_enc = avctx->priv_data;
+
+    svt_jpeg_xs_encoder_close(&svt_enc->encoder);
+
+    return 0;
+}
+
+static int set_pix_fmt(AVCodecContext* avctx, svt_jpeg_xs_encoder_api_t 
*encoder)
+{
+    switch (avctx->pix_fmt) {
+    case AV_PIX_FMT_YUV420P:
+        encoder->input_bit_depth = 8;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420;
+        return 0;
+    case AV_PIX_FMT_YUV422P:
+        encoder->input_bit_depth = 8;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422;
+        return 0;
+    case AV_PIX_FMT_YUV444P:
+        encoder->input_bit_depth = 8;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB;
+        return 0;
+    case AV_PIX_FMT_YUV420P10LE:
+        encoder->input_bit_depth = 10;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420;
+        return 0;
+    case AV_PIX_FMT_YUV422P10LE:
+        encoder->input_bit_depth = 10;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422;
+        return 0;
+    case AV_PIX_FMT_YUV444P10LE:
+        encoder->input_bit_depth = 10;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB;
+        return 0;
+    case AV_PIX_FMT_YUV420P12LE:
+        encoder->input_bit_depth = 12;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420;
+        return 0;
+    case AV_PIX_FMT_YUV422P12LE:
+        encoder->input_bit_depth = 12;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422;
+        return 0;
+    case AV_PIX_FMT_YUV444P12LE:
+        encoder->input_bit_depth = 12;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB;
+        return 0;
+    case AV_PIX_FMT_YUV420P14LE:
+        encoder->input_bit_depth = 14;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV420;
+        return 0;
+    case AV_PIX_FMT_YUV422P14LE:
+        encoder->input_bit_depth = 14;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV422;
+        return 0;
+    case AV_PIX_FMT_YUV444P14LE:
+        encoder->input_bit_depth = 14;
+        encoder->colour_format = COLOUR_FORMAT_PLANAR_YUV444_OR_RGB;
+        return 0;
+    default:
+        break;
+    }
+    av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
+    return AVERROR_INVALIDDATA;
+}
+
+static av_cold int svt_jpegxs_enc_init(AVCodecContext* avctx) {
+    SvtJpegXsEncodeContext* svt_enc = avctx->priv_data;
+    AVRational bpp;
+    SvtJxsErrorType_t err;
+
+    err = 
svt_jpeg_xs_encoder_load_default_parameters(SVT_JPEGXS_API_VER_MAJOR, 
SVT_JPEGXS_API_VER_MINOR, &(svt_enc->encoder));
+    if (err != SvtJxsErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, 
"svt_jpeg_xs_encoder_load_default_parameters failed\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    svt_enc->encoder.source_width = avctx->width;
+    svt_enc->encoder.source_height = avctx->height;
+
+    set_pix_fmt(avctx, &(svt_enc->encoder));
+
+    svt_enc->encoder.threads_num = FFMIN(avctx->thread_count ? 
avctx->thread_count : av_cpu_count(), 64);
+
+    if (av_log_get_level() < AV_LOG_DEBUG)
+        svt_enc->encoder.verbose = VERBOSE_ERRORS;
+    else if (av_log_get_level() == AV_LOG_DEBUG)
+        svt_enc->encoder.verbose = VERBOSE_SYSTEM_INFO;
+    else
+        svt_enc->encoder.verbose = VERBOSE_WARNINGS;
+
+    if (avctx->bit_rate <= 0) {
+        av_log(avctx, AV_LOG_ERROR, "bitrate can't be 0\n");
+        return AVERROR(EINVAL);
+    }
+    if (avctx->framerate.num <= 0 || avctx->framerate.den <= 0) {
+        av_log(avctx, AV_LOG_ERROR, "framerate must be set\n");
+        return AVERROR(EINVAL);
+    }
+
+    av_reduce(&bpp.num, &bpp.den, avctx->bit_rate, (int64_t)avctx->width * 
avctx->height, INT_MAX);
+    bpp = av_div_q(bpp, avctx->framerate);
+    svt_enc->encoder.bpp_numerator   = bpp.num;
+    svt_enc->encoder.bpp_denominator = bpp.den;
+
+    if (svt_enc->decomp_v >= 0)
+        svt_enc->encoder.ndecomp_v = svt_enc->decomp_v;
+    if (svt_enc->decomp_h >= 0)
+        svt_enc->encoder.ndecomp_h = svt_enc->decomp_h;
+    if (svt_enc->quant >= 0)
+        svt_enc->encoder.quantization = svt_enc->quant;
+    if (svt_enc->coding_signs_handling >= 0)
+        svt_enc->encoder.coding_signs_handling = 
svt_enc->coding_signs_handling;
+    if (svt_enc->coding_significance >= 0)
+        svt_enc->encoder.coding_significance = svt_enc->coding_significance;
+    if (svt_enc->coding_vpred >= 0)
+        svt_enc->encoder.coding_vertical_prediction_mode = 
svt_enc->coding_vpred;
+    if (avctx->slices > 0)
+        svt_enc->encoder.slice_height = avctx->height / avctx->slices;
+
+    err = svt_jpeg_xs_encoder_init(SVT_JPEGXS_API_VER_MAJOR, 
SVT_JPEGXS_API_VER_MINOR, &svt_enc->encoder);
+    if (err != SvtJxsErrorNone) {
+        av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_encoder_init failed\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    svt_enc->bitstream_frame_size = (((int64_t)avctx->width * avctx->height *
+                                      svt_enc->encoder.bpp_numerator / 
svt_enc->encoder.bpp_denominator + 7) / 8);
+
+    return 0;
+}
+
+static const enum AVPixelFormat pix_fmts[] = {
+    AV_PIX_FMT_YUV420P,
+    AV_PIX_FMT_YUV422P,
+    AV_PIX_FMT_YUV444P,
+    AV_PIX_FMT_YUV420P10LE,
+    AV_PIX_FMT_YUV422P10LE,
+    AV_PIX_FMT_YUV444P10LE,
+    AV_PIX_FMT_YUV420P12LE,
+    AV_PIX_FMT_YUV422P12LE,
+    AV_PIX_FMT_YUV444P12LE,
+    AV_PIX_FMT_YUV420P14LE,
+    AV_PIX_FMT_YUV422P14LE,
+    AV_PIX_FMT_YUV444P14LE,
+    AV_PIX_FMT_NONE
+};
+
+#define OFFSET(x) offsetof(SvtJpegXsEncodeContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption svtjpegxs_enc_options[] = {
+    { "decomp_v",     "vertical decomposition level",                          
    OFFSET(decomp_v),              AV_OPT_TYPE_INT,  {.i64 = -1 }, -1, 2, VE },
+    { "decomp_h",     "horizontal decomposition level",                        
    OFFSET(decomp_h),              AV_OPT_TYPE_INT,  {.i64 = -1 }, -1, 5, VE },
+    { "quantization", "Quantization algorithm",                                
    OFFSET(quant),                 AV_OPT_TYPE_INT,  {.i64 = -1 }, -1, 1, VE, 
.unit = "quantization" },
+      { "deadzone",     NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, 
INT_MAX, VE, .unit = "quantization" },
+      { "uniform",      NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, 
INT_MAX, VE, .unit = "quantization" },
+    { "coding-signs", "Enable Signs handling strategy",                        
    OFFSET(coding_signs_handling), AV_OPT_TYPE_INT,  {.i64 = -1 }, -1, 2, VE, 
.unit = "coding-signs" },
+      { "disable",      NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, 
INT_MAX, VE, .unit = "coding-signs" },
+      { "fast",         NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, 
INT_MAX, VE, .unit = "coding-signs" },
+      { "full",         NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, INT_MIN, 
INT_MAX, VE, .unit = "coding-signs" },
+    { "coding-sigf",  "Enable Significance coding",                            
    OFFSET(coding_significance),   AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE },
+    { "coding-vpred", "Enable Vertical Prediction coding",                     
    OFFSET(coding_vpred),          AV_OPT_TYPE_INT,  {.i64 = -1 }, -1, 2, VE, 
.unit = "coding-vpred" },
+      { "disable",      NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, 
INT_MAX, VE, .unit = "coding-vpred" },
+      { "no_residuals", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, 
INT_MAX, VE, .unit = "coding-vpred" },
+      { "no_coeffs",    NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, INT_MIN, 
INT_MAX, VE, .unit = "coding-vpred" },
+    { NULL },
+};
+
+static const AVClass svtjpegxs_enc_class = {
+    .class_name = "libsvtjpegxs",
+    .item_name = av_default_item_name,
+    .option = svtjpegxs_enc_options,
+    .version = LIBAVUTIL_VERSION_INT,
+};
+
+const FFCodec ff_libsvtjpegxs_encoder = {
+    .p.name         = "libsvtjpegxs",
+    CODEC_LONG_NAME("SVT JPEG XS(Scalable Video Technology for JPEG XS) 
encoder"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_JPEGXS,
+    .priv_data_size = sizeof(SvtJpegXsEncodeContext),
+    .init           = svt_jpegxs_enc_init,
+    .close          = svt_jpegxs_enc_free,
+    FF_CODEC_ENCODE_CB(svt_jpegxs_enc_encode),
+    .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
+                      FF_CODEC_CAP_AUTO_THREADS,
+    CODEC_PIXFMTS_ARRAY(pix_fmts),
+    .p.wrapper_name = "libsvtjpegxs",
+    .p.priv_class = &svtjpegxs_enc_class,
+};
-- 
2.49.1


>From ceb2b0801202ec15618aa5ab7dabdbf3c7191e7c Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Tue, 2 Dec 2025 17:44:59 -0300
Subject: [PATCH 4/4] avformat: add a raw JPEG-XS muxer and demuxer

Signed-off-by: James Almer <[email protected]>
---
 libavformat/allformats.c |  1 +
 libavformat/img2.c       |  1 +
 libavformat/img2dec.c    | 10 ++++++++++
 libavformat/img2enc.c    |  2 +-
 4 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 3a025da3db..6ec361fb7b 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -549,6 +549,7 @@ extern const FFInputFormat  ff_image_j2k_pipe_demuxer;
 extern const FFInputFormat  ff_image_jpeg_pipe_demuxer;
 extern const FFInputFormat  ff_image_jpegls_pipe_demuxer;
 extern const FFInputFormat  ff_image_jpegxl_pipe_demuxer;
+extern const FFInputFormat  ff_image_jpegxs_pipe_demuxer;
 extern const FFInputFormat  ff_image_pam_pipe_demuxer;
 extern const FFInputFormat  ff_image_pbm_pipe_demuxer;
 extern const FFInputFormat  ff_image_pcx_pipe_demuxer;
diff --git a/libavformat/img2.c b/libavformat/img2.c
index 9981867f82..2c69a932da 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -92,6 +92,7 @@
     TAG(GEM,             timg     ) \
     TAG(VBN,             vbn      ) \
     TAG(JPEGXL,          jxl      ) \
+    TAG(JPEGXS,          jxs      ) \
     TAG(QOI,             qoi      ) \
     TAG(RADIANCE_HDR,    hdr      ) \
     TAG(WBMP,            wbmp     ) \
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index 1f7e0fcce1..8f1c9013ca 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -824,6 +824,15 @@ static int jpegxl_probe(const AVProbeData *p)
     return 0;
 }
 
+static int jpegxs_probe(const AVProbeData *p)
+{
+    const uint8_t *b = p->buf;
+
+    if (AV_RB32(b) == 0xff10ff50)
+         return AVPROBE_SCORE_EXTENSION + 1;
+    return 0;
+}
+
 static int pcx_probe(const AVProbeData *p)
 {
     const uint8_t *b = p->buf;
@@ -1204,6 +1213,7 @@ IMAGEAUTO_DEMUXER(gif,       GIF)
 IMAGEAUTO_DEMUXER_EXT(hdr,   RADIANCE_HDR, HDR)
 IMAGEAUTO_DEMUXER_EXT(j2k,   JPEG2000, J2K)
 IMAGEAUTO_DEMUXER_EXT(jpeg,  MJPEG, JPEG)
+IMAGEAUTO_DEMUXER(jpegxs,    JPEGXS)
 IMAGEAUTO_DEMUXER(jpegls,    JPEGLS)
 IMAGEAUTO_DEMUXER(jpegxl,    JPEGXL)
 IMAGEAUTO_DEMUXER(pam,       PAM)
diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index fb51151090..62ec5be64b 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -290,7 +290,7 @@ static const AVClass img2mux_class = {
 const FFOutputFormat ff_image2_muxer = {
     .p.name         = "image2",
     .p.long_name    = NULL_IF_CONFIG_SMALL("image2 sequence"),
-    .p.extensions   = 
"bmp,dpx,exr,jls,jpeg,jpg,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv,phm,"
+    .p.extensions   = 
"bmp,dpx,exr,jls,jpeg,jpg,jxs,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv,phm,"
                       
"png,ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,"
                       "im24,sunras,vbn,xbm,xface,pix,y,avif,qoi,hdr,wbmp",
     .priv_data_size = sizeof(VideoMuxData),
-- 
2.49.1

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

Reply via email to