aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat/mov.c
diff options
context:
space:
mode:
authorRodger Combs <rodger.combs@gmail.com>2016-01-07 17:14:08 -0600
committerRodger Combs <rodger.combs@gmail.com>2016-10-24 05:47:10 -0500
commit697400eac07c0614f6b9f2e7615563982dbcbe4a (patch)
tree19889d47645182bada8d23adb233312b85c64b4e /libavformat/mov.c
parent73ead477ddd9dbfbe6f7e8d3fc90ebfd21b271b0 (diff)
downloadffmpeg-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.c54
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")) {