summaryrefslogtreecommitdiffstats
path: root/libavformat/mov.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/mov.c')
-rw-r--r--libavformat/mov.c125
1 files changed, 119 insertions, 6 deletions
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 125919f..a9b826f 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1771,8 +1771,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
if (codec_tag &&
- (codec_tag == AV_RL32("avc1") ||
- codec_tag == AV_RL32("hvc1") ||
+ (codec_tag == AV_RL32("hvc1") ||
codec_tag == AV_RL32("hev1") ||
(codec_tag != format &&
(c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
@@ -1857,6 +1856,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)
@@ -1867,13 +1879,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);
- return ff_mov_read_stsd_entries(c, pb, entries);
+ 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 0;
}
static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -1906,6 +1946,8 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->stsc_data[i].first = avio_rb32(pb);
sc->stsc_data[i].count = avio_rb32(pb);
sc->stsc_data[i].id = avio_rb32(pb);
+ if (sc->stsc_data[i].id > sc->stsd_count)
+ return AVERROR_INVALIDDATA;
}
sc->stsc_count = i;
@@ -1916,6 +1958,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;
@@ -2567,7 +2622,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);
@@ -3376,6 +3430,11 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->stps_data);
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);
}
if (mov->dv_demux) {
@@ -3507,6 +3566,29 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
return sample;
}
+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;
@@ -3589,6 +3671,24 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->pos = sample->pos;
av_log(s, AV_LOG_TRACE, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %"PRId64"\n",
pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration);
+
+ /* 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 &&
+ 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 - 1 != sc->last_stsd_index) {
+ ret = mov_change_extradata(sc, pkt);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
return 0;
}
@@ -3619,6 +3719,19 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
time_sample = next;
}
}
+
+ /* 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;
+ }
+
return sample;
}
OpenPOWER on IntegriCloud