summaryrefslogtreecommitdiff
path: root/libavformat/movenc.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2013-09-10 15:35:41 +0300
committerMartin Storsjö <martin@martin.st>2015-03-16 13:23:19 +0200
commit2cb9c2fc59c9267ad2631c07c81c188058502259 (patch)
tree2912430e30e9576c9ecfbefec1512fb995e2b403 /libavformat/movenc.c
parent50ff0c05b691524d1fd044a2f2eefb706932fc98 (diff)
movenc: Allow interleaving samples when writing fragmented files
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ö <martin@martin.st>
Diffstat (limited to 'libavformat/movenc.c')
-rw-r--r--libavformat/movenc.c85
1 files changed, 78 insertions, 7 deletions
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 &&