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

Reply via email to