summaryrefslogtreecommitdiff
path: root/libavformat/movenc.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2014-10-05 23:51:47 +0300
committerMartin Storsjö <martin@martin.st>2014-11-17 16:16:46 +0200
commit2ded57371abead879bcee56da5131e5fac0d17ef (patch)
tree98b74cd919aca09761035d812d0aeeefbf054105 /libavformat/movenc.c
parent2d9d6afb8d2f284f5e620ecc19f643d5cd3facb8 (diff)
movenc: Add support for writing sidx atoms for DASH segments
A flag "dash" is added, which enables the necessary flags for creating DASH compatible fragments. When this is enabled, one sidx atom is written for each track before every moof atom. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/movenc.c')
-rw-r--r--libavformat/movenc.c82
1 files changed, 80 insertions, 2 deletions
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 8d378c4357..76439678d1 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -59,6 +59,7 @@ static const AVOption options[] = {
{ "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
{ "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
@@ -2675,7 +2676,78 @@ static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
return update_size(pb, pos);
}
-static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
+static int mov_write_sidx_tag(AVIOContext *pb,
+ MOVTrack *track, int ref_size, int total_sidx_size)
+{
+ int64_t pos = avio_tell(pb), offset_pos, end_pos;
+ int64_t presentation_time = track->start_dts + track->frag_start +
+ track->cluster[0].cts;
+ int64_t duration = track->start_dts + track->track_duration -
+ track->cluster[0].dts;
+ int64_t offset;
+ int starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
+
+ // pts<0 should be cut away using edts
+ if (presentation_time < 0)
+ presentation_time = 0;
+
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "sidx");
+ avio_w8(pb, 1); /* version */
+ avio_wb24(pb, 0);
+ avio_wb32(pb, track->track_id); /* reference_ID */
+ avio_wb32(pb, track->timescale); /* timescale */
+ avio_wb64(pb, presentation_time); /* earliest_presentation_time */
+ offset_pos = avio_tell(pb);
+ avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
+ avio_wb16(pb, 0); /* reserved */
+ avio_wb16(pb, 1); /* reference_count */
+ avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
+ avio_wb32(pb, duration); /* subsegment_duration */
+ avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
+
+ end_pos = avio_tell(pb);
+ offset = pos + total_sidx_size - end_pos;
+ avio_seek(pb, offset_pos, SEEK_SET);
+ avio_wb64(pb, offset);
+ avio_seek(pb, end_pos, SEEK_SET);
+ return update_size(pb, pos);
+}
+
+static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
+ int tracks, int ref_size)
+{
+ int i, round, ret;
+ AVIOContext *avio_buf;
+ int total_size = 0;
+ for (round = 0; round < 2; round++) {
+ // First run one round to calculate the total size of all
+ // sidx atoms.
+ // This would be much simpler if we'd only write one sidx
+ // atom, for the first track in the moof.
+ if (round == 0) {
+ if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
+ return ret;
+ } else {
+ avio_buf = pb;
+ }
+ for (i = 0; i < mov->nb_streams; i++) {
+ MOVTrack *track = &mov->tracks[i];
+ if (tracks >= 0 && i != tracks)
+ continue;
+ if (!track->entry)
+ continue;
+ total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
+ total_size);
+ }
+ if (round == 0)
+ total_size = ffio_close_null_buf(avio_buf);
+ }
+ return 0;
+}
+
+static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
+ int64_t mdat_size)
{
AVIOContext *avio_buf;
int ret, moof_size;
@@ -2685,6 +2757,9 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
moof_size = ffio_close_null_buf(avio_buf);
+ if (mov->flags & FF_MOV_FLAG_DASH)
+ mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
+
if ((ret = mov_add_tfra_entries(pb, mov, tracks)) < 0)
return ret;
@@ -3054,7 +3129,7 @@ static int mov_flush_fragment(AVFormatContext *s)
if (write_moof) {
avio_flush(s->pb);
- mov_write_moof_tag(s->pb, mov, moof_tracks);
+ mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
mov->fragments++;
avio_wb32(s->pb, mdat_size + 8);
@@ -3504,6 +3579,9 @@ static int mov_write_header(AVFormatContext *s)
if (mov->mode == MODE_ISM)
mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
FF_MOV_FLAG_FRAGMENT;
+ if (mov->flags & FF_MOV_FLAG_DASH)
+ mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
+ FF_MOV_FLAG_DEFAULT_BASE_MOOF;
/* faststart: moov at the beginning of the file, if supported */
if (mov->flags & FF_MOV_FLAG_FASTSTART) {