From 2cb9c2fc59c9267ad2631c07c81c188058502259 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Tue, 10 Sep 2013 15:35:41 +0300 Subject: movenc: Allow interleaving samples when writing fragmented files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is incompatible with the omit_tfhd_offset flag (writing position independent fragments with interleaving requires the default_base_moof flag). This makes the moof atoms slightly bigger, but can be better for playback (improving locality of sample data in the mdat). Signed-off-by: Martin Storsjö --- libavformat/movenc.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 7 deletions(-) (limited to 'libavformat/movenc.c') diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 40de25c785..ae7029dbad 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -73,6 +73,7 @@ static const AVOption options[] = { { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM }, { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, + { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, }; @@ -3118,6 +3119,32 @@ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk) } } +static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track) +{ + MOVMuxContext *mov = s->priv_data; + int ret, buf_size; + uint8_t *buf; + int i, offset; + + if (!track->mdat_buf) + return 0; + if (!mov->mdat_buf) { + if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0) + return ret; + } + buf_size = avio_close_dyn_buf(track->mdat_buf, &buf); + track->mdat_buf = NULL; + + offset = avio_tell(mov->mdat_buf); + avio_write(mov->mdat_buf, buf, buf_size); + av_free(buf); + + for (i = track->entries_flushed; i < track->entry; i++) + track->cluster[i].pos += offset; + track->entries_flushed = track->entry; + return 0; +} + static int mov_flush_fragment(AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; @@ -3180,15 +3207,29 @@ static int mov_flush_fragment(AVFormatContext *s) return 0; } + if (mov->frag_interleave) { + for (i = 0; i < mov->nb_streams; i++) { + MOVTrack *track = &mov->tracks[i]; + int ret; + if ((ret = mov_flush_fragment_interleaving(s, track)) < 0) + return ret; + } + + if (!mov->mdat_buf) + return 0; + mdat_size = avio_tell(mov->mdat_buf); + } + for (i = 0; i < mov->nb_streams; i++) { MOVTrack *track = &mov->tracks[i]; - if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) + if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave) track->data_offset = 0; else track->data_offset = mdat_size; - if (!track->mdat_buf) + if (!track->entry) continue; - mdat_size += avio_tell(track->mdat_buf); + if (track->mdat_buf) + mdat_size += avio_tell(track->mdat_buf); if (first_track < 0) first_track = i; } @@ -3227,10 +3268,18 @@ static int mov_flush_fragment(AVFormatContext *s) if (track->entry) track->frag_start += duration; track->entry = 0; - if (!track->mdat_buf) - continue; - buf_size = avio_close_dyn_buf(track->mdat_buf, &buf); - track->mdat_buf = NULL; + track->entries_flushed = 0; + if (!mov->frag_interleave) { + if (!track->mdat_buf) + continue; + buf_size = avio_close_dyn_buf(track->mdat_buf, &buf); + track->mdat_buf = NULL; + } else { + if (!mov->mdat_buf) + continue; + buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf); + mov->mdat_buf = NULL; + } avio_write(s->pb, buf, buf_size); av_free(buf); @@ -3269,6 +3318,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (mov->flags & FF_MOV_FLAG_FRAGMENT) { int ret; if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) { + if (mov->frag_interleave && mov->fragments > 0) { + if (trk->entry - trk->entries_flushed >= mov->frag_interleave) { + if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0) + return ret; + } + } + if (!trk->mdat_buf) { if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0) return ret; @@ -3741,6 +3797,21 @@ static int mov_write_header(AVFormatContext *s) if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO) s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO; + /* Clear the omit_tfhd_offset flag if default_base_moof is set; + * if the latter is set that's enough and omit_tfhd_offset doesn't + * add anything extra on top of that. */ + if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET && + mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) + mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET; + + if (mov->frag_interleave && + mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) { + av_log(s, AV_LOG_ERROR, + "Sample interleaving in fragments is mutually exclusive with " + "omit_tfhd_offset and separate_moof\n"); + return AVERROR(EINVAL); + } + /* Non-seekable output is ok if using fragmentation. If ism_lookahead * is enabled, we don't support non-seekable output at all. */ if (!s->pb->seekable && -- cgit v1.2.3