[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