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

Git pushed a commit to branch master
in repository ffmpeg.

commit 3dba9eb80663abf77b083878a2f6e0f77abf81a7
Author:     James Almer <[email protected]>
AuthorDate: Mon Feb 16 11:58:46 2026 -0300
Commit:     James Almer <[email protected]>
CommitDate: Sat Feb 28 16:12:33 2026 -0300

    avcodec/bsf/extract_extradata: add support for LCEVC
    
    Signed-off-by: James Almer <[email protected]>
---
 libavcodec/bsf/extract_extradata.c | 180 +++++++++++++++++++++++++++++++++++++
 libavcodec/lcevc.h                 |  84 +++++++++++++++++
 2 files changed, 264 insertions(+)

diff --git a/libavcodec/bsf/extract_extradata.c 
b/libavcodec/bsf/extract_extradata.c
index 43f4d62855..f7b62189fe 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;
@@ -267,6 +277,174 @@ static int extract_extradata_h2645(AVBSFContext *ctx, 
AVPacket *pkt,
     return 0;
 }
 
+static inline uint64_t get_mb(GetBitContext *s) {
+    int more, i = 0;
+    uint64_t mb = 0;
+
+    do {
+        int byte = get_bits(s, 8);
+        unsigned bits = byte & 0x7f;
+        more = byte & 0x80;
+        mb = (mb << 7) | bits;
+        if (++i == 10)
+            break;
+    } while (more);
+
+    return mb;
+}
+
+/**
+ * Rewrite the NALu stripping the unneeded blocks.
+ * Given that length fields coded inside the NALu are not aware of any 
emulation_3bytes
+ * present in the bitstream, we need to keep track of the raw buffer as we 
navigate
+ * the stripped buffer.
+ */
+static int write_lcevc_nalu(AVBSFContext *ctx, PutByteContext *pbc, const 
H2645NAL *nal)
+{
+    GetByteContext gbc, raw_gbc;
+    int sc = 0, gc = 0;
+    int skipped_byte_pos = 0;
+
+    bytestream2_init(&gbc, nal->data, nal->size);
+    bytestream2_init(&raw_gbc, nal->raw_data, nal->raw_size);
+    bytestream2_put_be16(pbc, bytestream2_get_be16(&gbc));
+    bytestream2_skip(&raw_gbc, 2);
+
+    while (bytestream2_get_bytes_left(&gbc) > 1) {
+        GetBitContext gb;
+        int payload_size_type, payload_type, payload_size;
+        int block_size, raw_block_size, block_end;
+
+        init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc));
+
+        payload_size_type = get_bits(&gb, 3);
+        payload_type      = get_bits(&gb, 5);
+        payload_size      = payload_size_type;
+        if (payload_size_type == 6)
+            return AVERROR_PATCHWELCOME;
+        if (payload_size_type == 7)
+            payload_size = get_mb(&gb);
+
+        block_size = raw_block_size = payload_size + (get_bits_count(&gb) >> 
3);
+        if (block_size >= bytestream2_get_bytes_left(&gbc))
+            return AVERROR_INVALIDDATA;
+
+        block_end = bytestream2_tell(&gbc) + block_size;
+        // Take into account removed emulation 3bytes, as payload_size in
+        // the bitstream is not aware of them.
+        for (; skipped_byte_pos < nal->skipped_bytes; skipped_byte_pos++) {
+            if (nal->skipped_bytes_pos[skipped_byte_pos] >= block_end)
+                break;
+            raw_block_size++;
+        }
+
+        switch (payload_type) {
+        case 0:
+            bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
+            sc = 1;
+            break;
+        case 1:
+            bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
+            gc = 1;
+            break;
+        case 5:
+            bytestream2_put_buffer(pbc, raw_gbc.buffer, raw_block_size);
+            break;
+        default:
+            break;
+        }
+
+        bytestream2_skip(&gbc, block_size);
+        bytestream2_skip(&raw_gbc, raw_block_size);
+    }
+
+    if (!sc && !gc)
+        return AVERROR_INVALIDDATA;
+
+    bytestream2_put_byte(pbc, 0x80); // rbsp_alignment bits
+
+    return bytestream2_tell_p(pbc);
+}
+
+static int extract_extradata_lcevc(AVBSFContext *ctx, AVPacket *pkt,
+                                   uint8_t **data, int *size)
+{
+    static const int extradata_nal_types[] = {
+        LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT,
+    };
+
+    ExtractExtradataContext *s = ctx->priv_data;
+    PutByteContext pb_extradata;
+    int extradata_size = 0, filtered_size = 0;
+    size_t nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types);
+    int i, ret = 0;
+
+    ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
+                                ctx, 0, ctx->par_in->codec_id, 
H2645_FLAG_SMALL_PADDING);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
+        H2645NAL *nal = &s->h2645_pkt.nals[i];
+        if (val_in_array(extradata_nal_types, nb_extradata_nal_types, 
nal->type)) {
+            bytestream2_init_writer(&pb_extradata, NULL, 0);
+            // dummy pass to find sc, gc or ai
+            if (!write_lcevc_nalu(ctx, &pb_extradata, nal))
+                extradata_size += nal->raw_size + 3;
+        } else if (s->remove) {
+            filtered_size += nal->raw_size + 3;
+        }
+    }
+
+    if (extradata_size) {
+        AVBufferRef *filtered_buf = NULL;
+        PutByteContext pb_filtered_data;
+        uint8_t *extradata;
+
+        if (s->remove) {
+            filtered_buf = av_buffer_alloc(filtered_size + 
AV_INPUT_BUFFER_PADDING_SIZE);
+            if (!filtered_buf) {
+                return AVERROR(ENOMEM);
+            }
+            memset(filtered_buf->data + filtered_size, 0, 
AV_INPUT_BUFFER_PADDING_SIZE);
+        }
+
+        extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!extradata) {
+            av_buffer_unref(&filtered_buf);
+            return AVERROR(ENOMEM);
+        }
+
+        *data = extradata;
+        *size = extradata_size;
+
+        bytestream2_init_writer(&pb_extradata, extradata, extradata_size);
+        if (s->remove)
+            bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, 
filtered_size);
+
+        for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
+            H2645NAL *nal = &s->h2645_pkt.nals[i];
+            if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
+                             nal->type)) {
+                bytestream2_put_be24(&pb_extradata, 1); //startcode
+                               *size = write_lcevc_nalu(ctx, &pb_extradata, 
nal);
+            } else if (s->remove) {
+                bytestream2_put_be24(&pb_filtered_data, 1); //startcode
+                *size = write_lcevc_nalu(ctx, &pb_filtered_data, nal);
+            }
+        }
+
+        if (s->remove) {
+            av_buffer_unref(&pkt->buf);
+            pkt->buf  = filtered_buf;
+            pkt->data = filtered_buf->data;
+            pkt->size = filtered_size;
+        }
+    }
+
+    return 0;
+}
+
 static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
                                  uint8_t **data, int *size)
 {
@@ -371,6 +549,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_lcevc   },
     { AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12  },
     { AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12  },
     { AV_CODEC_ID_MPEG4,      extract_extradata_mpeg4   },
@@ -441,6 +620,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 */

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

Reply via email to