[FFmpeg-cvslog] Merge commit '76729970049fe95659346503f7401a5d869f9959'

Robert Krüger krueger at lesspain.software
Wed Jul 20 11:03:57 CEST 2016


On Wed, Jul 13, 2016 at 4:55 PM, Matthieu Bouron <git at videolan.org> wrote:

> ffmpeg | branch: master | Matthieu Bouron <matthieu.bouron at stupeflix.com>
> | Wed Jul 13 16:34:39 2016 +0200|
> [3c058f570128dcfa3a68f0860e2be7f098e8d6e1] | committer: Matthieu Bouron
>
> Merge commit '76729970049fe95659346503f7401a5d869f9959'
>
> * commit '76729970049fe95659346503f7401a5d869f9959':
>   mov: Implement support for multiple sample description tables
>
> Notes:
>   * The sc->stsc_data[index].id checks have been moved from the
> mov_read_stsc
>   to mov_read_packet before the value is used in mov_change_extradata to
>   not break playback of samples with broken stsc entries (see sample of
>   ticket #1918).
>
>   * sc->stsc_index is now checked against sc->stsc_count - 1 before it
>   is incremented so it remains lesser than sc->stsc_count. Fixes a crash
>   with:
>
>   ./ffmpeg -i matrixbench_mpeg2.mpg -t 1 -frag_duration 200k test.mov
>   ./ffprobe -show_packets test.mov
>
> Merged-by: Matthieu Bouron <matthieu.bouron at stupeflix.com>
>
> >
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=3c058f570128dcfa3a68f0860e2be7f098e8d6e1
> ---
>
>  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 726f350..df6c15a 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -128,6 +128,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
>      MOVElst *elst_data;
> @@ -169,6 +171,12 @@ typedef struct MOVStreamContext {
>      int nb_frames_for_fps;
>      int64_t duration_for_fps;
>
> +    /** extradata array (and size) for multiple stsd */
> +    uint8_t **extradata;
> +    int *extradata_size;
> +    int last_stsd_index;
> +    int stsd_count;
> +
>      int32_t *display_matrix;
>      uint32_t format;
>
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 485bb0b..756d0e8 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -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;
>
>
> ======================================================================
>
> diff --cc libavformat/isom.h
> index 726f350,75aa70b..df6c15a
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@@ -128,14 -105,13 +128,16 @@@ 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
>  +    MOVElst *elst_data;
>  +    unsigned int elst_count;
>       int ctts_index;
>       int ctts_sample;
>  -    unsigned int sample_size;
>  +    unsigned int sample_size; ///< may contain value calculated from
> stsd or value from stsz atom
>  +    unsigned int stsz_sample_size; ///< always contains sample size from
> stsz atom
>       unsigned int sample_count;
>       int *sample_sizes;
>       int keyframe_absent;
> @@@ -166,22 -139,13 +168,28 @@@
>       unsigned int rap_group_count;
>       MOVSbgp *rap_group;
>
>  +    int nb_frames_for_fps;
>  +    int64_t duration_for_fps;
>  +
> +     /** extradata array (and size) for multiple stsd */
> +     uint8_t **extradata;
> +     int *extradata_size;
> +     int last_stsd_index;
> +     int stsd_count;
> +
>       int32_t *display_matrix;
>  +    uint32_t format;
>  +
>  +    struct {
>  +        int use_subsamples;
>  +        uint8_t* auxiliary_info;
>  +        uint8_t* auxiliary_info_end;
>  +        uint8_t* auxiliary_info_pos;
>  +        uint8_t auxiliary_info_default_size;
>  +        uint8_t* auxiliary_info_sizes;
>  +        size_t auxiliary_info_sizes_count;
>  +        struct AVAESCTR* aes_ctr;
>  +    } cenc;
>   } MOVStreamContext;
>
>   typedef struct MOVContext {
> diff --cc libavformat/mov.c
> index 485bb0b,a9b826f..756d0e8
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@@ -2215,11 -1784,6 +2215,10 @@@ static int mov_skip_multiple_stsd(MOVCo
>           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");
>
>       return 0;
>   }
> @@@ -3201,18 -2615,13 +3254,17 @@@ static int mov_read_trak(MOVContext *c
>           st->codecpar->width = 0; /* let decoder init width/height */
>           st->codecpar->height= 0;
>           break;
>  -    case AV_CODEC_ID_MP3:
>  -        st->need_parsing = AVSTREAM_PARSE_FULL;
>  -        break;
>       }
>
>  +    // If the duration of the mp3 packets is not constant, then they
> could need a parser
>  +    if (st->codecpar->codec_id == AV_CODEC_ID_MP3
>  +        && sc->stts_count > 3
>  +        && sc->stts_count*10 > st->nb_frames
>  +        && sc->time_scale == st->codecpar->sample_rate) {
>  +            st->need_parsing = AVSTREAM_PARSE_FULL;
>  +    }
>       /* 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,9 -3431,10 +4825,14 @@@ static int mov_read_close(AVFormatConte
>           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);
>       }
>
>       if (mov->dv_demux) {
> @@@ -5137,59 -3566,29 +5194,82 @@@ static AVIndexEntry *mov_find_next_samp
>       return sample;
>   }
>
>  +static int should_retry(AVIOContext *pb, int error_code) {
>  +    if (error_code == AVERROR_EOF || avio_feof(pb))
>  +        return 0;
>  +
>  +    return 1;
>  +}
>  +
>  +static int mov_switch_root(AVFormatContext *s, int64_t target)
>  +{
>  +    MOVContext *mov = s->priv_data;
>  +    int i, j;
>  +    int already_read = 0;
>  +
>  +    if (avio_seek(s->pb, target, SEEK_SET) != target) {
>  +        av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64":
> partial file\n", target);
>  +        return AVERROR_INVALIDDATA;
>  +    }
>  +
>  +    mov->next_root_atom = 0;
>  +
>  +    for (i = 0; i < mov->fragment_index_count; i++) {
>  +        MOVFragmentIndex *index = mov->fragment_index_data[i];
>  +        int found = 0;
>  +        for (j = 0; j < index->item_count; j++) {
>  +            MOVFragmentIndexItem *item = &index->items[j];
>  +            if (found) {
>  +                mov->next_root_atom = item->moof_offset;
>  +                break; // Advance to next index in outer loop
>  +            } else if (item->moof_offset == target) {
>  +                index->current_item = FFMIN(j, index->current_item);
>  +                if (item->headers_read)
>  +                    already_read = 1;
>  +                item->headers_read = 1;
>  +                found = 1;
>  +            }
>  +        }
>  +        if (!found)
>  +            index->current_item = 0;
>  +    }
>  +
>  +    if (already_read)
>  +        return 0;
>  +
>  +    mov->found_mdat = 0;
>  +
>  +    if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"),
> INT64_MAX }) < 0 ||
>  +        avio_feof(s->pb))
>  +        return AVERROR_EOF;
>  +    av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n",
> avio_tell(s->pb));
>  +
>  +    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;
> @@@ -5281,42 -3669,26 +5361,61 @@@
>           goto retry;
>       pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
>       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 &&
> ++        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 - 1 !=
> sc->last_stsd_index) {
> ++        } 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);
>  +
>  +    if (sc->cenc.aes_ctr) {
>  +        ret = cenc_filter(mov, sc, pkt->data, pkt->size);
>  +        if (ret) {
>  +            return ret;
>  +        }
>  +    }
>  +
>  +    return 0;
>  +}
>  +
>  +static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t
> timestamp)
>  +{
>  +    MOVContext *mov = s->priv_data;
>  +    int i, j;
>  +
>  +    if (!mov->fragment_index_complete)
>  +        return 0;
>  +
>  +    for (i = 0; i < mov->fragment_index_count; i++) {
>  +        if (mov->fragment_index_data[i]->track_id == st->id) {
>  +            MOVFragmentIndex *index = mov->fragment_index_data[i];
>  +            for (j = index->item_count - 1; j >= 0; j--) {
>  +                if (index->items[j].time <= timestamp) {
>  +                    if (index->items[j].headers_read)
>  +                        return 0;
>  +
>  +                    return mov_switch_root(s,
> index->items[j].moof_offset);
>  +                }
>  +            }
>  +        }
>  +    }
>  +
>       return 0;
>   }
>
> @@@ -5352,11 -3720,18 +5451,23 @@@ static int mov_seek_stream(AVFormatCont
>           }
>       }
>
> +     /* 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;
>  +    }
>  +
>       return sample;
>   }
>
>
>
Don't know if that's come to the author's attention. This caused a
regression, see http://trac.ffmpeg.org/ticket/5723


More information about the ffmpeg-cvslog mailing list