diff options
author | Rodger Combs <rodger.combs@gmail.com> | 2016-01-07 17:14:08 -0600 |
---|---|---|
committer | Rodger Combs <rodger.combs@gmail.com> | 2016-10-24 05:47:10 -0500 |
commit | 697400eac07c0614f6b9f2e7615563982dbcbe4a (patch) | |
tree | 19889d47645182bada8d23adb233312b85c64b4e /libavformat/mov.c | |
parent | 73ead477ddd9dbfbe6f7e8d3fc90ebfd21b271b0 (diff) | |
download | ffmpeg-697400eac07c0614f6b9f2e7615563982dbcbe4a.tar.gz |
lavf/mov: improve `tref/chap` chapter handling
3 parts:
- Supports multiple chapter streams
- Exports regular text chapter streams as opaque data. This prevents consumers
from showing chapters as if they were regular subtitle streams.
- Exports video chapter streams as thumbnails, and provides the first one as
an attached_pic.
Diffstat (limited to 'libavformat/mov.c')
-rw-r--r-- | libavformat/mov.c | 54 |
1 files changed, 47 insertions, 7 deletions
diff --git a/libavformat/mov.c b/libavformat/mov.c index dada1e07e0..bf25db9332 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3992,7 +3992,20 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_chap(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - c->chapter_track = avio_rb32(pb); + unsigned i, num; + void *new_tracks; + + num = atom.size / 4; + if (!(new_tracks = av_malloc_array(num, sizeof(int)))) + return AVERROR(ENOMEM); + + av_free(c->chapter_tracks); + c->chapter_tracks = new_tracks; + c->nb_chapter_tracks = num; + + for (i = 0; i < num && !pb->eof_reached; i++) + c->chapter_tracks[i] = avio_rb32(pb); + return 0; } @@ -5055,25 +5068,50 @@ static int mov_probe(AVProbeData *p) static void mov_read_chapters(AVFormatContext *s) { MOVContext *mov = s->priv_data; - AVStream *st = NULL; + AVStream *st; MOVStreamContext *sc; int64_t cur_pos; - int i; + int i, j; + int chapter_track; + for (j = 0; j < mov->nb_chapter_tracks; j++) { + chapter_track = mov->chapter_tracks[j]; + st = NULL; for (i = 0; i < s->nb_streams; i++) - if (s->streams[i]->id == mov->chapter_track) { + if (s->streams[i]->id == chapter_track) { st = s->streams[i]; break; } if (!st) { av_log(s, AV_LOG_ERROR, "Referenced QT chapter track not found\n"); - return; + continue; } - st->discard = AVDISCARD_ALL; sc = st->priv_data; cur_pos = avio_tell(sc->pb); + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS; + if (st->nb_index_entries) { + // Retrieve the first frame, if possible + AVPacket pkt; + AVIndexEntry *sample = &st->index_entries[0]; + if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { + av_log(s, AV_LOG_ERROR, "Failed to retrieve first frame\n"); + goto finish; + } + + if (av_get_packet(sc->pb, &pkt, sample->size) < 0) + goto finish; + + st->attached_pic = pkt; + st->attached_pic.stream_index = st->index; + st->attached_pic.flags |= AV_PKT_FLAG_KEY; + } + } else { + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA; + st->discard = AVDISCARD_ALL; for (i = 0; i < st->nb_index_entries; i++) { AVIndexEntry *sample = &st->index_entries[i]; int64_t end = i+1 < st->nb_index_entries ? st->index_entries[i+1].timestamp : st->duration; @@ -5122,8 +5160,10 @@ static void mov_read_chapters(AVFormatContext *s) avpriv_new_chapter(s, i, st->time_base, sample->timestamp, end, title); av_freep(&title); } + } finish: avio_seek(sc->pb, cur_pos, SEEK_SET); + } } static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, @@ -5446,7 +5486,7 @@ static int mov_read_header(AVFormatContext *s) av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); if (pb->seekable) { - if (mov->chapter_track > 0 && !mov->ignore_chapters) + if (mov->nb_chapter_tracks > 0 && !mov->ignore_chapters) mov_read_chapters(s); for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->codecpar->codec_tag == AV_RL32("tmcd")) { |