movdec: Interpret the ismv specific sdtp atom

Message ID 1329481781-25317-1-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö Feb. 17, 2012, 12:29 p.m.
This atom contains info about which samples are keyframes in
some files where it isn't indicated in any other way. (Smooth
streaming fragments produced by Wowza and ismv files produced
by Sorenson Squeeze don't indicate any difference at all between
keyframes and nonkeyframes via sample flags.)
---
This is an alternative solution to bugzilla bug 215. The original
solution in http://patches.libav.org/patch/16188/ isn't really a
good solution in general, given the way that ismv files use these
sample flags.

 libavformat/isom.h |    2 ++
 libavformat/mov.c  |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 0 deletions(-)

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index e74a552..4d4e307 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -77,6 +77,7 @@  typedef struct {
     unsigned duration;
     unsigned size;
     unsigned flags;
+    unsigned trun_entries;
 } MOVFragment;
 
 typedef struct {
@@ -138,6 +139,7 @@  typedef struct MOVContext {
     DVDemuxContext *dv_demux;
     AVFormatContext *dv_fctx;
     int isom;             ///< 1 if file is ISO Media (mp4/3gp)
+    int ismv;             ///< 1 if file is ISMV/ISMA
     MOVFragment fragment; ///< current fragment in moof atom
     MOVTrackExt *trex_data;
     unsigned trex_count;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 690cd1e..9c0a143 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -664,6 +664,8 @@  static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     avio_read(pb, type, 4);
     if (strcmp(type, "qt  "))
         c->isom = 1;
+    if (!strcmp(type, "isml"))
+        c->ismv = 1;
     av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type);
     av_dict_set(&c->fc->metadata, "major_brand", type, 0);
     minor_ver = avio_rb32(pb); /* minor version */
@@ -2292,10 +2294,54 @@  static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         sc->data_size += sample_size;
     }
     frag->moof_offset = offset;
+    frag->trun_entries = entries;
     st->duration = sc->track_end = dts + sc->time_offset;
     return 0;
 }
 
+static int mov_read_sdtp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    MOVFragment *frag = &c->fragment;
+    AVStream *st = NULL;
+    int i;
+
+    /* Interpret the ismv specific sdtp atom. After the version+flags,
+     * there's one byte per sample in the trun. The bytes seem to be 0x28
+     * for audio streams, 0x24 for video keyframes and 0x14 for video
+     * nonkeyframes.
+     * The sample flags seem to have a different meaning in these files, too,
+     * compared to the iso media spec. For ismv, the flags normally are
+     * 0x8002 for audio samples, 0x4002 for video keyframes and 0x4001 for
+     * nonkeyframes. However, some files don't have sample flags at all,
+     * others don't indicate any difference between keyframes and
+     * nonkeyframes in the flags. By parsing the sdtp, we get keyframes
+     * marked properly. */
+    if (!c->ismv)
+        return 0;
+
+    for (i = 0; i < c->fc->nb_streams && !st; i++)
+        if (c->fc->streams[i]->id == frag->track_id)
+            st = c->fc->streams[i];
+    if (!st) {
+        av_log(c->fc, AV_LOG_ERROR,
+               "could not find corresponding track id %d\n", frag->track_id);
+        return AVERROR_INVALIDDATA;
+    }
+    avio_r8(pb); /* version */
+    avio_rb24(pb); /* flags */
+
+    if (frag->trun_entries == atom.size - 4 &&
+        st->nb_index_entries >= frag->trun_entries) {
+        for (i = 0; i < frag->trun_entries; i++) {
+            int entry = st->nb_index_entries - frag->trun_entries + i;
+            AVIndexEntry *ie = &st->index_entries[entry];
+            if (avio_r8(pb) & 0x20)
+                ie->flags |= AVINDEX_KEYFRAME;
+        }
+    }
+    return 0;
+}
+
 /* this atom should be null (from specs), but some buggy files put the 'moov' atom inside it... */
 /* like the files created with Adobe Premiere 5.0, for samples see */
 /* http://graphics.tudelft.nl/~wouter/publications/soundtests/ */
@@ -2455,6 +2501,7 @@  static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('c','h','a','p'), mov_read_chap },
 { MKTAG('t','r','e','x'), mov_read_trex },
 { MKTAG('t','r','u','n'), mov_read_trun },
+{ MKTAG('s','d','t','p'), mov_read_sdtp },
 { MKTAG('u','d','t','a'), mov_read_default },
 { MKTAG('w','a','v','e'), mov_read_wave },
 { MKTAG('e','s','d','s'), mov_read_esds },