Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: James Almer via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: James Almer <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PR] avcodec/cbs: add support for LCEVC bitstreams (PR #21789)
Date: Thu, 19 Feb 2026 01:01:17 -0000
Message-ID: <177146287775.25.119570817854103840@29965ddac10e> (raw)

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


From 464e9a505e0b55862f73fc499c742530ce2103d9 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 16 Feb 2026 11:58:46 -0300
Subject: [PATCH 1/3] avcodec/bsf/extract_extradata: add support for LCEVC

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/bsf/extract_extradata.c | 12 +++++
 libavcodec/lcevc.h                 | 84 ++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+)
 create mode 100644 libavcodec/lcevc.h

diff --git a/libavcodec/bsf/extract_extradata.c b/libavcodec/bsf/extract_extradata.c
index 43f4d62855..d005a57769 100644
--- a/libavcodec/bsf/extract_extradata.c
+++ b/libavcodec/bsf/extract_extradata.c
@@ -29,6 +29,7 @@
 #include "bytestream.h"
 #include "h2645_parse.h"
 #include "h264.h"
+#include "lcevc.h"
 #include "startcode.h"
 #include "vc1_common.h"
 #include "vvc.h"
@@ -167,6 +168,9 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
     static const int extradata_nal_types_vvc[] = {
         VVC_VPS_NUT, VVC_SPS_NUT, VVC_PPS_NUT,
     };
+    static const int extradata_nal_types_lcevc[] = {
+        LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT,
+    };
     static const int extradata_nal_types_hevc[] = {
         HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS,
     };
@@ -184,6 +188,9 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
     if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
         extradata_nal_types    = extradata_nal_types_vvc;
         nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_vvc);
+    } else if (ctx->par_in->codec_id == AV_CODEC_ID_LCEVC) {
+        extradata_nal_types    = extradata_nal_types_lcevc;
+        nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_lcevc);
     } else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
         extradata_nal_types    = extradata_nal_types_hevc;
         nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_hevc);
@@ -207,6 +214,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
             } else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
                 if (nal->type == HEVC_NAL_SPS) has_sps = 1;
                 if (nal->type == HEVC_NAL_VPS) has_vps = 1;
+            } else if (ctx->par_in->codec_id == AV_CODEC_ID_LCEVC) {
+                has_sps = 1;
             } else {
                 if (nal->type == H264_NAL_SPS) has_sps = 1;
             }
@@ -217,6 +226,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
 
     if (extradata_size &&
         ((ctx->par_in->codec_id == AV_CODEC_ID_VVC  && has_sps) ||
+         (ctx->par_in->codec_id == AV_CODEC_ID_LCEVC && has_sps) ||
          (ctx->par_in->codec_id == AV_CODEC_ID_HEVC && has_sps && has_vps) ||
          (ctx->par_in->codec_id == AV_CODEC_ID_H264 && has_sps))) {
         AVBufferRef *filtered_buf = NULL;
@@ -371,6 +381,7 @@ static const struct {
     { AV_CODEC_ID_CAVS,       extract_extradata_mpeg4   },
     { AV_CODEC_ID_H264,       extract_extradata_h2645   },
     { AV_CODEC_ID_HEVC,       extract_extradata_h2645   },
+    { AV_CODEC_ID_LCEVC,      extract_extradata_h2645   },
     { AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12  },
     { AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12  },
     { AV_CODEC_ID_MPEG4,      extract_extradata_mpeg4   },
@@ -441,6 +452,7 @@ static const enum AVCodecID codec_ids[] = {
     AV_CODEC_ID_CAVS,
     AV_CODEC_ID_H264,
     AV_CODEC_ID_HEVC,
+    AV_CODEC_ID_LCEVC,
     AV_CODEC_ID_MPEG1VIDEO,
     AV_CODEC_ID_MPEG2VIDEO,
     AV_CODEC_ID_MPEG4,
diff --git a/libavcodec/lcevc.h b/libavcodec/lcevc.h
new file mode 100644
index 0000000000..cfe4c1e6e1
--- /dev/null
+++ b/libavcodec/lcevc.h
@@ -0,0 +1,84 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * LCEVC common definitions
+ */
+
+#ifndef AVCODEC_LCEVC_H
+#define AVCODEC_LCEVC_H
+
+/*
+ * Table 17 — NAL unit type codes and NAL unit type classes in
+ * ISO/IEC 23094-2:2021
+ */
+enum {
+    LCEVC_UNSPEC0_NUT  = 0,
+    LCEVC_UNSPEC1_NUT  = 1,
+    LCEVC_UNSPEC2_NUT  = 2,
+    LCEVC_UNSPEC3_NUT  = 3,
+    LCEVC_UNSPEC4_NUT  = 4,
+    LCEVC_UNSPEC5_NUT  = 5,
+    LCEVC_UNSPEC6_NUT  = 6,
+    LCEVC_UNSPEC7_NUT  = 7,
+    LCEVC_UNSPEC8_NUT  = 8,
+    LCEVC_UNSPEC9_NUT  = 9,
+    LCEVC_UNSPEC10_NUT = 10,
+    LCEVC_UNSPEC11_NUT = 11,
+    LCEVC_UNSPEC12_NUT = 12,
+    LCEVC_UNSPEC13_NUT = 13,
+    LCEVC_UNSPEC14_NUT = 14,
+    LCEVC_UNSPEC15_NUT = 15,
+    LCEVC_UNSPEC16_NUT = 16,
+    LCEVC_UNSPEC17_NUT = 17,
+    LCEVC_UNSPEC18_NUT = 18,
+    LCEVC_UNSPEC19_NUT = 19,
+    LCEVC_UNSPEC20_NUT = 20,
+    LCEVC_UNSPEC21_NUT = 21,
+    LCEVC_UNSPEC22_NUT = 22,
+    LCEVC_UNSPEC23_NUT = 23,
+    LCEVC_UNSPEC24_NUT = 24,
+    LCEVC_UNSPEC25_NUT = 25,
+    LCEVC_UNSPEC26_NUT = 26,
+    LCEVC_UNSPEC27_NUT = 27,
+    LCEVC_NON_IDR_NUT  = 28,
+    LCEVC_IDR_NUT      = 29,
+    LCEVC_RSV_NUT      = 30,
+    LCEVC_UNSPEC31_NUT = 31,
+};
+
+/*
+ * Table 19 — Content of payload
+ */
+enum {
+    LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG    = 0,
+    LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG      = 1,
+    LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG     = 2,
+    LCEVC_PAYLOAD_TYPE_ENCODED_DATA       = 3,
+    LCEVC_PAYLOAD_TYPE_ENCODED_DATA_TILED = 4,
+    LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO    = 5,
+    LCEVC_PAYLOAD_TYPE_FILLER             = 6,
+};
+
+enum {
+    LCEVC_ADDITIONAL_INFO_TYPE_SEI        = 0,
+    LCEVC_ADDITIONAL_INFO_TYPE_VUI        = 1,
+};
+
+#endif /* AVCODEC_LCEVC_H */
-- 
2.52.0


From 5603cd678f91f8aa66b7187bb3d2738761d83a1e Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Mon, 16 Feb 2026 11:59:15 -0300
Subject: [PATCH 2/3] avcodec/h2645_parse: add support for LCEVC

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/h2645_parse.c | 63 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c
index fa57911c08..448f424b26 100644
--- a/libavcodec/h2645_parse.c
+++ b/libavcodec/h2645_parse.c
@@ -149,6 +149,47 @@ nsc:
     return si;
 }
 
+static const char *const lcevc_nal_type_name[32] = {
+    "UNSPEC0 ", // UNSPEC0
+    "UNSPEC1 ", // UNSPEC1
+    "UNSPEC2 ", // UNSPEC2
+    "UNSPEC3 ", // UNSPEC3
+    "UNSPEC4 ", // UNSPEC4
+    "UNSPEC5 ", // UNSPEC5
+    "UNSPEC6 ", // UNSPEC6
+    "UNSPEC7 ", // UNSPEC7
+    "UNSPEC8 ", // UNSPEC8
+    "UNSPEC9 ", // UNSPEC9
+    "UNSPEC10", // UNSPEC10
+    "UNSPEC11", // UNSPEC11
+    "UNSPEC12", // UNSPEC12
+    "UNSPEC13", // UNSPEC13
+    "UNSPEC14", // UNSPEC14
+    "UNSPEC15", // UNSPEC15
+    "UNSPEC16", // UNSPEC16
+    "UNSPEC17", // UNSPEC17
+    "UNSPEC18", // UNSPEC18
+    "UNSPEC19", // UNSPEC19
+    "UNSPEC20", // UNSPEC20
+    "UNSPEC21", // UNSPEC21
+    "UNSPEC22", // UNSPEC22
+    "UNSPEC23", // UNSPEC23
+    "UNSPEC24", // UNSPEC24
+    "UNSPEC25", // UNSPEC25
+    "UNSPEC26", // UNSPEC26
+    "UNSPEC27", // UNSPEC27
+    "LCEVC_NON_IDR", //LCEVC_NON_IDR
+    "LCEVC_IDR", // LCEVC_IDR
+    "LCEVC_RSV", // LCEVC_RSV
+    "UNSPEC31", // UNSPEC31
+};
+
+static const char *lcevc_nal_unit_name(int nal_type)
+{
+    av_assert0(nal_type >= 0 && nal_type < 32);
+    return lcevc_nal_type_name[nal_type];
+}
+
 static const char *const vvc_nal_type_name[32] = {
     "TRAIL_NUT", // VVC_TRAIL_NUT
     "STSA_NUT", // VVC_STSA_NUT
@@ -338,6 +379,26 @@ static int get_bit_length(H2645NAL *nal, int min_size, int skip_trailing_zeros)
  * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit,
  * 0 otherwise
  */
+
+static int lcevc_parse_nal_header(H2645NAL *nal, void *logctx)
+{
+    GetBitContext *gb = &nal->gb;
+
+    if (get_bits1(gb) != 0)     //forbidden_zero_bit
+        return AVERROR_INVALIDDATA;
+
+    if (get_bits1(gb) != 1)     //forbidden_one_bit
+        return AVERROR_INVALIDDATA;
+
+    nal->type = get_bits(gb, 5);
+
+    av_log(logctx, AV_LOG_DEBUG,
+           "nal_unit_type: %d(%s)\n",
+           nal->type, lcevc_nal_unit_name(nal->type));
+
+    return 0;
+}
+
 static int vvc_parse_nal_header(H2645NAL *nal, void *logctx)
 {
     GetBitContext *gb = &nal->gb;
@@ -582,6 +643,8 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length,
 
         if (codec_id == AV_CODEC_ID_VVC)
             ret = vvc_parse_nal_header(nal, logctx);
+        else if (codec_id == AV_CODEC_ID_LCEVC)
+            ret = lcevc_parse_nal_header(nal, logctx);
         else if (codec_id == AV_CODEC_ID_HEVC) {
             ret = hevc_parse_nal_header(nal, logctx);
             if (nal->nuh_layer_id == 63)
-- 
2.52.0


From f8af34880470dbdad8f52636b5fccb53d0a5de8b Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Wed, 18 Feb 2026 21:15:17 -0300
Subject: [PATCH 3/3] avcodec/cbs: add support for LCEVC bitstreams

As defined on ISO/IEC 23094-2:2021/FDAM 1:2023

Signed-off-by: James Almer <jamrial@gmail.com>
---
 configure                              |   2 +
 libavcodec/Makefile                    |   1 +
 libavcodec/cbs.c                       |   6 +
 libavcodec/cbs_h2645.c                 | 333 +++++++++++++++
 libavcodec/cbs_internal.h              |   4 +
 libavcodec/cbs_lcevc.c                 | 112 +++++
 libavcodec/cbs_lcevc.h                 | 263 ++++++++++++
 libavcodec/cbs_lcevc_syntax_template.c | 569 +++++++++++++++++++++++++
 libavformat/cbs.h                      |   1 +
 9 files changed, 1291 insertions(+)
 create mode 100644 libavcodec/cbs_lcevc.c
 create mode 100644 libavcodec/cbs_lcevc.h
 create mode 100644 libavcodec/cbs_lcevc_syntax_template.c

diff --git a/configure b/configure
index da93aaf661..e959444449 100755
--- a/configure
+++ b/configure
@@ -2693,6 +2693,7 @@ CONFIG_EXTRA="
     cbs_h265
     cbs_h266
     cbs_jpeg
+    cbs_lcevc
     cbs_mpeg2
     cbs_vp8
     cbs_vp9
@@ -3005,6 +3006,7 @@ cbs_h264_select="cbs"
 cbs_h265_select="cbs"
 cbs_h266_select="cbs"
 cbs_jpeg_select="cbs"
+cbs_lcevc_select="cbs"
 cbs_mpeg2_select="cbs"
 cbs_vp8_select="cbs"
 cbs_vp9_select="cbs"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3d60347a19..4c104757d1 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -91,6 +91,7 @@ OBJS-$(CONFIG_CBS_AV1)                 += cbs_av1.o
 OBJS-$(CONFIG_CBS_H264)                += cbs_h2645.o cbs_sei.o h2645_parse.o
 OBJS-$(CONFIG_CBS_H265)                += cbs_h2645.o cbs_sei.o h2645_parse.o
 OBJS-$(CONFIG_CBS_H266)                += cbs_h2645.o cbs_sei.o h2645_parse.o
+OBJS-$(CONFIG_CBS_LCEVC)               += cbs_h2645.o cbs_sei.o h2645_parse.o cbs_lcevc.o
 OBJS-$(CONFIG_CBS_JPEG)                += cbs_jpeg.o
 OBJS-$(CONFIG_CBS_MPEG2)               += cbs_mpeg2.o
 OBJS-$(CONFIG_CBS_VP8)                 += cbs_vp8.o vp8data.o
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 41c8184434..b045b73b68 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -46,6 +46,9 @@ static const CodedBitstreamType *const cbs_type_table[] = {
 #if CBS_H266
     &CBS_FUNC(type_h266),
 #endif
+#if CBS_LCEVC
+    &CBS_FUNC(type_lcevc),
+#endif
 #if CBS_JPEG
     &CBS_FUNC(type_jpeg),
 #endif
@@ -76,6 +79,9 @@ const enum AVCodecID CBS_FUNC(all_codec_ids)[] = {
 #if CBS_H266
     AV_CODEC_ID_H266,
 #endif
+#if CBS_LCEVC
+    AV_CODEC_ID_LCEVC,
+#endif
 #if CBS_JPEG
     AV_CODEC_ID_MJPEG,
 #endif
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index 0dd256ada0..cc553211dc 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -26,6 +26,7 @@
 #include "cbs_h264.h"
 #include "cbs_h265.h"
 #include "cbs_h266.h"
+#include "cbs_lcevc.h"
 #include "h264.h"
 #include "h2645_parse.h"
 #include "libavutil/refstruct.h"
@@ -137,6 +138,37 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
     return 0;
 }
 
+static int cbs_read_multi_byte(CodedBitstreamContext *ctx, GetBitContext *gbc,
+                               const char *name, uint32_t *write_to)
+{
+    uint64_t value;
+    uint32_t byte;
+    int i;
+
+    CBS_TRACE_READ_START();
+
+    value = 0;
+    for (i = 0; i < 10; i++) {
+        if (get_bits_left(gbc) < 8) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid multi byte at "
+                   "%s: bitstream ended.\n", name);
+            return AVERROR_INVALIDDATA;
+        }
+        byte = get_bits(gbc, 8);
+        value = (value << 7) | (byte & 0x7f);
+        if (!(byte & 0x80))
+            break;
+    }
+
+    if (value > UINT32_MAX)
+        return AVERROR_INVALIDDATA;
+
+    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
+
+    *write_to = value;
+    return 0;
+}
+
 static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
                                const char *name, const int *subscripts,
                                uint32_t value,
@@ -209,6 +241,32 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
     return 0;
 }
 
+static int cbs_write_multi_byte(CodedBitstreamContext *ctx, PutBitContext *pbc,
+                               const char *name, uint32_t value)
+{
+    int len, i;
+    uint8_t byte;
+
+    CBS_TRACE_WRITE_START();
+
+    len = (av_log2(value) + 7) / 7;
+
+    for (i = len - 1; i >= 0; i--) {
+        if (put_bits_left(pbc) < 8)
+            return AVERROR(ENOSPC);
+
+        byte = value >> (7 * i) & 0x7f;
+        if (i > 0)
+            byte |= 0x80;
+
+        put_bits(pbc, 8, byte);
+    }
+
+    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
+
+    return 0;
+}
+
 // payload_extension_present() - true if we are before the last 1-bit
 // in the payload structure, which must be in the last byte.
 static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t payload_size,
@@ -234,6 +292,7 @@ static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t paylo
 #define FUNC_H264(name) FUNC_NAME1(READWRITE, h264, name)
 #define FUNC_H265(name) FUNC_NAME1(READWRITE, h265, name)
 #define FUNC_H266(name) FUNC_NAME1(READWRITE, h266, name)
+#define FUNC_LCEVC(name) FUNC_NAME1(READWRITE, lcevc, name)
 #define FUNC_SEI(name)  FUNC_NAME1(READWRITE, sei,  name)
 
 #define SEI_FUNC(name, args) \
@@ -246,6 +305,16 @@ static int FUNC(name ## _internal)(CodedBitstreamContext *ctx, \
 } \
 static int FUNC(name) args
 
+#define LCEVC_BLOCK_FUNC(name, args) \
+static int FUNC(name) args;  \
+static int FUNC(name ## _internal)(CodedBitstreamContext *ctx,       \
+                                   RWContext *rw, void *cur,         \
+                                   LCEVCProcessBlockState *state) \
+{ \
+    return FUNC(name)(ctx, rw, cur, state); \
+} \
+static int FUNC(name) args
+
 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
 
 #define u(width, name, range_min, range_max) \
@@ -274,6 +343,8 @@ static int FUNC(name) args
         xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__)
 #define ses(name, range_min, range_max, subs, ...) \
         xse(name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define mb(name) \
+        xmb(name, current->name)
 
 #define fixed(width, name, value) do { \
         av_unused uint32_t fixed_value = value; \
@@ -319,6 +390,11 @@ static int FUNC(name) args
                                  &value, range_min, range_max)); \
         var = value; \
     } while (0)
+#define xmb(name, var) do { \
+        uint32_t value; \
+        CHECK(cbs_read_multi_byte(ctx, rw, #name, &value)); \
+        var = value; \
+    } while (0)
 
 
 #define infer(name, value) do { \
@@ -337,6 +413,10 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
     return 0;
 }
 
+static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
+                                      PutBitContext *pbc, const uint8_t *data,
+                                      size_t data_size, int data_bit_start);
+
 #define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw))
 
 #define bit_position(rw)   (get_bits_count(rw))
@@ -355,6 +435,10 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
 #include "cbs_sei_syntax_template.c"
 #undef FUNC
 
+#define FUNC(name) FUNC_LCEVC(name)
+#include "cbs_lcevc_syntax_template.c"
+#undef FUNC
+
 #undef allocate
 
 /* The other code uses the refstruct API for the allocation
@@ -387,11 +471,13 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
 #undef xi
 #undef xue
 #undef xse
+#undef xmb
 #undef infer
 #undef more_rbsp_data
 #undef bit_position
 #undef byte_alignment
 #undef allocate
+#undef allocate_struct
 
 
 #define WRITE
@@ -427,6 +513,10 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
                                   SUBSCRIPTS(subs, __VA_ARGS__), \
                                   value, range_min, range_max)); \
     } while (0)
+#define xmb(name, var) do { \
+        uint32_t value = var; \
+        CHECK(cbs_write_multi_byte(ctx, rw, #name, value)); \
+    } while (0)
 
 #define infer(name, value) do { \
         if (current->name != (value)) { \
@@ -467,6 +557,10 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
 #include "cbs_h266_syntax_template.c"
 #undef FUNC
 
+#define FUNC(name) FUNC_LCEVC(name)
+#include "cbs_lcevc_syntax_template.c"
+#undef FUNC
+
 #undef WRITE
 #undef READWRITE
 #undef RWContext
@@ -475,6 +569,7 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
 #undef xi
 #undef xue
 #undef xse
+#undef xmb
 #undef u
 #undef i
 #undef flag
@@ -736,6 +831,60 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx,
             if (err < 0)
                 return err;
         }
+    } else if (header && frag->data[0] && codec_id == AV_CODEC_ID_LCEVC) {
+        // LVCC header.
+        size_t size, start, end;
+        int i, j, nb_arrays, nal_unit_type, nb_nals, version;
+
+        priv->mp4 = 1;
+
+        bytestream2_init(&gbc, frag->data, frag->data_size);
+
+        if (bytestream2_get_bytes_left(&gbc) < 14)
+            return AVERROR_INVALIDDATA;
+
+        version = bytestream2_get_byte(&gbc);
+        if (version != 1) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid LVCC header: "
+                   "first byte %u.\n", version);
+            return AVERROR_INVALIDDATA;
+        }
+
+        bytestream2_skip(&gbc, 3);
+        priv->nal_length_size = (bytestream2_get_byte(&gbc) >> 6) + 1;
+
+        bytestream2_skip(&gbc, 9);
+        nb_arrays = bytestream2_get_byte(&gbc);
+
+        for (i = 0; i < nb_arrays; i++) {
+            nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f;
+            nb_nals = bytestream2_get_be16(&gbc);
+
+            start = bytestream2_tell(&gbc);
+            for (j = 0; j < nb_nals; j++) {
+                if (bytestream2_get_bytes_left(&gbc) < 2)
+                    return AVERROR_INVALIDDATA;
+                size = bytestream2_get_be16(&gbc);
+                if (bytestream2_get_bytes_left(&gbc) < size)
+                    return AVERROR_INVALIDDATA;
+                bytestream2_skip(&gbc, size);
+            }
+            end = bytestream2_tell(&gbc);
+
+            err = ff_h2645_packet_split(&priv->read_packet,
+                                        frag->data + start, end - start,
+                                        ctx->log_ctx, 2, AV_CODEC_ID_LCEVC,
+                                        H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF);
+            if (err < 0) {
+                av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split "
+                       "LVCC array %d (%d NAL units of type %d).\n",
+                       i, nb_nals, nal_unit_type);
+                return err;
+            }
+            err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet);
+            if (err < 0)
+                return err;
+        }
     } else {
         int flags = (H2645_FLAG_IS_NALFF * !!priv->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF;
         // Annex B, or later MP4 with already-known parameters.
@@ -1245,6 +1394,59 @@ static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx,
     return 0;
 }
 
+
+static int cbs_lcevc_read_nal_unit(CodedBitstreamContext *ctx,
+                                   CodedBitstreamUnit *unit)
+{
+    GetBitContext gbc;
+    int err;
+
+    err = init_get_bits8(&gbc, unit->data, unit->data_size);
+    if (err < 0)
+        return err;
+
+    err = ff_cbs_alloc_unit_content(ctx, unit);
+    if (err < 0)
+        return err;
+
+    switch (unit->type) {
+    case LCEVC_NON_IDR_NUT:
+    case LCEVC_IDR_NUT:
+        {
+            LCEVCRawNAL *nal = unit->content;
+            LCEVCRawProcessBlockList *block_list;
+
+            err = cbs_lcevc_read_nal(ctx, &gbc, unit->content, unit->type);
+
+            if (err < 0)
+                return err;
+
+            block_list = &nal->process_block_list;
+            for (int i = 0; i < block_list->nb_blocks; i++) {
+                LCEVCRawProcessBlock *block = &block_list->blocks[i];
+                LCEVCRawEncodedData *slice;
+
+                if (block->payload_type != LCEVC_PAYLOAD_TYPE_ENCODED_DATA)
+                    continue;
+
+                slice = block->payload;
+                slice->data_ref = av_buffer_ref(unit->data_ref);
+                if (!slice->data_ref)
+                     return AVERROR(ENOMEM);
+                slice->data = unit->data + slice->header_size;
+            }
+
+            if (err < 0)
+                return err;
+        }
+        break;
+    default:
+        return AVERROR(ENOSYS);
+    }
+
+    return 0;
+}
+
 static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
                                       PutBitContext *pbc, const uint8_t *data,
                                       size_t data_size, int data_bit_start)
@@ -1814,6 +2016,31 @@ static int cbs_h266_write_nal_unit(CodedBitstreamContext *ctx,
     return 0;
 }
 
+static int cbs_lcevc_write_nal_unit(CodedBitstreamContext *ctx,
+                                    CodedBitstreamUnit *unit,
+                                    PutBitContext *pbc)
+{
+    int err;
+
+    switch (unit->type) {
+    case LCEVC_NON_IDR_NUT:
+    case LCEVC_IDR_NUT:
+        {
+            err = cbs_lcevc_write_nal(ctx, pbc, unit->content, unit->type);
+
+            if (err < 0)
+                return err;
+        }
+        break;
+    default:
+        av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for "
+               "NAL unit type %"PRIu32".\n", unit->type);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    return 0;
+}
+
 static int cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id,
                                              CodedBitstreamUnitType type,
                                              int nal_unit_index)
@@ -1991,6 +2218,23 @@ static av_cold void cbs_h266_close(CodedBitstreamContext *ctx)
     ff_h2645_packet_uninit(&h266->common.read_packet);
  }
 
+static av_cold void cbs_lcevc_flush(CodedBitstreamContext *ctx)
+{
+    CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
+
+    av_refstruct_unref(&lcevc->sc);
+    av_refstruct_unref(&lcevc->gc);
+    av_refstruct_unref(&lcevc->pc);
+}
+
+static av_cold void cbs_lcevc_close(CodedBitstreamContext *ctx)
+{
+    CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
+
+    cbs_lcevc_flush(ctx);
+    ff_h2645_packet_uninit(&lcevc->common.read_packet);
+}
+
 static void cbs_h264_free_sei(AVRefStructOpaque unused, void *content)
 {
     H264RawSEI *sei = content;
@@ -2095,6 +2339,19 @@ static CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = {
     CBS_UNIT_TYPE_END_OF_LIST
 };
 
+static void cbs_lcevc_free_nal(AVRefStructOpaque unused, void *content)
+{
+    LCEVCRawNAL *nal = content;
+    ff_cbs_lcevc_free_process_block_list(&nal->process_block_list);
+}
+
+static CodedBitstreamUnitTypeDescriptor cbs_lcevc_unit_types[] = {
+    CBS_UNIT_TYPES_COMPLEX((LCEVC_NON_IDR_NUT, LCEVC_IDR_NUT),
+                           LCEVCRawNAL, cbs_lcevc_free_nal),
+
+    CBS_UNIT_TYPE_END_OF_LIST
+};
+
 const CodedBitstreamType ff_cbs_type_h264 = {
     .codec_id          = AV_CODEC_ID_H264,
 
@@ -2145,6 +2402,75 @@ const CodedBitstreamType ff_cbs_type_h266 = {
     .close             = &cbs_h266_close,
 };
 
+const CodedBitstreamType ff_cbs_type_lcevc = {
+    .codec_id          = AV_CODEC_ID_LCEVC,
+
+    .priv_data_size    = sizeof(CodedBitstreamLCEVCContext),
+
+    .unit_types        = cbs_lcevc_unit_types,
+
+    .split_fragment    = &cbs_h2645_split_fragment,
+    .read_unit         = &cbs_lcevc_read_nal_unit,
+    .write_unit        = &cbs_lcevc_write_nal_unit,
+    .assemble_fragment = &cbs_h2645_assemble_fragment,
+
+    .flush             = &cbs_lcevc_flush,
+    .close             = &cbs_lcevc_close,
+};
+
+// Macro for the read/write pair.
+#define LCEVC_PROCESS_BLOCK_RW(codec, name) \
+    .read  = cbs_ ## codec ## _read_  ## name ## _internal, \
+    .write = cbs_ ## codec ## _write_ ## name ## _internal
+
+static const LCEVCProcessBlockTypeDescriptor cbs_lcevc_process_block_types[] = {
+    {
+        LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG,
+        sizeof(LCEVCRawSequenceConfig),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, sequence_config),
+    },
+    {
+        LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG,
+        sizeof(LCEVCRawGlobalConfig),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, global_config),
+    },
+    {
+        LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG,
+        sizeof(LCEVCRawPictureConfig),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, picture_config),
+    },
+    {
+        LCEVC_PAYLOAD_TYPE_ENCODED_DATA,
+        sizeof(LCEVCRawEncodedData),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, encoded_data),
+    },
+    {
+        LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO,
+        sizeof(LCEVCRawAdditionalInfo),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, additional_info),
+    },
+    {
+        LCEVC_PAYLOAD_TYPE_FILLER,
+        sizeof(LCEVCRawFiller),
+        LCEVC_PROCESS_BLOCK_RW(lcevc, filler),
+    },
+    LCEVC_PROCESS_BLOCK_TYPE_END,
+};
+
+const LCEVCProcessBlockTypeDescriptor
+    *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx,
+                                          int payload_type)
+{
+    int i;
+
+    for (i = 0; cbs_lcevc_process_block_types[i].payload_type >= 0; i++) {
+        if (cbs_lcevc_process_block_types[i].payload_type == payload_type)
+            return &cbs_lcevc_process_block_types[i];
+    }
+
+    return NULL;
+}
+
 // Macro for the read/write pair.
 #define SEI_MESSAGE_RW(codec, name) \
     .read  = cbs_ ## codec ## _read_  ## name ## _internal, \
@@ -2328,6 +2654,10 @@ static const SEIMessageTypeDescriptor cbs_sei_h266_types[] = {
     SEI_MESSAGE_TYPE_END
 };
 
+static const SEIMessageTypeDescriptor cbs_sei_lcevc_types[] = {
+    SEI_MESSAGE_TYPE_END
+};
+
 static const SEIMessageTypeDescriptor cbs_sei_h274_types[] = {
     {
         SEI_TYPE_FILM_GRAIN_CHARACTERISTICS,
@@ -2366,6 +2696,9 @@ const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx,
     case AV_CODEC_ID_H266:
         codec_list = cbs_sei_h266_types;
         break;
+    case AV_CODEC_ID_LCEVC:
+        codec_list = cbs_sei_lcevc_types;
+        break;
     default:
         return NULL;
     }
diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
index 8ca53ff3ce..2af8075f78 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -57,6 +57,9 @@
 #ifndef CBS_H266
 #define CBS_H266 CONFIG_CBS_H266
 #endif
+#ifndef CBS_LCEVC
+#define CBS_LCEVC CONFIG_CBS_LCEVC
+#endif
 #ifndef CBS_JPEG
 #define CBS_JPEG CONFIG_CBS_JPEG
 #endif
@@ -391,6 +394,7 @@ extern const CodedBitstreamType CBS_FUNC(type_av1);
 extern const CodedBitstreamType CBS_FUNC(type_h264);
 extern const CodedBitstreamType CBS_FUNC(type_h265);
 extern const CodedBitstreamType CBS_FUNC(type_h266);
+extern const CodedBitstreamType CBS_FUNC(type_lcevc);
 extern const CodedBitstreamType CBS_FUNC(type_jpeg);
 extern const CodedBitstreamType CBS_FUNC(type_mpeg2);
 extern const CodedBitstreamType CBS_FUNC(type_vp8);
diff --git a/libavcodec/cbs_lcevc.c b/libavcodec/cbs_lcevc.c
new file mode 100644
index 0000000000..7dcf709c94
--- /dev/null
+++ b/libavcodec/cbs_lcevc.c
@@ -0,0 +1,112 @@
+/*
+ * 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 "libavutil/mem.h"
+#include "cbs.h"
+#include "cbs_internal.h"
+#include "cbs_lcevc.h"
+#include "libavutil/refstruct.h"
+
+static void free_picture_config(AVRefStructOpaque unused, void *obj)
+{
+    LCEVCRawPictureConfig *picture_config = obj;
+
+    av_refstruct_unref(&picture_config->gc);
+}
+
+static void free_encoded_data(AVRefStructOpaque unused, void *obj)
+{
+    LCEVCRawEncodedData *slice = obj;
+
+    av_buffer_unref(&slice->data_ref);
+
+    av_refstruct_unref(&slice->sc);
+    av_refstruct_unref(&slice->gc);
+    av_refstruct_unref(&slice->pc);
+}
+
+static void free_additional_info(AVRefStructOpaque unused, void *obj)
+{
+    LCEVCRawAdditionalInfo *additional_info = obj;
+    SEIRawMessage *message = &additional_info->sei;
+
+    av_refstruct_unref(&additional_info->payload_ref);
+    av_refstruct_unref(&message->payload_ref);
+    av_refstruct_unref(&message->extension_data);
+}
+
+int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block,
+                                             const LCEVCProcessBlockTypeDescriptor *desc)
+{
+    void (*free_func)(AVRefStructOpaque, void*);
+
+    av_assert0(block->payload     == NULL &&
+               block->payload_ref == NULL);
+    block->payload_type = desc->payload_type;
+
+    if (desc->payload_type == LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG)
+        free_func = &free_picture_config;
+    else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ENCODED_DATA)
+        free_func = &free_encoded_data;
+    else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO)
+        free_func = &free_additional_info;
+    else
+        free_func = NULL;
+
+    block->payload_ref = av_refstruct_alloc_ext(desc->payload_size, 0,
+                                                NULL, free_func);
+    if (!block->payload_ref)
+        return AVERROR(ENOMEM);
+    block->payload = block->payload_ref;
+
+    return 0;
+}
+
+int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list)
+{
+    void *ptr;
+    int old_count = list->nb_blocks_allocated;
+
+    av_assert0(list->nb_blocks <= old_count);
+    if (list->nb_blocks + 1 > old_count) {
+        int new_count = 2 * old_count + 1;
+
+        ptr = av_realloc_array(list->blocks,
+                               new_count, sizeof(*list->blocks));
+        if (!ptr)
+            return AVERROR(ENOMEM);
+
+        list->blocks = ptr;
+        list->nb_blocks_allocated = new_count;
+
+        // Zero the newly-added entries.
+        memset(list->blocks + old_count, 0,
+               (new_count - old_count) * sizeof(*list->blocks));
+    }
+    ++list->nb_blocks;
+    return 0;
+}
+
+void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list)
+{
+    for (int i = 0; i < list->nb_blocks; i++) {
+        LCEVCRawProcessBlock *block = &list->blocks[i];
+        av_refstruct_unref(&block->payload_ref);
+    }
+    av_free(list->blocks);
+}
diff --git a/libavcodec/cbs_lcevc.h b/libavcodec/cbs_lcevc.h
new file mode 100644
index 0000000000..66b5cbd081
--- /dev/null
+++ b/libavcodec/cbs_lcevc.h
@@ -0,0 +1,263 @@
+/*
+ * 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_CBS_LCEVC_H
+#define AVCODEC_CBS_LCEVC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "cbs_h2645.h"
+#include "cbs_sei.h"
+#include "lcevc.h"
+
+typedef struct LCEVCRawNALUnitHeader {
+    uint8_t nal_unit_type;
+    uint16_t reserved_flag;
+} LCEVCRawNALUnitHeader;
+
+typedef struct  LCEVCRawSequenceConfig {
+    uint8_t  profile_idc;
+    uint8_t  level_idc;
+    uint8_t  sublevel_idc;
+    uint8_t  conformance_window_flag;
+    uint8_t  reserved_zeros_5bit;
+    uint8_t  extended_profile_idc;
+    uint8_t  extended_level_idc;
+    uint8_t  reserved_zeros_1bit;
+    uint32_t  conf_win_left_offset;
+    uint32_t  conf_win_right_offset;
+    uint32_t  conf_win_top_offset;
+    uint32_t  conf_win_bottom_offset;
+} LCEVCRawSequenceConfig;
+
+typedef struct  LCEVCRawGlobalConfig {
+    uint8_t  processed_planes_type_flag;
+    uint8_t  resolution_type;
+    uint8_t  transform_type;
+    uint8_t  chroma_sampling_type;
+    uint8_t  base_depth_type;
+    uint8_t  enhancement_depth_type;
+    uint8_t  temporal_step_width_modifier_signalled_flag;
+    uint8_t  predicted_residual_mode_flag;
+    uint8_t  temporal_tile_intra_signalling_enabled_flag;
+    uint8_t  temporal_enabled_flag;
+    uint8_t  upsample_type;
+    uint8_t  level1_filtering_signalled_flag;
+    uint8_t  scaling_mode_level1;
+    uint8_t  scaling_mode_level2;
+    uint8_t  tile_dimensions_type;
+    uint8_t  user_data_enabled;
+    uint8_t  level1_depth_flag;
+    uint8_t  chroma_step_width_flag;
+    uint8_t  planes_type;
+    uint8_t  reserved_zeros_4bit;
+    uint8_t  temporal_step_width_modifier;
+    uint16_t  upsampler_coeff1;
+    uint16_t  upsampler_coeff2;
+    uint16_t  upsampler_coeff3;
+    uint16_t  upsampler_coeff4;
+    uint8_t  level1_filtering_first_coefficient;
+    uint8_t  level1_filtering_second_coefficient;
+    uint16_t  custom_tile_width;
+    uint16_t  custom_tile_height;
+    uint16_t  reserved_zeros_5bit;
+    uint8_t  compression_type_entropy_enabled_per_tile_flag;
+    uint8_t  compression_type_size_per_tile;
+    uint16_t  custom_resolution_width;
+    uint16_t  custom_resolution_height;
+    uint8_t  chroma_step_width_multiplier;
+} LCEVCRawGlobalConfig;
+
+typedef struct  LCEVCRawPictureConfig {
+    uint8_t  no_enhancement_bit_flag;
+    uint8_t  quant_matrix_mode;
+    uint8_t  dequant_offset_signalled_flag;
+    uint8_t  picture_type_bit_flag;
+    uint8_t  temporal_refresh_bit_flag;
+    uint8_t  step_width_sublayer1_enabled_flag;
+    uint16_t  step_width_sublayer2;
+    uint8_t  dithering_control_flag;
+    uint8_t  reserved_zeros_4bit;
+    uint8_t  temporal_signalling_present_flag;
+    uint8_t  field_type_bit_flag;
+    uint8_t  reserved_zeros_7bit;
+    uint16_t  step_width_sublayer1;
+    uint8_t  level1_filtering_enabled_flag;
+    uint8_t  qm_coefficient_0[16];
+    uint8_t  qm_coefficient_1[16];
+    uint8_t  dequant_offset_mode_flag;
+    uint8_t  dequant_offset;
+    uint8_t  dithering_type;
+    uint8_t  reserverd_zero;
+    uint8_t  dithering_strength;
+    uint8_t  reserved_zeros_5bit;
+
+    LCEVCRawGlobalConfig   *gc; ///< RefStruct references
+} LCEVCRawPictureConfig;
+
+typedef struct LCEVCRawEncodedData {
+    LCEVCRawNALUnitHeader nal_unit_header;
+
+    uint8_t surfaces_entropy_enabled_flag[3][3][16];
+    uint8_t surfaces_rle_only_flag[3][3][16];
+    uint8_t temporal_surfaces_entropy_enabled_flag[3];
+    uint8_t temporal_surfaces_rle_only_flag[3];
+
+    uint8_t     *data;
+    AVBufferRef *data_ref;
+    size_t       header_size;
+    size_t       data_size;
+
+    LCEVCRawSequenceConfig *sc; ///< RefStruct references
+    LCEVCRawGlobalConfig   *gc; ///< RefStruct references
+    LCEVCRawPictureConfig  *pc; ///< RefStruct references
+} LCEVCRawEncodedData;
+
+typedef struct LCEVCRawVUI {
+    uint8_t  aspect_ratio_info_present_flag;
+    uint8_t  aspect_ratio_idc;
+    uint16_t  sar_width;
+    uint8_t  sar_height;
+    uint8_t  overscan_info_present_flag;
+    uint8_t  overscan_appropriate_flag;
+    uint8_t  video_signal_type_present_flag;
+    uint8_t  video_format;
+    uint8_t  video_full_range_flag;
+    uint8_t  colour_description_present_flag;
+    uint8_t  colour_primaries;
+    uint8_t  transfer_characteristics;
+    uint8_t  matrix_coefficients;
+    uint8_t  chroma_loc_info_present_flag;
+    uint8_t  chroma_sample_loc_type_top_field;
+    uint8_t  chroma_sample_loc_type_bottom_field;
+} LCEVCRawVUI;
+
+typedef struct LCEVCRawSharpenFilter {
+    uint8_t  sharpen_type;
+    uint8_t  sharpen_strength;
+} LCEVCRawSharpenFilter;
+
+typedef struct LCEVCRawAdditionalInfo {
+    uint8_t additional_info_type;
+    uint8_t payload_type;
+
+    SEIRawMessage         sei;
+    LCEVCRawVUI           vui;
+    LCEVCRawSharpenFilter sfilter;
+
+    uint32_t     payload_size;
+    void        *payload;
+    void        *payload_ref;    ///< RefStruct reference
+} LCEVCRawAdditionalInfo;
+
+typedef struct LCEVCRawFiller {
+    uint32_t filler_size;
+} LCEVCRawFiller;
+
+typedef struct LCEVCRawProcessBlock {
+    uint32_t     payload_type;
+    uint32_t     payload_size;
+    void        *payload;
+    void        *payload_ref;    ///< RefStruct reference
+} LCEVCRawProcessBlock;
+
+typedef struct LCEVCRawProcessBlockList {
+    LCEVCRawProcessBlock *blocks;
+    int         nb_blocks;
+    int         nb_blocks_allocated;
+} LCEVCRawProcessBlockList;
+
+typedef struct LCEVCRawNAL {
+    LCEVCRawNALUnitHeader nal_unit_header;
+
+    LCEVCRawProcessBlockList process_block_list;
+} LCEVCRawNAL;
+
+typedef struct LCEVCProcessBlockState {
+    // The type of the payload being written.
+    uint32_t payload_type;
+    // When reading, contains the size of the payload to allow finding the
+    // end of variable-length fields (such as user_data_payload_byte[]).
+    // (When writing, the size will be derived from the total number of
+    // bytes actually written.)
+    uint32_t payload_size;
+} LCEVCProcessBlockState;
+
+typedef int (*LCEVCRawProcessBlockReadFunction)(CodedBitstreamContext *ctx,
+                                      struct GetBitContext *rw,
+                                      void *current,
+                                      LCEVCProcessBlockState *sei);
+
+typedef int (*LCEVCRawProcessBlockWriteFunction)(CodedBitstreamContext *ctx,
+                                       struct PutBitContext *rw,
+                                       void *current,
+                                       LCEVCProcessBlockState *sei);
+
+typedef struct LCEVCProcessBlockTypeDescriptor {
+    // Payload type for the block.  (-1 in this field ends a list.)
+    int     payload_type;
+    // Size of the decomposed structure.
+    size_t  payload_size;
+    // Read bitstream into Process Block.
+    LCEVCRawProcessBlockReadFunction  read;
+    // Write bitstream from Process Block.
+    LCEVCRawProcessBlockWriteFunction write;
+} LCEVCProcessBlockTypeDescriptor;
+
+// End-of-list sentinel element.
+#define LCEVC_PROCESS_BLOCK_TYPE_END { .payload_type = -1 }
+
+typedef struct CodedBitstreamLCEVCContext {
+    // Reader/writer context in common with the H.264 implementation.
+    CodedBitstreamH2645Context common;
+
+    // All currently available parameter sets.  These are updated when
+    // any parameter set NAL unit is read/written with this context.
+    LCEVCRawSequenceConfig *sc; ///< RefStruct references
+    LCEVCRawGlobalConfig   *gc; ///< RefStruct references
+    LCEVCRawPictureConfig  *pc; ///< RefStruct references
+} CodedBitstreamLCEVCContext;
+
+/**
+ * Find the type descriptor for the given payload type.
+ *
+ * Returns NULL if the payload type is not known.
+ */
+const LCEVCProcessBlockTypeDescriptor *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx,
+                                                     int payload_type);
+
+/**
+ * Allocate a new payload for the given Process Block.
+ */
+int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block,
+                                     const LCEVCProcessBlockTypeDescriptor *desc);
+
+/**
+ * Allocate a new empty Process Block in a block list.
+ *
+ * The new block is in place nb_blocks - 1.
+ */
+int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list);
+
+/**
+ * Free all Process Block in a block list.
+ */
+void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list);
+
+#endif /* AVCODEC_CBS_LCEVC_H */
diff --git a/libavcodec/cbs_lcevc_syntax_template.c b/libavcodec/cbs_lcevc_syntax_template.c
new file mode 100644
index 0000000000..552a9e271d
--- /dev/null
+++ b/libavcodec/cbs_lcevc_syntax_template.c
@@ -0,0 +1,569 @@
+/*
+ * 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
+ */
+
+static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw)
+{
+    int err;
+
+    // ISO/IEC 23094-2:2021/FDAM 1:2023(E) 7.3.12
+    while (byte_alignment(rw) != 0)
+        fixed(1, alignment_bit_equal_to_zero, 0);
+
+    return 0;
+}
+
+static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw)
+{
+    int err;
+
+    fixed(1, rbsp_stop_one_bit, 1);
+    while (byte_alignment(rw) != 0)
+        fixed(1, rbsp_alignment_zero_bit, 0);
+
+    return 0;
+}
+
+static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw,
+                                 LCEVCRawNALUnitHeader *current,
+                                 uint32_t valid_type_mask)
+{
+    int err;
+
+    fixed(1, forbidden_zero_bit, 0);
+    fixed(1, forbidden_one_bit, 1);
+    ub(5, nal_unit_type);
+
+    if (!(1 << current->nal_unit_type & valid_type_mask)) {
+        av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n",
+               current->nal_unit_type);
+        return AVERROR_INVALIDDATA;
+    }
+
+    ub(9, reserved_flag);
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(global_config, (CodedBitstreamContext *ctx, RWContext *rw,
+                                 LCEVCRawGlobalConfig *current,
+                                 LCEVCProcessBlockState *state))
+{
+    CodedBitstreamLCEVCContext *priv = ctx->priv_data;
+    int err;
+
+    HEADER("Global Config");
+
+    flag(processed_planes_type_flag);
+    ub(6, resolution_type);
+    ub(1, transform_type);
+    ub(2, chroma_sampling_type);
+    ub(2, base_depth_type);
+    ub(2, enhancement_depth_type);
+    flag(temporal_step_width_modifier_signalled_flag);
+    flag(predicted_residual_mode_flag);
+    flag(temporal_tile_intra_signalling_enabled_flag);
+    flag(temporal_enabled_flag);
+    ub(3, upsample_type);
+    flag(level1_filtering_signalled_flag);
+    ub(2, scaling_mode_level1);
+    ub(2, scaling_mode_level2);
+    ub(2, tile_dimensions_type);
+    ub(2, user_data_enabled);
+    flag(level1_depth_flag);
+    flag(chroma_step_width_flag);
+
+    if (current->processed_planes_type_flag) {
+        ub(4, planes_type);
+        ub(4, reserved_zeros_4bit);
+    } else
+        infer(planes_type, 0);
+
+    if (current->temporal_step_width_modifier_signalled_flag) {
+        ub(8, temporal_step_width_modifier);
+    }
+
+    if (current->upsample_type == 4) {
+        ub(16, upsampler_coeff1);
+        ub(16, upsampler_coeff2);
+        ub(16, upsampler_coeff3);
+        ub(16, upsampler_coeff4);
+    }
+
+    if (current->level1_filtering_signalled_flag) {
+        ub(4, level1_filtering_first_coefficient);
+        ub(4, level1_filtering_second_coefficient);
+    }
+
+    if (current->tile_dimensions_type > 0) {
+        if (current->tile_dimensions_type == 3) {
+            ub(16, custom_tile_width);
+            ub(16, custom_tile_height);
+        }
+        ub(5, reserved_zeros_5bit);
+        flag(compression_type_entropy_enabled_per_tile_flag);
+        ub(2, compression_type_size_per_tile);
+    }
+
+    if (current->resolution_type == 63) {
+        ub(16, custom_resolution_width);
+        ub(16, custom_resolution_height);
+    }
+    if (current->chroma_step_width_flag) {
+        ub(8, chroma_step_width_multiplier);
+    } else {
+        infer(chroma_step_width_multiplier, 64);
+    }
+
+    av_refstruct_replace(&priv->gc, current);
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(sequence_config, (CodedBitstreamContext *ctx, RWContext *rw,
+                                   LCEVCRawSequenceConfig *current,
+                                   LCEVCProcessBlockState *state))
+{
+    CodedBitstreamLCEVCContext *priv = ctx->priv_data;
+    int err;
+
+    HEADER("Sequence Config");
+
+    ub(4, profile_idc);
+    ub(4, level_idc);
+    ub(2, sublevel_idc);
+    flag(conformance_window_flag);
+    ub(5, reserved_zeros_5bit);
+
+    if (current->profile_idc == 15 || current->level_idc == 15) {
+        ub(3, profile_idc);
+        ub(4, level_idc);
+        ub(1, reserved_zeros_1bit);
+    }
+    if (current->conformance_window_flag == 1) {
+        mb(conf_win_left_offset);
+        mb(conf_win_right_offset);
+        mb(conf_win_top_offset);
+        mb(conf_win_bottom_offset);
+    }
+
+    av_refstruct_replace(&priv->sc, current);
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(picture_config, (CodedBitstreamContext *ctx, RWContext *rw,
+                                  LCEVCRawPictureConfig *current,
+                                  LCEVCProcessBlockState *state))
+{
+    CodedBitstreamLCEVCContext *priv = ctx->priv_data;
+    int nlayers, err;
+
+    HEADER("Picture Config");
+
+    if (!priv->gc)
+        return AVERROR_INVALIDDATA;
+
+    flag(no_enhancement_bit_flag);
+    if (current->no_enhancement_bit_flag == 0) {
+        ub(3, quant_matrix_mode);
+        flag(dequant_offset_signalled_flag);
+        flag(picture_type_bit_flag);
+        flag(temporal_refresh_bit_flag);
+        flag(step_width_sublayer1_enabled_flag);
+        ub(15, step_width_sublayer2);
+        flag(dithering_control_flag);
+        infer(temporal_signalling_present_flag, 0);
+    } else {
+        ub(4, reserved_zeros_4bit);
+        flag(picture_type_bit_flag);
+        flag(temporal_refresh_bit_flag);
+        flag(temporal_signalling_present_flag);
+    }
+
+    if (current->picture_type_bit_flag == 1) {
+        flag(field_type_bit_flag);
+        ub(7, reserved_zeros_7bit);
+    }
+
+    if (current->step_width_sublayer1_enabled_flag == 1) {
+        ub(15, step_width_sublayer1);
+        flag(level1_filtering_enabled_flag);
+    }
+
+    nlayers = priv->gc->transform_type ? 16 : 4;
+    if (current->quant_matrix_mode == 2 ||
+        current->quant_matrix_mode == 3 ||
+        current->quant_matrix_mode == 5) {
+        for (int layer_idx = 0; layer_idx < nlayers; layer_idx++)
+            ubs(8, qm_coefficient_0[layer_idx], 1, layer_idx);
+    }
+
+    if (current->quant_matrix_mode == 4 || current->quant_matrix_mode == 5) {
+        for (int layer_idx = 0; layer_idx < nlayers; layer_idx++)
+            ubs(8, qm_coefficient_1[layer_idx], 1, layer_idx);
+    }
+
+    if (current->dequant_offset_signalled_flag) {
+        flag(dequant_offset_mode_flag);
+        ub(7, dequant_offset);
+    }
+
+    if (current->dithering_control_flag == 1) {
+        ub(2, dithering_type);
+        ub(1, reserverd_zero);
+        if (current->dithering_type != 0) {
+            ub(5, dithering_strength);
+        } else {
+            ub(5, reserved_zeros_5bit);
+        }
+    }
+
+    av_refstruct_replace(&priv->pc, current);
+    av_refstruct_replace(&current->gc, priv->gc);
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(encoded_data, (CodedBitstreamContext *ctx, RWContext *rw,
+                                LCEVCRawEncodedData *current,
+                                LCEVCProcessBlockState *state))
+{
+    CodedBitstreamLCEVCContext *priv = ctx->priv_data;
+    int nplanes, nlayers, err;
+#ifdef READ
+    int start = get_bits_count(rw);
+#endif
+
+    HEADER("Encoded Data");
+
+    if (!priv->gc || !priv->pc)
+        return AVERROR_INVALIDDATA;
+
+    nplanes = priv->gc->planes_type ? 3 : 1;
+    nlayers = priv->gc->transform_type ? 16 : 4;
+    for (int plane_idx = 0; plane_idx < nplanes; plane_idx++) {
+        if (priv->pc->no_enhancement_bit_flag == 0) {
+            for (int level_idx = 1; level_idx <= 2; level_idx++) {
+                for (int layer_idx = 0; layer_idx < nlayers; layer_idx++) {
+                    ubs(1, surfaces_entropy_enabled_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx);
+                    ubs(1, surfaces_rle_only_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx);
+                }
+            }
+        }
+        if (priv->pc->temporal_signalling_present_flag == 1) {
+            ubs(1, temporal_surfaces_entropy_enabled_flag[plane_idx], 1, plane_idx);
+            ubs(1, temporal_surfaces_rle_only_flag[plane_idx], 1, plane_idx);
+        }
+    }
+
+    CHECK(FUNC(byte_alignment)(ctx, rw));
+
+#ifdef READ
+    if (!cbs_h2645_read_more_rbsp_data(rw))
+        return AVERROR_INVALIDDATA;
+
+    int pos = get_bits_count(rw) - start;
+    int len = state->payload_size;
+
+    current->header_size = pos / 8;
+    current->data_size = len - pos / 8;
+#else
+    err = cbs_h2645_write_slice_data(ctx, rw, current->data,
+                                     current->data_size, 0);
+    if (err < 0)
+        return err;
+#endif
+
+    av_refstruct_replace(&current->sc, priv->sc);
+    av_refstruct_replace(&current->gc, priv->gc);
+    av_refstruct_replace(&current->pc, priv->pc);
+
+    return 0;
+}
+
+static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw,
+                             SEIRawMessage *current,
+                             int payload_type, int payload_size)
+{
+    int sei_type;
+    int err;
+
+    if (payload_type == 1)
+        sei_type = SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME;
+    else if (payload_type == 2)
+        sei_type = SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO;
+    else if (payload_type == 4)
+        sei_type = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35;
+    else if (payload_type == 5)
+        sei_type = SEI_TYPE_USER_DATA_UNREGISTERED;
+
+    current->payload_type = sei_type;
+    current->payload_size = payload_size;
+
+    CHECK(FUNC_SEI(message)(ctx, rw, current));
+
+    return 0;
+}
+
+static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw,
+                                LCEVCRawVUI *current)
+{
+    int err;
+
+    HEADER("VUI Parameters");
+
+    flag(aspect_ratio_info_present_flag);
+    if (current->aspect_ratio_info_present_flag) {
+        ub(8, aspect_ratio_idc);
+
+        if (current->aspect_ratio_idc == 255) {
+            ub(16, sar_width);
+            ub(16, sar_height);
+        }
+    }
+
+    flag(overscan_info_present_flag);
+    if (current->overscan_info_present_flag)
+        flag(overscan_appropriate_flag);
+
+    flag(video_signal_type_present_flag);
+    if (current->video_signal_type_present_flag) {
+        ub(3, video_format);
+        flag(video_full_range_flag);
+        flag(colour_description_present_flag);
+        if (current->colour_description_present_flag) {
+            ub(8, colour_primaries);
+            ub(8, transfer_characteristics);
+            ub(8, matrix_coefficients);
+        }
+    }
+    flag(chroma_loc_info_present_flag);
+    if (current->chroma_loc_info_present_flag) {
+        ue(chroma_sample_loc_type_top_field, 0, 5);
+        ue(chroma_sample_loc_type_bottom_field, 0, 5);
+    }
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(additional_info, (CodedBitstreamContext *ctx, RWContext *rw,
+                                   LCEVCRawAdditionalInfo *current,
+                                   LCEVCProcessBlockState *state))
+{
+    int err, i;
+
+    HEADER("Additional Info");
+
+    ub(8, additional_info_type);
+
+    if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_SEI) {
+        ub(8, payload_type);
+        CHECK(FUNC(sei_payload)(ctx, rw, &current->sei,
+                                current->payload_type, state->payload_size - 2));
+    } else if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_VUI)
+        CHECK(FUNC(vui_parameters)(ctx, rw, &current->vui));
+    else {
+        uint8_t *data;
+
+        allocate(current->payload_ref, state->payload_size - 1);
+        current->payload_size = state->payload_size - 1;
+        current->payload = current->payload_ref;
+        data = current->payload;
+
+        for (i = 0; i < current->payload_size; i++)
+            xu(8, additional_info_byte[i], data[i], 0, 255, 1, i);
+    }
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(filler, (CodedBitstreamContext *ctx, RWContext *rw,
+                          LCEVCRawFiller *current,
+                          LCEVCProcessBlockState *state))
+{
+    int err;
+
+    HEADER("Filler");
+
+
+#ifdef READ
+    while (show_bits(rw, 8) == 0xaa) {
+        fixed(8, filler_byte, 0xaa);
+        ++current->filler_size;
+    }
+    if (state->payload_size != current->filler_size)
+        return AVERROR_INVALIDDATA;
+
+#else
+    for (int i = 0; i < current->filler_size; i++)
+        fixed(8, filler_byte, 0xaa);
+#endif
+
+    return 0;
+}
+
+static int FUNC(process_block)(CodedBitstreamContext *ctx, RWContext *rw,
+                               LCEVCRawProcessBlock *current)
+{
+    const LCEVCProcessBlockTypeDescriptor *desc;
+    int err, i;
+
+    desc = ff_cbs_lcevc_process_block_find_type(ctx, current->payload_type);
+    if (desc) {
+        LCEVCProcessBlockState state = {
+            .payload_type      = current->payload_type,
+            .payload_size      = current->payload_size,
+        };
+#ifdef READ
+        CHECK(ff_cbs_lcevc_alloc_process_block_payload(current, desc));
+#else
+        int start_position = bit_position(rw);
+#endif
+
+        CHECK(desc->READWRITE(ctx, rw, current->payload, &state));
+
+        av_assert0(!byte_alignment(rw));
+#ifdef WRITE
+        current->payload_size = (bit_position(rw) - start_position) / 8;
+#endif
+    } else {
+        uint8_t *data;
+
+#ifdef READ
+        allocate(current->payload_ref, current->payload_size);
+        current->payload = current->payload_ref;
+#else
+        allocate(current->payload, current->payload_size);
+#endif
+        data = current->payload;
+
+        for (i = 0; i < current->payload_size; i++)
+            xu(8, payload_byte[i], data[i], 0, 255, 1, i);
+    }
+
+    return 0;
+}
+
+static int FUNC(process_block_list)(CodedBitstreamContext *ctx, RWContext *rw,
+                                    LCEVCRawProcessBlockList *current)
+{
+    LCEVCRawProcessBlock *block;
+    int err, k;
+
+#ifdef READ
+    for (k = 0;; k++) {
+        int payload_size_type;
+        int payload_type;
+        uint32_t payload_size;
+        uint32_t tmp;
+        GetBitContext payload_gbc;
+
+        HEADER("Process Block");
+
+        xu(3, payload_size_type, tmp, 0, MAX_UINT_BITS(3), 0);
+        payload_size_type = tmp;
+        xu(5, payload_type, tmp, 0, MAX_UINT_BITS(5), 0);
+        payload_type = tmp;
+
+        if (payload_size_type == 6) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "payload_size_type == 6\n");
+            return AVERROR_INVALIDDATA;
+        }
+
+        payload_size = payload_size_type;
+        if (payload_size_type == 7)
+            xmb(custom_byte_size, payload_size);
+
+        // There must be space remaining for the payload
+        if (payload_size > get_bits_left(rw) / 8) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR,
+                   "Invalid process block: payload_size too large "
+                   "(%"PRIu32" bytes).\n", payload_size);
+            return AVERROR_INVALIDDATA;
+        }
+        CHECK(init_get_bits(&payload_gbc, rw->buffer,
+                            get_bits_count(rw) + 8 * payload_size));
+        skip_bits_long(&payload_gbc, get_bits_count(rw));
+
+        CHECK(ff_cbs_lcevc_list_add(current));
+        block = &current->blocks[k];
+
+        block->payload_type = payload_type;
+        block->payload_size = payload_size;
+
+        CHECK(FUNC(process_block)(ctx, &payload_gbc, block));
+
+        skip_bits_long(rw, 8 * payload_size);
+
+        if (!cbs_h2645_read_more_rbsp_data(rw))
+            break;
+    }
+#else
+    for (k = 0; k < current->nb_blocks; k++) {
+        PutBitContext start_state;
+        uint32_t tmp;
+        int trace, i;
+
+        block = &current->blocks[k];
+
+        // We write the payload twice in order to find the size. Trace
+        // output is switched off for the first write.
+        trace = ctx->trace_enable;
+        ctx->trace_enable = 0;
+
+        start_state = *rw;
+        for (i = 0; i < 2; i++) {
+            *rw = start_state;
+
+            tmp = FFMIN(block->payload_size, 7);
+            xu(3, payload_size_type, tmp, 0, 7, 0);
+            xu(5, payload_type, block->payload_type, 0, MAX_UINT_BITS(5), 0);
+
+            if (tmp == 7)
+                xmb(custom_byte_size, block->payload_size);
+
+            err = FUNC(process_block)(ctx, rw, block);
+            ctx->trace_enable = trace;
+            if (err < 0)
+                return err;
+        }
+    }
+#endif
+
+    return 0;
+}
+
+static int FUNC(nal)(CodedBitstreamContext *ctx, RWContext *rw,
+                     LCEVCRawNAL *current, int nal_unit_type)
+{
+    int err;
+
+    if (nal_unit_type == LCEVC_NON_IDR_NUT)
+        HEADER("Non IDR");
+    else
+        HEADER("IDR");
+
+    CHECK(FUNC(nal_unit_header)(ctx, rw, &current->nal_unit_header,
+                                (1 << LCEVC_IDR_NUT) | (1 << LCEVC_NON_IDR_NUT)));
+
+    CHECK(FUNC(process_block_list) (ctx, rw, &current->process_block_list));
+
+    CHECK(FUNC(rbsp_trailing_bits)(ctx, rw));
+
+    return 0;
+}
diff --git a/libavformat/cbs.h b/libavformat/cbs.h
index e4dc231001..1de86a5fce 100644
--- a/libavformat/cbs.h
+++ b/libavformat/cbs.h
@@ -25,6 +25,7 @@
 #define CBS_H264 0
 #define CBS_H265 0
 #define CBS_H266 0
+#define CBS_LCEVC 0
 #define CBS_JPEG 0
 #define CBS_MPEG2 0
 #define CBS_VP8 0
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

                 reply	other threads:[~2026-02-19  1:02 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=177146287775.25.119570817854103840@29965ddac10e \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=code@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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