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 <[email protected]>
> ---
> 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
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel