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


>From f9cb7ca9b94d9497fe749f7fc65247f63ba8af75 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Mon, 16 Mar 2026 18:47:25 -0300
Subject: [PATCH 1/3] avformat/movenc: don't write a tref box of type sbas when
 there's no stream to reference

Signed-off-by: James Almer <[email protected]>
---
 libavformat/movenc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 570dc1efef..5303c9f7b9 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -3841,6 +3841,7 @@ static void get_pts_range(MOVMuxContext *mov, MOVTrack 
*track,
         // tmcd tracks gets track_duration set in mov_write_moov_tag from
         // another track's duration, while the end_pts may be left at zero.
         // Calculate the pts duration for that track instead.
+        av_assert0(track->src_track >= 0);
         get_pts_range(mov, &mov->tracks[track->src_track], start, end);
         *start = av_rescale(*start, track->timescale,
                             mov->tracks[track->src_track].timescale);
@@ -5237,8 +5238,9 @@ static int mov_write_moov_tag(AVIOContext *pb, 
MOVMuxContext *mov,
         MOVTrack *track = &mov->tracks[i];
         if (track->tag == MKTAG('r','t','p',' ')) {
             track->tref_tag = MKTAG('h','i','n','t');
+            av_assert0(track->src_track >= 0);
             track->tref_id = mov->tracks[track->src_track].track_id;
-        } else if (track->tag == MKTAG('l','v','c','1')) {
+        } else if (track->tag == MKTAG('l','v','c','1') && track->src_track >= 
0) {
             track->tref_tag = MKTAG('s','b','a','s');
             track->tref_id = mov->tracks[track->src_track].track_id;
         } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -5257,6 +5259,7 @@ static int mov_write_moov_tag(AVIOContext *pb, 
MOVMuxContext *mov,
     for (i = 0; i < mov->nb_tracks; i++) {
         if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
             int src_trk = mov->tracks[i].src_track;
+            av_assert0(src_trk >= 0);
             mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
             mov->tracks[src_trk].tref_id  = mov->tracks[i].track_id;
             //src_trk may have a different timescale than the tmcd track
@@ -8263,6 +8266,8 @@ static int mov_init(AVFormatContext *s)
         /* If hinting of this track is enabled by a later hint track,
          * this is updated. */
         track->hint_track = -1;
+        /* If this track is meant to reference another, this is updated. */
+        track->src_track = -1;
         track->start_dts  = AV_NOPTS_VALUE;
         track->start_cts  = AV_NOPTS_VALUE;
         track->end_pts    = AV_NOPTS_VALUE;
-- 
2.52.0


>From 31b4c2251094ed36415bfba268e1117ecc6dc164 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Mon, 16 Mar 2026 18:46:21 -0300
Subject: [PATCH 2/3] avformat/lcevc: add a function to parse sequence and
 global config blocks

This exposes parsing already being done to write lvcC boxes, for the purpose
of having these values available elsewhere.
Will be useful for the following change.

Signed-off-by: James Almer <[email protected]>
---
 libavformat/lcevc.c | 76 +++++++++++++++++++++++++++++++++++++++------
 libavformat/lcevc.h | 13 ++++++++
 2 files changed, 79 insertions(+), 10 deletions(-)

diff --git a/libavformat/lcevc.c b/libavformat/lcevc.c
index 83217c2e79..341d8d1694 100644
--- a/libavformat/lcevc.c
+++ b/libavformat/lcevc.c
@@ -30,16 +30,6 @@
 #include "avio_internal.h"
 #include "lcevc.h"
 
-typedef struct LCEVCDecoderConfigurationRecord {
-    uint8_t  profile_idc;
-    uint8_t  level_idc;
-    uint8_t  chroma_format_idc;
-    uint8_t  bit_depth_luma_minus8;
-    uint8_t  bit_depth_chroma_minus8;
-    uint32_t pic_width_in_luma_samples;
-    uint32_t pic_height_in_luma_samples;
-} LCEVCDecoderConfigurationRecord;
-
 /**
  * Rewrite the NALu stripping the unneeded blocks.
  * Given that length fields coded inside the NALu are not aware of any 
emulation_3bytes
@@ -187,6 +177,72 @@ static int write_nalu(LCEVCDecoderConfigurationRecord 
*lvcc, AVIOContext *pb,
     return 0;
 }
 
+int ff_lcvec_parse_config_record(LCEVCDecoderConfigurationRecord *lvcc,
+                                 const uint8_t *buf, int size)
+{
+    H2645Packet h2645_pkt = { 0 };
+    AVIOContext *pb;
+    int ret;
+
+    if (size <= 0)
+        return AVERROR_INVALIDDATA;
+
+    if (buf[0] == 1) {
+        GetBitContext gb;
+
+        if (size < 13)
+            return AVERROR_INVALIDDATA;
+
+        ret = init_get_bits8(&gb, buf, 13);
+        if (ret < 0)
+            return ret;
+
+        memset(lvcc, 0, sizeof(*lvcc));
+
+        skip_bits(&gb, 8);
+        lvcc->profile_idc                 = get_bits(&gb, 8);
+        lvcc->level_idc                   = get_bits(&gb, 8);
+        lvcc->chroma_format_idc           = get_bits(&gb, 2);
+        lvcc->bit_depth_luma_minus8       = get_bits(&gb, 3);
+        lvcc->bit_depth_chroma_minus8     = get_bits(&gb, 3);
+        skip_bits(&gb, 8);
+        lvcc->pic_width_in_luma_samples   = get_bits_long(&gb, 32);
+        lvcc->pic_height_in_luma_samples  = get_bits_long(&gb, 32);
+
+        return 0;
+    }
+
+    ret = ffio_open_null_buf(&pb);
+    if (ret < 0)
+        return ret;
+
+    ret = ff_h2645_packet_split(&h2645_pkt, buf, size, NULL, 0, 
AV_CODEC_ID_LCEVC, 0);
+    if (ret < 0)
+        goto fail;
+
+    /* look for IDR or NON_IDR */
+    for (int i = 0; i < h2645_pkt.nb_nals; i++) {
+        const H2645NAL *nal = &h2645_pkt.nals[i];
+
+        if (nal->type == LCEVC_IDR_NUT) {
+            ret = write_nalu(lvcc, pb, nal);
+            if (ret < 0)
+                goto fail;
+        } else if (nal->type == LCEVC_NON_IDR_NUT) {
+            ret = write_nalu(lvcc, pb, nal);
+            if (ret < 0)
+                goto fail;
+        }
+    }
+
+    ret = 0;
+fail:
+    ffio_close_null_buf(pb);
+    ff_h2645_packet_uninit(&h2645_pkt);
+
+    return ret;
+}
+
 int ff_isom_write_lvcc(AVIOContext *pb, const uint8_t *data, int len)
 {
     LCEVCDecoderConfigurationRecord lvcc = { 0 };
diff --git a/libavformat/lcevc.h b/libavformat/lcevc.h
index 76093c4a36..9bbc0c6764 100644
--- a/libavformat/lcevc.h
+++ b/libavformat/lcevc.h
@@ -24,6 +24,19 @@
 #include <stdint.h>
 #include "avio.h"
 
+typedef struct LCEVCDecoderConfigurationRecord {
+    uint8_t  profile_idc;
+    uint8_t  level_idc;
+    uint8_t  chroma_format_idc;
+    uint8_t  bit_depth_luma_minus8;
+    uint8_t  bit_depth_chroma_minus8;
+    uint32_t pic_width_in_luma_samples;
+    uint32_t pic_height_in_luma_samples;
+} LCEVCDecoderConfigurationRecord;
+
 int ff_isom_write_lvcc(AVIOContext *pb, const uint8_t *data, int len);
 
+int ff_lcvec_parse_config_record(LCEVCDecoderConfigurationRecord *lvcc,
+                                 const uint8_t *buf, int size);
+
 #endif /* AVFORMAT_LCEVC_H */
-- 
2.52.0


>From af5db49a61f190541eb2756e8bcddd6fc6430e6f Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Mon, 16 Mar 2026 18:46:48 -0300
Subject: [PATCH 3/3] avformat/codecstring: add support for LCEVC streams

Signed-off-by: James Almer <[email protected]>
---
 libavformat/codecstring.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libavformat/codecstring.c b/libavformat/codecstring.c
index c6672b7244..b0ccb93e8d 100644
--- a/libavformat/codecstring.c
+++ b/libavformat/codecstring.c
@@ -29,6 +29,7 @@
 #include "avc.h"
 #include "avformat.h"
 #include "internal.h"
+#include "lcevc.h"
 #include "nal.h"
 #include "vpcc.h"
 
@@ -174,6 +175,14 @@ int ff_make_codec_str(void *logctx, const 
AVCodecParameters *par,
                        profile_compatibility, tier, level, constraints);
         } else
             return AVERROR(EINVAL);
+    } else if (par->codec_id == AV_CODEC_ID_LCEVC) {
+        LCEVCDecoderConfigurationRecord lvcc;
+        int err;
+        if (!par->extradata_size)
+            return AVERROR(EINVAL);
+        if ((err = ff_lcvec_parse_config_record(&lvcc, par->extradata, 
par->extradata_size)) < 0)
+            return err;
+        av_bprintf(out, "lvc1.vprf%u.vlev%u", lvcc.profile_idc, 
lvcc.level_idc);
     } else if (par->codec_id == AV_CODEC_ID_AV1) {
         // https://aomediacodec.github.io/av1-isobmff/#codecsparam
         AV1SequenceParameters seq;
-- 
2.52.0

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

Reply via email to