]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mov.c
Merge commit '76729970049fe95659346503f7401a5d869f9959'
[ffmpeg] / libavformat / mov.c
index 485bb0bc0c723ec46b35e745b4c47e8e840a6333..756d0e8c3c906bc010ed991d33d4e60c4dd18fd0 100644 (file)
@@ -2215,8 +2215,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
         avio_skip(pb, size);
         return 1;
     }
-    if ( codec_tag == AV_RL32("avc1") ||
-         codec_tag == AV_RL32("hvc1") ||
+    if ( codec_tag == AV_RL32("hvc1") ||
          codec_tag == AV_RL32("hev1")
     )
         av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
@@ -2294,6 +2293,19 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
                 return ret;
         } else if (a.size > 0)
             avio_skip(pb, a.size);
+
+        if (sc->extradata) {
+            int extra_size = st->codecpar->extradata_size;
+
+            /* Move the current stream extradata to the stream context one. */
+            sc->extradata_size[pseudo_stream_id] = extra_size;
+            sc->extradata[pseudo_stream_id] = av_malloc(extra_size + AV_INPUT_BUFFER_PADDING_SIZE);
+            if (!sc->extradata[pseudo_stream_id])
+                return AVERROR(ENOMEM);
+            memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, extra_size);
+            av_freep(&st->codecpar->extradata);
+            st->codecpar->extradata_size = 0;
+        }
     }
 
     if (pb->eof_reached)
@@ -2304,13 +2316,41 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
 
 static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
-    int entries;
+    AVStream *st;
+    MOVStreamContext *sc;
+    int ret;
+
+    if (c->fc->nb_streams < 1)
+        return 0;
+    st = c->fc->streams[c->fc->nb_streams - 1];
+    sc = st->priv_data;
 
     avio_r8(pb); /* version */
     avio_rb24(pb); /* flags */
-    entries = avio_rb32(pb);
+    sc->stsd_count = avio_rb32(pb); /* entries */
+
+    /* Prepare space for hosting multiple extradata. */
+    sc->extradata = av_mallocz_array(sc->stsd_count, sizeof(*sc->extradata));
+    if (!sc->extradata)
+        return AVERROR(ENOMEM);
+
+    sc->extradata_size = av_mallocz_array(sc->stsd_count, sizeof(sc->extradata_size));
+    if (!sc->extradata_size)
+        return AVERROR(ENOMEM);
+
+    ret = ff_mov_read_stsd_entries(c, pb, sc->stsd_count);
+    if (ret < 0)
+        return ret;
+
+    /* Restore back the primary extradata. */
+    av_free(st->codecpar->extradata);
+    st->codecpar->extradata_size = sc->extradata_size[0];
+    st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + AV_INPUT_BUFFER_PADDING_SIZE);
+    if (!st->codecpar->extradata)
+        return AVERROR(ENOMEM);
+    memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]);
 
-    return ff_mov_read_stsd_entries(c, pb, entries);
+    return 0;
 }
 
 static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -2355,6 +2395,19 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+/* Compute the samples value for the stsc entry at the given index. */
+static inline int mov_get_stsc_samples(MOVStreamContext *sc, int index)
+{
+    int chunk_count;
+
+    if (index < sc->stsc_count - 1)
+        chunk_count = sc->stsc_data[index + 1].first - sc->stsc_data[index].first;
+    else
+        chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1);
+
+    return sc->stsc_data[index].count * chunk_count;
+}
+
 static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     AVStream *st;
@@ -3212,7 +3265,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     }
     /* Do not need those anymore. */
     av_freep(&sc->chunk_offsets);
-    av_freep(&sc->stsc_data);
     av_freep(&sc->sample_sizes);
     av_freep(&sc->keyframes);
     av_freep(&sc->stts_data);
@@ -4773,6 +4825,11 @@ static int mov_read_close(AVFormatContext *s)
         av_freep(&sc->rap_group);
         av_freep(&sc->display_matrix);
 
+        for (j = 0; j < sc->stsd_count; j++)
+            av_free(sc->extradata[j]);
+        av_freep(&sc->extradata);
+        av_freep(&sc->extradata_size);
+
         av_freep(&sc->cenc.auxiliary_info);
         av_freep(&sc->cenc.auxiliary_info_sizes);
         av_aes_ctr_free(sc->cenc.aes_ctr);
@@ -5190,6 +5247,29 @@ static int mov_switch_root(AVFormatContext *s, int64_t target)
     return 1;
 }
 
+static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt)
+{
+    uint8_t *side, *extradata;
+    int extradata_size;
+
+    /* Save the current index. */
+    sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1;
+
+    /* Notify the decoder that extradata changed. */
+    extradata_size = sc->extradata_size[sc->last_stsd_index];
+    extradata = sc->extradata[sc->last_stsd_index];
+    if (extradata_size > 0 && extradata) {
+        side = av_packet_new_side_data(pkt,
+                                       AV_PKT_DATA_NEW_EXTRADATA,
+                                       extradata_size);
+        if (!side)
+            return AVERROR(ENOMEM);
+        memcpy(side, extradata, extradata_size);
+    }
+
+    return 0;
+}
+
 static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     MOVContext *mov = s->priv_data;
@@ -5282,6 +5362,25 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
     pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
     pkt->pos = sample->pos;
 
+    /* Multiple stsd handling. */
+    if (sc->stsc_data) {
+        /* Keep track of the stsc index for the given sample, then check
+        * if the stsd index is different from the last used one. */
+        sc->stsc_sample++;
+        if (sc->stsc_index < sc->stsc_count - 1 &&
+            mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) {
+            sc->stsc_index++;
+            sc->stsc_sample = 0;
+        /* Do not check indexes after a switch. */
+        } else if (sc->stsc_data[sc->stsc_index].id > 0 &&
+                   sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count &&
+                   sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) {
+            ret = mov_change_extradata(sc, pkt);
+            if (ret < 0)
+                return ret;
+        }
+    }
+
     if (mov->aax_mode)
         aax_filter(pkt->data, pkt->size, mov);
 
@@ -5352,6 +5451,18 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
         }
     }
 
+    /* adjust stsd index */
+    time_sample = 0;
+    for (i = 0; i < sc->stsc_count; i++) {
+        int next = time_sample + mov_get_stsc_samples(sc, i);
+        if (next > sc->current_sample) {
+            sc->stsc_index = i;
+            sc->stsc_sample = sc->current_sample - time_sample;
+            break;
+        }
+        time_sample = next;
+    }
+
     ret = mov_seek_auxiliary_info(s, sc);
     if (ret < 0) {
         return ret;