Quoting Vittorio Giovara (2016-06-10 00:55:18) > Store data from each stsd in a separate extradata buffer, keep track of > the stsc index for read and seek operations, switch buffers when the > index differs. Decoder is notified with an AV_PKT_DATA_NEW_EXTRADATA > packet side data. > > Since H264 supports this notification, and can be reset midstream, enable > this feature only for multiple avcC's. All other stsd types (such as > hvc1 and hev1) need decoder-side changes, so they are left disabled for > now. > > Signed-off-by: Vittorio Giovara <vittorio.giov...@gmail.com> > --- > Only modified to avoid caching a zero-sized extradata. > Vittorio > > libavformat/isom.h | 8 ++++ > libavformat/mov.c | 123 > ++++++++++++++++++++++++++++++++++++++++++++++++++--- > 2 files changed, 125 insertions(+), 6 deletions(-) > > diff --git a/libavformat/isom.h b/libavformat/isom.h > index aec623b..75aa70b 100644 > --- a/libavformat/isom.h > +++ b/libavformat/isom.h > @@ -105,6 +105,8 @@ typedef struct MOVStreamContext { > MOVStts *ctts_data; > unsigned int stsc_count; > MOVStsc *stsc_data; > + int stsc_index; > + int stsc_sample; > unsigned int stps_count; > unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop > int ctts_index; > @@ -137,6 +139,12 @@ typedef struct MOVStreamContext { > unsigned int rap_group_count; > MOVSbgp *rap_group; > > + /** extradata array (and size) for multiple stsd */ > + uint8_t **extradata; > + int *extradata_size; > + int last_stsd_index; > + int stsd_count;
Nit: nb_stsd would be more consistent > + > int32_t *display_matrix; > } MOVStreamContext; > > diff --git a/libavformat/mov.c b/libavformat/mov.c > index 125919f..9e2d0e2 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,20 @@ 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->stsd_count > 1) { Are all those checks really necessary? Naively I'd expect that stsd_count==1 is not really any different from stsd_count=n for any larger n. > + /* Move the current stream extradata to the stream context one. > + * In this way, the stsd data can be stored away and a new stream > + * extradata will be allocated by the read functions. */ > + int size = st->codecpar->extradata_size; > + sc->extradata_size[pseudo_stream_id] = size; > + sc->extradata[pseudo_stream_id] = av_malloc(size + > AV_INPUT_BUFFER_PADDING_SIZE); > + if (!sc->extradata[pseudo_stream_id]) > + return AVERROR(ENOMEM); > + memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, > size); > + av_freep(&st->codecpar->extradata); > + st->codecpar->extradata_size = 0; > + } > } > > if (pb->eof_reached) > @@ -1867,13 +1880,46 @@ 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. */ > + if (sc->stsd_count > 1) { > + sc->extradata = av_malloc_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; > + > + /* Reset primary extradata. */ > + if (sc->stsd_count > 1) { > + int size = sc->extradata_size[0]; > + > + av_free(st->codecpar->extradata); > + st->codecpar->extradata_size = size; > + st->codecpar->extradata = av_mallocz(size + > AV_INPUT_BUFFER_PADDING_SIZE); > + if (!st->codecpar->extradata) > + return AVERROR(ENOMEM); > + memcpy(st->codecpar->extradata, sc->extradata[0], size); > + } > + return 0; > } > > static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) > @@ -1916,6 +1962,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 +2626,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 +3434,13 @@ static int mov_read_close(AVFormatContext *s) > av_freep(&sc->stps_data); > av_freep(&sc->rap_group); > av_freep(&sc->display_matrix); > + > + if (sc->stsd_count > 1) > + for (j = 0; j < sc->stsd_count; j++) > + if (sc->extradata_size[j] > 0) This looks rather fragile to me, why not just mallocz sc->extradata and then free its elements unconditionally. -- Anton Khirnov _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel