diff options
author | James Almer <jamrial@gmail.com> | 2024-08-15 14:06:15 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2024-09-19 10:01:24 -0300 |
commit | 5fa9c4e596ea973659dfcade310ba05610bcf2ea (patch) | |
tree | 12bce3fd163b6e8fb2bbefec7a694f190e4ce7b1 | |
parent | ba0ef0860f0018c6e8fda7b378d69b011575fdaf (diff) | |
download | ffmpeg-5fa9c4e596ea973659dfcade310ba05610bcf2ea.tar.gz |
avformat/mov: support for LCEVC tracks
Co-authored-by: V-Nova Team <systems@v-nova.com>
Signed-off-by: James Almer <jamrial@gmail.com>
-rw-r--r-- | Changelog | 2 | ||||
-rw-r--r-- | libavformat/isom.h | 3 | ||||
-rw-r--r-- | libavformat/isom_tags.c | 2 | ||||
-rw-r--r-- | libavformat/mov.c | 87 |
4 files changed, 93 insertions, 1 deletions
@@ -24,7 +24,7 @@ version <next>: - Vulkan H.264 encoder - Vulkan H.265 encoder - stream specifiers in fftools can now match by stream disposition -- LCEVC enhancement data exporting in H.26x +- LCEVC enhancement data exporting in H.26x and MP4/ISOBMFF version 7.0: diff --git a/libavformat/isom.h b/libavformat/isom.h index 15e9466e41..4723397048 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -212,6 +212,8 @@ typedef struct MOVStreamContext { unsigned drefs_count; MOVDref *drefs; int dref_id; + unsigned tref_flags; + int tref_id; int timecode_track; int width; ///< tkhd width int height; ///< tkhd height @@ -408,6 +410,7 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MOV_SAMPLE_DEPENDENCY_YES 0x1 #define MOV_SAMPLE_DEPENDENCY_NO 0x2 +#define MOV_TREF_FLAG_ENHANCEMENT 0x1 #define TAG_IS_AVCI(tag) \ ((tag) == MKTAG('a', 'i', '5', 'p') || \ diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c index 058f0f2a59..5dd72d570e 100644 --- a/libavformat/isom_tags.c +++ b/libavformat/isom_tags.c @@ -290,6 +290,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_CFHD, MKTAG('C', 'F', 'H', 'D') }, + { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') }, /* LCEVC raw payload */ + { AV_CODEC_ID_NONE, 0 }, }; diff --git a/libavformat/mov.c b/libavformat/mov.c index d57c4f150b..56563be360 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2434,6 +2434,30 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_sbas(MOVContext* c, AVIOContext* pb, MOVAtom atom) +{ + AVStream* st; + MOVStreamContext* sc; + + if (c->fc->nb_streams < 1) + return 0; + + /* For SBAS this should be fine - though beware if someone implements a + * tref atom processor that doesn't drop down to default then this may + * be lost. */ + if (atom.size > 4) { + av_log(c->fc, AV_LOG_ERROR, "Only a single tref of type sbas is supported\n"); + return AVERROR_PATCHWELCOME; + } + + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + sc->tref_id = avio_rb32(pb); + sc->tref_flags |= MOV_TREF_FLAG_ENHANCEMENT; + + return 0; +} + /** * An strf atom is a BITMAPINFOHEADER struct. This struct is 40 bytes itself, * but can have extradata appended at the end after the 40 bytes belonging @@ -4995,6 +5019,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->codec_type = AVMEDIA_TYPE_DATA; sc->ffindex = st->index; c->trak_index = st->index; + sc->tref_flags = 0; + sc->tref_id = -1; sc->refcount = 1; if ((ret = mov_read_default(c, pb, atom)) < 0) @@ -9052,6 +9078,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('a','v','c','C'), mov_read_glbl }, { MKTAG('p','a','s','p'), mov_read_pasp }, { MKTAG('c','l','a','p'), mov_read_clap }, +{ MKTAG('s','b','a','s'), mov_read_sbas }, { MKTAG('s','i','d','x'), mov_read_sidx }, { MKTAG('s','t','b','l'), mov_read_default }, { MKTAG('s','t','c','o'), mov_read_stco }, @@ -9132,6 +9159,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('i','i','n','f'), mov_read_iinf }, { MKTAG('a','m','v','e'), mov_read_amve }, /* ambient viewing environment box */ { MKTAG('l','h','v','C'), mov_read_lhvc }, +{ MKTAG('l','v','c','C'), mov_read_glbl }, #if CONFIG_IAMFDEC { MKTAG('i','a','c','b'), mov_read_iacb }, #endif @@ -10029,6 +10057,21 @@ static int mov_parse_tiles(AVFormatContext *s) return 0; } +static AVStream *mov_find_reference_track(AVFormatContext *s, AVStream *st, + int first_index) +{ + MOVStreamContext *sc = st->priv_data; + + if (sc->tref_id < 0) + return NULL; + + for (int i = first_index; i < s->nb_streams; i++) + if (s->streams[i]->id == sc->tref_id) + return s->streams[i]; + + return NULL; +} + static int mov_read_header(AVFormatContext *s) { MOVContext *mov = s->priv_data; @@ -10154,6 +10197,50 @@ static int mov_read_header(AVFormatContext *s) } export_orphan_timecode(s); + /* Create LCEVC stream groups. */ + for (i = 0; i < s->nb_streams; i++) { + AVStreamGroup *stg; + AVStream *st = s->streams[i]; + AVStream *st_base; + MOVStreamContext *sc = st->priv_data; + + /* Find an enhancement stream. */ + if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC || + !(sc->tref_flags & MOV_TREF_FLAG_ENHANCEMENT)) + continue; + + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + + stg = avformat_stream_group_create(s, AV_STREAM_GROUP_PARAMS_LCEVC, NULL); + if (!stg) + return AVERROR(ENOMEM); + + stg->id = st->id; + stg->params.lcevc->width = st->codecpar->width; + stg->params.lcevc->height = st->codecpar->height; + st->codecpar->width = 0; + st->codecpar->height = 0; + + j = 0; + while (st_base = mov_find_reference_track(s, st, j)) { + err = avformat_stream_group_add_stream(stg, st_base); + if (err < 0) + return err; + + j = st_base->index + 1; + } + if (!j) { + av_log(s, AV_LOG_ERROR, "Failed to find base stream for enhancement stream\n"); + return AVERROR_INVALIDDATA; + } + + err = avformat_stream_group_add_stream(stg, st); + if (err < 0) + return err; + + stg->params.lcevc->lcevc_index = stg->nb_streams; + } + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; FFStream *const sti = ffstream(st); |