[FFmpeg-devel,4/6] lavf/mov: set AV_PKT_FLAG_DISPOSABLE from sdtp box

Submitted by John Stebbins on Dec. 1, 2017, 12:25 a.m.

Details

Message ID 20171201002502.24432-2-jstebbins@jetheaddev.com
State New
Headers show

Commit Message

John Stebbins Dec. 1, 2017, 12:25 a.m.
---
 libavformat/isom.h  | 10 ++++++
 libavformat/mov.c   | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 libavformat/utils.c |  3 +-
 3 files changed, 99 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 65676fb0f5..646b31ccc7 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -137,11 +137,19 @@  typedef struct MOVIndexRange {
     int64_t end;
 } MOVIndexRange;
 
+typedef struct MOVIndexEntry {
+#define MOVINDEX_DISPOSABLE 0x01
+    int8_t  flags;
+} MOVIndexEntry;
+
 typedef struct MOVStreamContext {
     AVIOContext *pb;
     int pb_is_copied;
     int ffindex;          ///< AVStream index
     int next_chunk;
+    MOVIndexEntry * mov_index_entries;
+    int nb_mov_index_entries;
+    unsigned int mov_index_allocated_size;
     unsigned int chunk_count;
     int64_t *chunk_offsets;
     unsigned int stts_count;
@@ -166,6 +174,8 @@  typedef struct MOVStreamContext {
     int keyframe_absent;
     unsigned int keyframe_count;
     int *keyframes;
+    unsigned int frame_deps_count;
+    int *frame_deps;
     int time_scale;
     int64_t time_offset;  ///< time offset of the edit list entries
     int current_sample;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index f7fab98dd8..2bb81d8f01 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2682,6 +2682,43 @@  static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_sdtp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    unsigned int i, entries;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+    st = c->fc->streams[c->fc->nb_streams-1];
+    sc = st->priv_data;
+
+    if (atom.size < 8)
+        return 0;
+
+    avio_r8(pb); /* version */
+    avio_rb24(pb); /* flags */
+
+    entries = atom.size - 4;
+    sc->frame_deps_count = 0;
+    sc->frame_deps = av_malloc_array(entries, sizeof(*sc->frame_deps));
+
+    if (!sc->frame_deps)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < entries && !pb->eof_reached; i++) {
+        sc->frame_deps[i] = avio_r8(pb);
+    }
+
+    sc->frame_deps_count = i;
+
+    if (pb->eof_reached)
+        return AVERROR_EOF;
+
+
+    return 0;
+}
+
 static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     AVStream *st;
@@ -3638,15 +3675,40 @@  static void mov_build_index(MOVContext *mov, AVStream *st)
 
         if (!sc->sample_count || st->nb_index_entries)
             return;
-        if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
+        if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries))
             return;
-        if (av_reallocp_array(&st->index_entries,
-                              st->nb_index_entries + sc->sample_count,
+        if (av_reallocp_array(&st->index_entries, sc->sample_count,
                               sizeof(*st->index_entries)) < 0) {
             st->nb_index_entries = 0;
             return;
         }
-        st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries);
+        st->index_entries_allocated_size = sc->sample_count *
+                                           sizeof(*st->index_entries);
+
+        // realloc mov_index_entries if needed for frame dependencies
+        // or if it already exists for ctts
+        if (sc->frame_deps || sc->mov_index_entries) {
+            // make mov_index_entries the same number of entries as
+            // index_entries
+            if (av_reallocp_array(&sc->mov_index_entries,
+                                  sc->sample_count,
+                                  sizeof(*sc->mov_index_entries)) < 0) {
+                sc->nb_mov_index_entries = 0;
+                return;
+            }
+            sc->mov_index_allocated_size = sc->sample_count *
+                                           sizeof(*sc->mov_index_entries);
+
+            if (sc->sample_count > sc->nb_mov_index_entries)
+                // In case there were samples without ctts entries, ensure they
+                // get zero valued entries. This ensures clips which mix boxes
+                // with and without ctts entries don't pickup uninitialized
+                // data.
+                memset(sc->mov_index_entries + sc->nb_mov_index_entries, 0,
+                       (sc->sample_count - sc->nb_mov_index_entries) *
+                       sizeof(*sc->mov_index_entries));
+            sc->nb_mov_index_entries = sc->sample_count;
+        }
 
         if (ctts_data_old) {
             // Expand ctts entries such that we have a 1-1 mapping with samples
@@ -3689,10 +3751,14 @@  static void mov_build_index(MOVContext *mov, AVStream *st)
 
             for (j = 0; j < sc->stsc_data[stsc_index].count; j++) {
                 int keyframe = 0;
+                int disposable = 0;
                 if (current_sample >= sc->sample_count) {
                     av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n");
                     return;
                 }
+                if (sc->frame_deps && current_sample < sc->frame_deps_count)
+                    disposable = ((sc->frame_deps[current_sample] >> 2) & 3) ==
+                                 MOV_SAMPLE_DEPENDENCY_NO;
 
                 if (!sc->keyframe_absent && (!sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index])) {
                     keyframe = 1;
@@ -3722,16 +3788,22 @@  static void mov_build_index(MOVContext *mov, AVStream *st)
                 if (sc->pseudo_stream_id == -1 ||
                    sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {
                     AVIndexEntry *e;
+                    MOVIndexEntry *me;
                     if (sample_size > 0x3FFFFFFF) {
                         av_log(mov->fc, AV_LOG_ERROR, "Sample size %u is too large\n", sample_size);
                         return;
                     }
-                    e = &st->index_entries[st->nb_index_entries++];
+                    e = &st->index_entries[st->nb_index_entries];
                     e->pos = current_offset;
                     e->timestamp = current_dts;
                     e->size = sample_size;
                     e->min_distance = distance;
                     e->flags = keyframe ? AVINDEX_KEYFRAME : 0;
+                    if (sc->mov_index_entries) {
+                        me = &sc->mov_index_entries[st->nb_index_entries];
+                        me->flags = disposable ? MOVINDEX_DISPOSABLE : 0;
+                    }
+                    st->nb_index_entries++;
                     av_log(mov->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %u, offset %"PRIx64", dts %"PRId64", "
                             "size %u, distance %u, keyframe %d\n", st->index, current_sample,
                             current_offset, current_dts, sample_size, distance, keyframe);
@@ -4098,6 +4170,7 @@  static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     av_freep(&sc->chunk_offsets);
     av_freep(&sc->sample_sizes);
     av_freep(&sc->keyframes);
+    av_freep(&sc->frame_deps);
     av_freep(&sc->stts_data);
     av_freep(&sc->stps_data);
     av_freep(&sc->elst_data);
@@ -5975,6 +6048,7 @@  static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('s','t','s','c'), mov_read_stsc },
 { MKTAG('s','t','s','d'), mov_read_stsd }, /* sample description */
 { MKTAG('s','t','s','s'), mov_read_stss }, /* sync sample */
+{ MKTAG('s','d','t','p'), mov_read_sdtp }, /* sample dependencies */
 { MKTAG('s','t','s','z'), mov_read_stsz }, /* sample size */
 { MKTAG('s','t','t','s'), mov_read_stts },
 { MKTAG('s','t','z','2'), mov_read_stsz }, /* compact sample size */
@@ -6407,6 +6481,7 @@  static int mov_read_close(AVFormatContext *s)
             continue;
 
         av_freep(&sc->ctts_data);
+        av_freep(&sc->mov_index_entries);
         for (j = 0; j < sc->drefs_count; j++) {
             av_freep(&sc->drefs[j].path);
             av_freep(&sc->drefs[j].dir);
@@ -6423,6 +6498,7 @@  static int mov_read_close(AVFormatContext *s)
         av_freep(&sc->stsc_data);
         av_freep(&sc->sample_sizes);
         av_freep(&sc->keyframes);
+        av_freep(&sc->frame_deps);
         av_freep(&sc->stts_data);
         av_freep(&sc->stps_data);
         av_freep(&sc->elst_data);
@@ -6912,6 +6988,7 @@  static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
     MOVContext *mov = s->priv_data;
     MOVStreamContext *sc;
     AVIndexEntry *sample;
+    MOVIndexEntry *movsample = NULL;
     AVStream *st = NULL;
     int64_t current_index;
     int ret;
@@ -6926,6 +7003,8 @@  static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
         goto retry;
     }
     sc = st->priv_data;
+    if (sc->current_sample < sc->nb_mov_index_entries)
+        movsample = &sc->mov_index_entries[sc->current_sample];
     /* must be done just before reading, to avoid infinite loop on sample */
     current_index = sc->current_index;
     mov_current_sample_inc(sc);
@@ -7008,6 +7087,9 @@  static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
     if (st->discard == AVDISCARD_ALL)
         goto retry;
     pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
+    if (movsample)
+        pkt->flags |= movsample->flags & MOVINDEX_DISPOSABLE ?
+                                         AV_PKT_FLAG_DISPOSABLE : 0;
     pkt->pos = sample->pos;
 
     /* Multiple stsd handling. */
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 84e49208b8..816f963b5f 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1458,7 +1458,8 @@  static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
         out_pkt.pts          = st->parser->pts;
         out_pkt.dts          = st->parser->dts;
         out_pkt.pos          = st->parser->pos;
-        out_pkt.flags       |= pkt->flags & AV_PKT_FLAG_DISCARD;
+        out_pkt.flags       |= pkt->flags & (AV_PKT_FLAG_DISCARD |
+                                             AV_PKT_FLAG_DISPOSABLE);
 
         if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW)
             out_pkt.pos = st->parser->frame_offset;