| @@ -2434,6 +2434,30 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 2433 unmodified lines |
| 2434 | 2434 | return 0; |
| 2435 | 2435 | } |
| 2436 | 2436 | |
| 2437 | +static int mov_read_sbas(MOVContext* c, AVIOContext* pb, MOVAtom atom) |
| 2438 | +{ |
| 2439 | + AVStream* st; |
| 2440 | + MOVStreamContext* sc; |
| 2441 | + |
| 2442 | + if (c->fc->nb_streams < 1) |
| 2443 | + return 0; |
| 2444 | + |
| 2445 | + /* For SBAS this should be fine - though beware if someone implements a |
| 2446 | + * tref atom processor that doesn't drop down to default then this may |
| 2447 | + * be lost. */ |
| 2448 | + if (atom.size > 4) { |
| 2449 | + av_log(c->fc, AV_LOG_ERROR, "Only a single tref of type sbas is supported\n"); |
| 2450 | + return AVERROR_PATCHWELCOME; |
| 2451 | + } |
| 2452 | + |
| 2453 | + st = c->fc->streams[c->fc->nb_streams - 1]; |
| 2454 | + sc = st->priv_data; |
| 2455 | + sc->tref_id = avio_rb32(pb); |
| 2456 | + sc->tref_flags |= MOV_TREF_FLAG_ENHANCEMENT; |
| 2457 | + |
| 2458 | + return 0; |
| 2459 | +} |
| 2460 | + |
| 2437 | 2461 | /** |
| 2438 | 2462 | * An strf atom is a BITMAPINFOHEADER struct. This struct is 40 bytes itself, |
| 2439 | 2463 | * 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) · 2555 unmodified lines |
| 4995 | 5019 | st->codecpar->codec_type = AVMEDIA_TYPE_DATA; |
| 4996 | 5020 | sc->ffindex = st->index; |
| 4997 | 5021 | c->trak_index = st->index; |
| 5022 | + sc->tref_flags = 0; |
| 5023 | + sc->tref_id = -1; |
| 4998 | 5024 | sc->refcount = 1; |
| 4999 | 5025 | |
| 5000 | 5026 | if ((ret = mov_read_default(c, pb, atom)) < 0) |
| @@ -9052,6 +9078,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { · 4051 unmodified lines |
| 9052 | 9078 | { MKTAG('a','v','c','C'), mov_read_glbl }, |
| 9053 | 9079 | { MKTAG('p','a','s','p'), mov_read_pasp }, |
| 9054 | 9080 | { MKTAG('c','l','a','p'), mov_read_clap }, |
| 9081 | +{ MKTAG('s','b','a','s'), mov_read_sbas }, |
| 9055 | 9082 | { MKTAG('s','i','d','x'), mov_read_sidx }, |
| 9056 | 9083 | { MKTAG('s','t','b','l'), mov_read_default }, |
| 9057 | 9084 | { MKTAG('s','t','c','o'), mov_read_stco }, |
| @@ -9132,6 +9159,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { · 74 unmodified lines |
| 9132 | 9159 | { MKTAG('i','i','n','f'), mov_read_iinf }, |
| 9133 | 9160 | { MKTAG('a','m','v','e'), mov_read_amve }, /* ambient viewing environment box */ |
| 9134 | 9161 | { MKTAG('l','h','v','C'), mov_read_lhvc }, |
| 9162 | +{ MKTAG('l','v','c','C'), mov_read_glbl }, |
| 9135 | 9163 | #if CONFIG_IAMFDEC |
| 9136 | 9164 | { MKTAG('i','a','c','b'), mov_read_iacb }, |
| 9137 | 9165 | #endif |
| @@ -10029,6 +10057,21 @@ static int mov_parse_tiles(AVFormatContext *s) · 891 unmodified lines |
| 10029 | 10057 | return 0; |
| 10030 | 10058 | } |
| 10031 | 10059 | |
| 10060 | +static AVStream *mov_find_reference_track(AVFormatContext *s, AVStream *st, |
| 10061 | + int first_index) |
| 10062 | +{ |
| 10063 | + MOVStreamContext *sc = st->priv_data; |
| 10064 | + |
| 10065 | + if (sc->tref_id < 0) |
| 10066 | + return NULL; |
| 10067 | + |
| 10068 | + for (int i = first_index; i < s->nb_streams; i++) |
| 10069 | + if (s->streams[i]->id == sc->tref_id) |
| 10070 | + return s->streams[i]; |
| 10071 | + |
| 10072 | + return NULL; |
| 10073 | +} |
| 10074 | + |
| 10032 | 10075 | static int mov_read_header(AVFormatContext *s) |
| 10033 | 10076 | { |
| 10034 | 10077 | MOVContext *mov = s->priv_data; |
| @@ -10154,6 +10197,50 @@ static int mov_read_header(AVFormatContext *s) · 119 unmodified lines |
| 10154 | 10197 | } |
| 10155 | 10198 | export_orphan_timecode(s); |
| 10156 | 10199 | |
| 10200 | + /* Create LCEVC stream groups. */ |
| 10201 | + for (i = 0; i < s->nb_streams; i++) { |
| 10202 | + AVStreamGroup *stg; |
| 10203 | + AVStream *st = s->streams[i]; |
| 10204 | + AVStream *st_base; |
| 10205 | + MOVStreamContext *sc = st->priv_data; |
| 10206 | + |
| 10207 | + /* Find an enhancement stream. */ |
| 10208 | + if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC || |
| 10209 | + !(sc->tref_flags & MOV_TREF_FLAG_ENHANCEMENT)) |
| 10210 | + continue; |
| 10211 | + |
| 10212 | + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; |
| 10213 | + |
| 10214 | + stg = avformat_stream_group_create(s, AV_STREAM_GROUP_PARAMS_LCEVC, NULL); |
| 10215 | + if (!stg) |
| 10216 | + return AVERROR(ENOMEM); |
| 10217 | + |
| 10218 | + stg->id = st->id; |
| 10219 | + stg->params.lcevc->width = st->codecpar->width; |
| 10220 | + stg->params.lcevc->height = st->codecpar->height; |
| 10221 | + st->codecpar->width = 0; |
| 10222 | + st->codecpar->height = 0; |
| 10223 | + |
| 10224 | + j = 0; |
| 10225 | + while (st_base = mov_find_reference_track(s, st, j)) { |
| 10226 | + err = avformat_stream_group_add_stream(stg, st_base); |
| 10227 | + if (err < 0) |
| 10228 | + return err; |
| 10229 | + |
| 10230 | + j = st_base->index + 1; |
| 10231 | + } |
| 10232 | + if (!j) { |
| 10233 | + av_log(s, AV_LOG_ERROR, "Failed to find base stream for enhancement stream\n"); |
| 10234 | + return AVERROR_INVALIDDATA; |
| 10235 | + } |
| 10236 | + |
| 10237 | + err = avformat_stream_group_add_stream(stg, st); |
| 10238 | + if (err < 0) |
| 10239 | + return err; |
| 10240 | + |
| 10241 | + stg->params.lcevc->lcevc_index = stg->nb_streams; |
| 10242 | + } |
| 10243 | + |
| 10157 | 10244 | for (i = 0; i < s->nb_streams; i++) { |
| 10158 | 10245 | AVStream *st = s->streams[i]; |
| 10159 | 10246 | FFStream *const sti = ffstream(st); |