mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 00:32:31 +00:00
avformat/mov: support for LCEVC tracks
Co-authored-by: V-Nova Team <systems@v-nova.com> Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
ba0ef0860f
commit
5fa9c4e596
@ -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:
|
||||
|
@ -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') || \
|
||||
|
@ -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 },
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user