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

Git pushed a commit to branch master
in repository ffmpeg.

commit 0390793dc36c1e390dd9559abd2e2502ebc7f92d
Author:     James Almer <[email protected]>
AuthorDate: Wed Feb 18 21:15:17 2026 -0300
Commit:     James Almer <[email protected]>
CommitDate: Sat Feb 28 16:12:33 2026 -0300

    avcodec/cbs: add support for LCEVC bitstreams
    
    As defined in ISO/IEC 23094-2:2021/FDAM 1:2023
    
    Signed-off-by: James Almer <[email protected]>
---
 configure                              |   3 +
 libavcodec/Makefile                    |   1 +
 libavcodec/cbs.c                       |   6 +
 libavcodec/cbs_internal.h              |   4 +
 libavcodec/cbs_lcevc.c                 | 833 +++++++++++++++++++++++++++++++++
 libavcodec/cbs_lcevc.h                 | 308 ++++++++++++
 libavcodec/cbs_lcevc_syntax_template.c | 674 ++++++++++++++++++++++++++
 libavformat/cbs.h                      |   1 +
 8 files changed, 1830 insertions(+)

diff --git a/configure b/configure
index 87a9c02686..16f82cdf07 100755
--- a/configure
+++ b/configure
@@ -2694,6 +2694,7 @@ CONFIG_EXTRA="
     cbs_h265
     cbs_h266
     cbs_jpeg
+    cbs_lcevc
     cbs_mpeg2
     cbs_vp8
     cbs_vp9
@@ -3006,6 +3007,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"
@@ -3692,6 +3694,7 @@ h264_metadata_bsf_deps="const_nan"
 h264_metadata_bsf_select="cbs_h264"
 h264_redundant_pps_bsf_select="cbs_h264"
 hevc_metadata_bsf_select="cbs_h265"
+lcevc_metadata_bsf_select="cbs_lcevc"
 mjpeg2jpeg_bsf_select="jpegtables"
 mpeg2_metadata_bsf_select="cbs_mpeg2"
 smpte436m_to_eia608_bsf_select="smpte_436m"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 7d3e4aa1b4..b33d7bcd0f 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -91,6 +91,7 @@ OBJS-$(CONFIG_CBS_AV1)                 += cbs_av1.o
 OBJS-$(CONFIG_CBS_H264)                += cbs_h264.o cbs_h2645.o cbs_sei.o 
h2645_parse.o
 OBJS-$(CONFIG_CBS_H265)                += cbs_h265.o cbs_h2645.o cbs_sei.o 
h2645_parse.o
 OBJS-$(CONFIG_CBS_H266)                += cbs_h266.o cbs_h2645.o cbs_sei.o 
h2645_parse.o
+OBJS-$(CONFIG_CBS_LCEVC)               += cbs_lcevc.o cbs_h2645.o cbs_sei.o 
h2645_parse.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_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..11b47199b6
--- /dev/null
+++ b/libavcodec/cbs_lcevc.c
@@ -0,0 +1,833 @@
+/*
+ * 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 "libavutil/refstruct.h"
+#include "bytestream.h"
+#include "cbs.h"
+#include "cbs_internal.h"
+#include "cbs_h2645.h"
+#include "cbs_lcevc.h"
+#include "cbs_sei.h"
+#include "get_bits.h"
+
+#define HEADER(name) do { \
+        ff_cbs_trace_header(ctx, name); \
+    } while (0)
+
+#define CHECK(call) do { \
+        err = (call); \
+        if (err < 0) \
+            return err; \
+    } while (0)
+
+#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
+#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name)
+#define FUNC_LCEVC(name) FUNC_NAME1(READWRITE, lcevc, name)
+#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## 
name
+#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name)
+#define FUNC_SEI(name)  FUNC_NAME1_EXPORT(READWRITE, sei,  name)
+
+#define SEI_FUNC(name, args) \
+static int FUNC_LCEVC(name) args;  \
+static int FUNC_LCEVC(name ## _internal)(CodedBitstreamContext *ctx, \
+                                   RWContext *rw, void *cur,   \
+                                   SEIMessageState *state)     \
+{ \
+    return FUNC_LCEVC(name)(ctx, rw, cur, state); \
+} \
+static int FUNC_LCEVC(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,    \
+                                   int nal_unit_type)                \
+{ \
+    return FUNC(name)(ctx, rw, cur, state, nal_unit_type); \
+} \
+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) \
+        xu(width, name, current->name, range_min, range_max, 0, )
+#define flag(name) ub(1, name)
+#define ue(name, range_min, range_max) \
+        xue(name, current->name, range_min, range_max, 0, )
+#define i(width, name, range_min, range_max) \
+        xi(width, name, current->name, range_min, range_max, 0, )
+#define ib(width, name) \
+        xi(width, name, current->name, MIN_INT_BITS(width), 
MAX_INT_BITS(width), 0, )
+#define se(name, range_min, range_max) \
+        xse(name, current->name, range_min, range_max, 0, )
+
+#define us(width, name, range_min, range_max, subs, ...) \
+        xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define ubs(width, name, subs, ...) \
+        xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, 
__VA_ARGS__)
+#define flags(name, subs, ...) \
+        xu(1, name, current->name, 0, 1, subs, __VA_ARGS__)
+#define ues(name, range_min, range_max, subs, ...) \
+        xue(name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define is(width, name, range_min, range_max, subs, ...) \
+        xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define ibs(width, name, subs, ...) \
+        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; \
+        xu(width, name, fixed_value, value, value, 0, ); \
+    } while (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;
+}
+
+#define READ
+#define READWRITE read
+#define RWContext GetBitContext
+
+#define ub(width, name) do { \
+        uint32_t value; \
+        CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
+                                          &value)); \
+        current->name = value; \
+    } while (0)
+#define xu(width, name, var, range_min, range_max, subs, ...) do { \
+        uint32_t value; \
+        CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+                                   SUBSCRIPTS(subs, __VA_ARGS__), \
+                                   &value, range_min, range_max)); \
+        var = value; \
+    } while (0)
+#define xue(name, var, range_min, range_max, subs, ...) do { \
+        uint32_t value; \
+        CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \
+                                 SUBSCRIPTS(subs, __VA_ARGS__), \
+                                 &value, range_min, range_max)); \
+        var = value; \
+    } while (0)
+#define xi(width, name, var, range_min, range_max, subs, ...) do { \
+        int32_t value; \
+        CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
+                                 SUBSCRIPTS(subs, __VA_ARGS__), \
+                                 &value, range_min, range_max)); \
+        var = value; \
+    } while (0)
+#define xse(name, var, range_min, range_max, subs, ...) do { \
+        int32_t value; \
+        CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \
+                                 SUBSCRIPTS(subs, __VA_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 { \
+        current->name = value; \
+    } while (0)
+
+#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw))
+
+#define bit_position(rw)   (get_bits_count(rw))
+#define byte_alignment(rw) (get_bits_count(rw) % 8)
+
+/* The CBS LCEVC code uses the refstruct API for the allocation
+ * of its child buffers. */
+#define allocate(name, size) do { \
+        name  = av_refstruct_allocz(size + \
+                                        AV_INPUT_BUFFER_PADDING_SIZE); \
+        if (!name) \
+            return AVERROR(ENOMEM); \
+    } while (0)
+
+#define FUNC(name) FUNC_LCEVC(name)
+#include "cbs_lcevc_syntax_template.c"
+#undef FUNC
+
+
+#undef READ
+#undef READWRITE
+#undef RWContext
+#undef ub
+#undef xu
+#undef xi
+#undef xue
+#undef xse
+#undef xmb
+#undef infer
+#undef more_rbsp_data
+#undef bit_position
+#undef byte_alignment
+#undef allocate
+
+
+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;
+}
+
+#define WRITE
+#define READWRITE write
+#define RWContext PutBitContext
+
+#define ub(width, name) do { \
+        uint32_t value = current->name; \
+        CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
+                                           value)); \
+    } while (0)
+#define xu(width, name, var, range_min, range_max, subs, ...) do { \
+        uint32_t value = var; \
+        CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+                                    SUBSCRIPTS(subs, __VA_ARGS__), \
+                                    value, range_min, range_max)); \
+    } while (0)
+#define xue(name, var, range_min, range_max, subs, ...) do { \
+        uint32_t value = var; \
+        CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \
+                                  SUBSCRIPTS(subs, __VA_ARGS__), \
+                                  value, range_min, range_max)); \
+    } while (0)
+#define xi(width, name, var, range_min, range_max, subs, ...) do { \
+        int32_t value = var; \
+        CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
+                                  SUBSCRIPTS(subs, __VA_ARGS__), \
+                                  value, range_min, range_max)); \
+    } while (0)
+#define xse(name, var, range_min, range_max, subs, ...) do { \
+        int32_t value = var; \
+        CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \
+                                  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)) { \
+            av_log(ctx->log_ctx, AV_LOG_ERROR, \
+                   "%s does not match inferred value: " \
+                   "%"PRId64", but should be %"PRId64".\n", \
+                   #name, (int64_t)current->name, (int64_t)(value)); \
+            return AVERROR_INVALIDDATA; \
+        } \
+    } while (0)
+
+#define more_rbsp_data(var) (var)
+
+#define bit_position(rw)   (put_bits_count(rw))
+#define byte_alignment(rw) (put_bits_count(rw) % 8)
+
+#define allocate(name, size) do { \
+        if (!name) { \
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \
+                   "for writing.\n", #name); \
+            return AVERROR_INVALIDDATA; \
+        } \
+    } while (0)
+
+#define FUNC(name) FUNC_LCEVC(name)
+#include "cbs_lcevc_syntax_template.c"
+#undef FUNC
+
+#undef WRITE
+#undef READWRITE
+#undef RWContext
+#undef ub
+#undef xu
+#undef xi
+#undef xue
+#undef xse
+#undef xmb
+#undef u
+#undef i
+#undef flag
+#undef ue
+#undef se
+#undef infer
+#undef more_rbsp_data
+#undef bit_position
+#undef byte_alignment
+#undef allocate
+
+
+static int cbs_lcevc_split_fragment(CodedBitstreamContext *ctx,
+                                    CodedBitstreamFragment *frag,
+                                    int header)
+{
+    enum AVCodecID codec_id = ctx->codec->codec_id;
+    CodedBitstreamLCEVCContext *priv = ctx->priv_data;
+    CodedBitstreamH2645Context *h2645 = &priv->common;
+    GetByteContext gbc;
+    int err;
+
+    av_assert0(frag->data && frag->nb_units == 0);
+    if (frag->data_size == 0)
+        return 0;
+
+    if (header && frag->data[0]) {
+        // LVCC header.
+        size_t size, start, end;
+        int i, j, nb_arrays, nal_unit_type, nb_nals, version;
+
+        h2645->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);
+        h2645->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(&h2645->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 = ff_cbs_h2645_fragment_add_nals(ctx, frag, 
&h2645->read_packet);
+            if (err < 0)
+                return err;
+        }
+    } else {
+        int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | 
H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF;
+        // Annex B, or later MP4 with already-known parameters.
+
+        err = ff_h2645_packet_split(&h2645->read_packet,
+                                    frag->data, frag->data_size,
+                                    ctx->log_ctx,
+                                    h2645->nal_length_size,
+                                    codec_id, flags);
+        if (err < 0)
+            return err;
+
+        err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet);
+        if (err < 0)
+            return err;
+    }
+
+    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_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 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;
+    LCEVCRawSEI *sei = &additional_info->sei;
+    SEIRawMessage *message = &sei->message;
+
+    av_refstruct_unref(&additional_info->payload_ref);
+    av_refstruct_unref(&sei->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, int position)
+{
+    LCEVCRawProcessBlock *blocks;
+
+    if (position == -1)
+        position = list->nb_blocks;
+    av_assert0(position >= 0 && position <= list->nb_blocks);
+
+    if (list->nb_blocks < list->nb_blocks_allocated) {
+        blocks = list->blocks;
+
+        if (position < list->nb_blocks)
+            memmove(blocks + position + 1, blocks + position,
+                    (list->nb_blocks - position) * sizeof(*blocks));
+    } else {
+        blocks = av_malloc_array(list->nb_blocks*2 + 1, sizeof(*blocks));
+        if (!blocks)
+            return AVERROR(ENOMEM);
+
+        list->nb_blocks_allocated = 2*list->nb_blocks_allocated + 1;
+
+        if (position > 0)
+            memcpy(blocks, list->blocks, position * sizeof(*blocks));
+
+        if (position < list->nb_blocks)
+            memcpy(blocks + position + 1, list->blocks + position,
+                   (list->nb_blocks - position) * sizeof(*blocks));
+
+        av_free(list->blocks);
+        list->blocks = blocks;
+    }
+
+    memset(blocks + position, 0, sizeof(*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_refstruct_unref(&block->extension_data);
+    }
+    av_free(list->blocks);
+}
+
+static int cbs_lcevc_get_process_block_list(CodedBitstreamContext *ctx,
+                                            CodedBitstreamUnit *unit,
+                                            LCEVCRawProcessBlockList **list)
+{
+    LCEVCRawNAL *nal = unit->content;
+    if (unit->type != LCEVC_NON_IDR_NUT && unit->type != LCEVC_IDR_NUT)
+        return AVERROR(EINVAL);
+    *list = &nal->process_block_list;
+
+    return 0;
+}
+
+int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx,
+                                   CodedBitstreamFragment *au,
+                                   int position,
+                                   uint32_t     payload_type,
+                                   void        *payload_data,
+                                   void        *payload_ref)
+{
+    const LCEVCProcessBlockTypeDescriptor *desc;
+    CodedBitstreamUnit *unit = NULL;
+    LCEVCRawProcessBlockList *list;
+    LCEVCRawProcessBlock *block;
+    int err;
+
+    desc = ff_cbs_lcevc_process_block_find_type(ctx, payload_type);
+    if (!desc)
+        return AVERROR(EINVAL);
+
+    for (int i = 0; i < au->nb_units; i++) {
+        if (au->units[i].type == LCEVC_NON_IDR_NUT ||
+            au->units[i].type == LCEVC_IDR_NUT) {
+            unit = &au->units[i];
+            break;
+        }
+    }
+    if (!unit)
+        return AVERROR(EINVAL);
+
+    // Find the block list inside the codec-dependent unit.
+    err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
+    if (err < 0)
+        return err;
+
+    // Add a new block to the message list.
+    err = ff_cbs_lcevc_list_add(list, position);
+    if (err < 0)
+        return err;
+
+    if (payload_ref) {
+        /* The following just increments payload_ref's refcount,
+         * so that payload_ref is now owned by us. */
+        payload_ref = av_refstruct_ref(payload_ref);
+    }
+
+    block = &list->blocks[position];
+
+    block->payload_type = payload_type;
+    block->payload      = payload_data;
+    block->payload_ref  = payload_ref;
+
+    return 0;
+}
+
+int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx,
+                                    CodedBitstreamFragment *au,
+                                    uint32_t payload_type,
+                                    LCEVCRawProcessBlock **iter)
+{
+    int err, found;
+
+    found = 0;
+    for (int i = 0; i < au->nb_units; i++) {
+        CodedBitstreamUnit *unit = &au->units[i];
+        LCEVCRawProcessBlockList *list;
+
+        err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
+        if (err < 0)
+            continue;
+
+        for (int j = 0; j < list->nb_blocks; j++) {
+            LCEVCRawProcessBlock *block = &list->blocks[j];
+
+            if (block->payload_type == payload_type) {
+                if (!*iter || found) {
+                    *iter = block;
+                    return j;
+                }
+                if (block == *iter)
+                    found = 1;
+            }
+        }
+    }
+
+    return AVERROR(ENOENT);
+}
+
+static void cbs_lcevc_delete_process_block(LCEVCRawProcessBlockList *list,
+                                           int position)
+{
+    LCEVCRawProcessBlock *block;
+
+    av_assert0(0 <= position && position < list->nb_blocks);
+
+    block = &list->blocks[position];
+    av_refstruct_unref(&block->payload_ref);
+
+    --list->nb_blocks;
+
+    if (list->nb_blocks > 0) {
+        memmove(list->blocks + position,
+                list->blocks + position + 1,
+                (list->nb_blocks - position) * sizeof(*list->blocks));
+    }
+}
+
+void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx,
+                                            CodedBitstreamFragment *au,
+                                            uint32_t payload_type)
+{
+    int err;
+
+    for (int i = 0; i < au->nb_units; i++) {
+        CodedBitstreamUnit *unit = &au->units[i];
+        LCEVCRawProcessBlockList *list;
+
+        err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
+        if (err < 0)
+            continue;
+
+        for (int j = list->nb_blocks - 1; j >= 0; j--) {
+            if (list->blocks[j].payload_type == payload_type)
+                cbs_lcevc_delete_process_block(list, j);
+        }
+    }
+}
+
+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_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
+};
+
+// 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)
+{
+    for (int 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;
+}
+
+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_lcevc_split_fragment,
+    .read_unit         = &cbs_lcevc_read_nal_unit,
+    .write_unit        = &cbs_lcevc_write_nal_unit,
+    .assemble_fragment = &ff_cbs_h2645_assemble_fragment,
+
+    .flush             = &cbs_lcevc_flush,
+    .close             = &cbs_lcevc_close,
+};
diff --git a/libavcodec/cbs_lcevc.h b/libavcodec/cbs_lcevc.h
new file mode 100644
index 0000000000..371c7912e0
--- /dev/null
+++ b/libavcodec/cbs_lcevc.h
@@ -0,0 +1,308 @@
+/*
+ * 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 LCEVCRawSEI {
+    SEIRawMessage message;
+
+    uint8_t       payload_type;
+    uint32_t      payload_size;
+    void         *payload;
+    void         *payload_ref;    ///< RefStruct reference
+} LCEVCRawSEI;
+
+typedef struct LCEVCRawAdditionalInfo {
+    uint8_t additional_info_type;
+
+    LCEVCRawSEI           sei;
+    LCEVCRawVUI           vui;
+
+    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
+    uint8_t     *extension_data; ///< RefStruct reference
+    size_t       extension_bit_length;
+} 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;
+    // When writing, indicates that payload extension data is present so
+    // all extended fields must be written.  May be updated by the writer
+    // to indicate that extended fields have been written, so the extension
+    // end bits must be written too.
+    uint8_t  extension_present;
+} LCEVCProcessBlockState;
+
+typedef int (*LCEVCRawProcessBlockReadFunction)(CodedBitstreamContext *ctx,
+                                      struct GetBitContext *rw,
+                                      void *current,
+                                      LCEVCProcessBlockState *state,
+                                      int nal_unit_type);
+
+typedef int (*LCEVCRawProcessBlockWriteFunction)(CodedBitstreamContext *ctx,
+                                       struct PutBitContext *rw,
+                                       void *current,
+                                       LCEVCProcessBlockState *state,
+                                       int nal_unit_type);
+
+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;
+
+    int dithering_control_flag;
+
+    // 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 at a given position.
+ */
+int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list, int position);
+
+/**
+ * Free all Process Block in a block list.
+ */
+void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list);
+
+/**
+ * Add a process block to an access unit.
+ *
+ * An existing NAL unit of type IDR or NON_IDR are required.
+ *
+ * If set, payload_ref must be a RefStruct reference backing payload_data.
+ * This function creates a new reference to payload_ref in this case.
+ * If payload_ref is NULL, the new message will not be reference counted.
+ */
+int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx,
+                                   CodedBitstreamFragment *au,
+                                   int position,
+                                   uint32_t     payload_type,
+                                   void        *payload_data,
+                                   void        *payload_ref);
+
+/**
+ * Iterate over blocks with the given payload type in an access unit.
+ *
+ * Set block to NULL in the first call. Returns 0 while more blocks
+ * are available, AVERROR(ENOENT) when all blocks have been found.
+ */
+int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx,
+                                    CodedBitstreamFragment *au,
+                                    uint32_t payload_type,
+                                    LCEVCRawProcessBlock **block);
+
+/**
+ * Delete all blocks with the given payload type from an access unit.
+ */
+void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx,
+                                            CodedBitstreamFragment *au,
+                                            uint32_t payload_type);
+
+#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..17ea907152
--- /dev/null
+++ b/libavcodec/cbs_lcevc_syntax_template.c
@@ -0,0 +1,674 @@
+/*
+ * 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,
+                                 int nal_unit_type))
+{
+    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,
+                                   int nal_unit_type))
+{
+    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,
+                                  int nal_unit_type))
+{
+    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);
+        priv->dithering_control_flag = current->dithering_control_flag;
+        infer(temporal_signalling_present_flag, 
priv->gc->temporal_enabled_flag &&
+                                                
!current->temporal_refresh_bit_flag);
+    } else {
+        infer(quant_matrix_mode, 0);
+        infer(dequant_offset_signalled_flag, 0);
+        ub(4, reserved_zeros_4bit);
+        flag(picture_type_bit_flag);
+        flag(temporal_refresh_bit_flag);
+        infer(step_width_sublayer1_enabled_flag, 0);
+        infer(dithering_control_flag, nal_unit_type == LCEVC_IDR_NUT
+                                     ? 0
+                                     : priv->dithering_control_flag);
+        priv->dithering_control_flag = current->dithering_control_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);
+    } else
+        infer(level1_filtering_enabled_flag, 0);
+
+    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,
+                                int nal_unit_type))
+{
+    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 (!ff_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;
+    skip_bits_long(rw, current->data_size * 8);
+#else
+    err = ff_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,
+                             LCEVCRawSEI *current, int payload_size)
+{
+    SEIRawMessage *message = &current->message;
+    int sei_type;
+    int i, err;
+
+    ub(8, payload_type);
+
+    if (current->payload_type == 1)
+        sei_type = SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME;
+    else if (current->payload_type == 2)
+        sei_type = SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO;
+    else if (current->payload_type == 4)
+        sei_type = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35;
+    else if (current->payload_type == 5)
+        sei_type = SEI_TYPE_USER_DATA_UNREGISTERED;
+    else {
+        uint8_t *data;
+
+#ifdef READ
+        current->payload_size = payload_size;
+        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, reserved_sei_message_payload_byte[i], data[i], 0, 255, 1, i);
+
+        return 0;
+    }
+
+    message->payload_type = sei_type;
+    message->payload_size = payload_size;
+
+    CHECK(FUNC_SEI(message)(ctx, rw, message));
+
+    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);
+        }
+    } else {
+        infer(aspect_ratio_idc, 0);
+    }
+
+    flag(overscan_info_present_flag);
+    if (current->overscan_info_present_flag)
+        flag(overscan_appropriate_flag);
+    else
+        infer(overscan_appropriate_flag, 0);
+
+    flag(video_signal_type_present_flag);
+    if (current->video_signal_type_present_flag) {
+        u(3, video_format, 0, 5);
+        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);
+        } else {
+            infer(colour_primaries, 2);
+            infer(transfer_characteristics, 2);
+            infer(matrix_coefficients, 2);
+        }
+    } else {
+        infer(video_format, 5);
+        infer(video_full_range_flag, 0);
+        infer(colour_description_present_flag, 0);
+        infer(colour_primaries, 2);
+        infer(transfer_characteristics, 2);
+        infer(matrix_coefficients, 2);
+    }
+    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);
+    } else {
+        infer(chroma_sample_loc_type_top_field, 0);
+        infer(chroma_sample_loc_type_bottom_field, 0);
+    }
+
+    return 0;
+}
+
+LCEVC_BLOCK_FUNC(additional_info, (CodedBitstreamContext *ctx, RWContext *rw,
+                                   LCEVCRawAdditionalInfo *current,
+                                   LCEVCProcessBlockState *state,
+                                   int nal_unit_type))
+{
+    int i, err;
+
+    HEADER("Additional Info");
+
+    ub(8, additional_info_type);
+
+    if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_SEI) {
+        CHECK(FUNC(sei_payload)(ctx, rw, &current->sei, 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;
+
+#ifdef READ
+        current->payload_size = state->payload_size - 1;
+        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, 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 nal_unit_type))
+{
+    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,
+                               int nal_unit_type)
+{
+    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,
+            .extension_present = current->extension_bit_length > 0,
+        };
+        int start_position, current_position, bits_written;
+
+#ifdef READ
+        CHECK(ff_cbs_lcevc_alloc_process_block_payload(current, desc));
+#endif
+
+        start_position = bit_position(rw);
+
+        CHECK(desc->READWRITE(ctx, rw, current->payload, &state, 
nal_unit_type));
+
+        current_position = bit_position(rw);
+        bits_written = current_position - start_position;
+
+        if (byte_alignment(rw) || state.extension_present ||
+            bits_written < 8 * current->payload_size) {
+            size_t bits_left;
+
+#ifdef READ
+            GetBitContext tmp = *rw;
+            int trailing_bits, trailing_zero_bits;
+
+            bits_left = 8 * current->payload_size - bits_written;
+            if (bits_left > 8)
+                skip_bits_long(&tmp, bits_left - 8);
+            trailing_bits = get_bits(&tmp, FFMIN(bits_left, 8));
+            if (trailing_bits == 0) {
+                // The trailing bits must contain a payload_bit_equal_to_one, 
so
+                // they can't all be zero.
+                return AVERROR_INVALIDDATA;
+            }
+            trailing_zero_bits = ff_ctz(trailing_bits);
+            current->extension_bit_length =
+                bits_left - 1 - trailing_zero_bits;
+#endif
+
+            if (current->extension_bit_length > 0) {
+                allocate(current->extension_data,
+                         (current->extension_bit_length + 7) / 8);
+
+                bits_left = current->extension_bit_length;
+                for (i = 0; bits_left > 0; i++) {
+                    int length = FFMIN(bits_left, 8);
+                    xu(length, reserved_payload_extension_data,
+                       current->extension_data[i],
+                       0, MAX_UINT_BITS(length), 0);
+                    bits_left -= length;
+                }
+            }
+
+            fixed(1, payload_bit_equal_to_one, 1);
+            while (byte_alignment(rw))
+                fixed(1, payload_bit_equal_to_zero, 0);
+        }
+
+#ifdef WRITE
+        current->payload_size = (put_bits_count(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,
+                                    int nal_unit_type)
+{
+    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, -1));
+        block = &current->blocks[k];
+
+        block->payload_type = payload_type;
+        block->payload_size = payload_size;
+
+        CHECK(FUNC(process_block)(ctx, &payload_gbc, block, nal_unit_type));
+
+        skip_bits_long(rw, 8 * payload_size);
+
+        if (!ff_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, nal_unit_type);
+            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,
+                                    current->nal_unit_header.nal_unit_type));
+
+    CHECK(FUNC(rbsp_trailing_bits)(ctx, rw));
+
+    return 0;
+}
diff --git a/libavformat/cbs.h b/libavformat/cbs.h
index e4dc231001..dffd0e9206 100644
--- a/libavformat/cbs.h
+++ b/libavformat/cbs.h
@@ -26,6 +26,7 @@
 #define CBS_H265 0
 #define CBS_H266 0
 #define CBS_JPEG 0
+#define CBS_LCEVC 0
 #define CBS_MPEG2 0
 #define CBS_VP8 0
 #define CBS_VP9 0

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

Reply via email to