1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

movenc: Add an option for enabling negative CTS offsets

This reduces the need for an edit list; streams that start with
e.g. dts=-1, pts=0 can be encoded as dts=0, pts=0 (which is valid
in mov/mp4) by shifting the dts values of all packets forward.
This avoids the need for edit lists for such streams (while they
still are needed for audio streams with encoder delay).

This eases conformance with the DASH-IF interoperability guidelines.

Signed-off-by: Martin Storsjö <martin@martin.st>
This commit is contained in:
Martin Storsjö 2016-04-07 15:45:37 +03:00
parent d05c9cde0e
commit c380a0d7f7
2 changed files with 26 additions and 4 deletions

View File

@ -62,6 +62,7 @@ static const AVOption options[] = {
{ "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, 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},
@ -1163,8 +1164,9 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
return update_size(pb, pos);
}
static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track)
static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
{
MOVMuxContext *mov = s->priv_data;
MOVStts *ctts_entries;
uint32_t entries = 0;
uint32_t atom_size;
@ -1188,7 +1190,11 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track)
atom_size = 16 + (entries * 8);
avio_wb32(pb, atom_size); /* size */
ffio_wfourcc(pb, "ctts");
avio_wb32(pb, 0); /* version & flags */
if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
avio_w8(pb, 1); /* version */
else
avio_w8(pb, 0); /* version */
avio_wb24(pb, 0); /* flags */
avio_wb32(pb, entries); /* entry count */
for (i = 0; i < entries; i++) {
avio_wb32(pb, ctts_entries[i].count);
@ -1273,7 +1279,7 @@ static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
track->flags & MOV_TRACK_CTTS && track->entry)
mov_write_ctts_tag(pb, track);
mov_write_ctts_tag(s, pb, track);
mov_write_stsc_tag(pb, track);
mov_write_stsz_tag(pb, track);
mov_write_stco_tag(pb, track);
@ -2594,7 +2600,10 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb32(pb, 0); /* size placeholder */
ffio_wfourcc(pb, "trun");
avio_w8(pb, 0); /* version */
if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
avio_w8(pb, 1); /* version */
else
avio_w8(pb, 0); /* version */
avio_wb24(pb, flags);
avio_wb32(pb, end - first); /* sample count */
@ -3040,6 +3049,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
ffio_wfourcc(pb, "MSNV");
else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
ffio_wfourcc(pb, "iso4");
else if (mov->mode == MODE_MP4)
ffio_wfourcc(pb, "isom");
else if (mov->mode == MODE_IPOD)
@ -3288,6 +3299,8 @@ static int mov_flush_fragment(AVFormatContext *s, int force)
if (!track->end_reliable) {
AVPacket pkt;
if (!ff_interleaved_peek(s, i, &pkt, 1)) {
if (track->dts_shift != AV_NOPTS_VALUE)
pkt.dts += track->dts_shift;
track->track_duration = pkt.dts - track->start_dts;
if (pkt.pts != AV_NOPTS_VALUE)
track->end_pts = pkt.pts;
@ -3729,6 +3742,12 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
}
if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
if (trk->dts_shift == AV_NOPTS_VALUE)
trk->dts_shift = pkt->pts - pkt->dts;
pkt->dts += trk->dts_shift;
}
if (!pkt->size) {
if (trk->start_dts == AV_NOPTS_VALUE && trk->frag_discont) {
trk->start_dts = pkt->dts;
@ -4095,6 +4114,7 @@ static int mov_write_header(AVFormatContext *s)
track->start_dts = AV_NOPTS_VALUE;
track->start_cts = AV_NOPTS_VALUE;
track->end_pts = AV_NOPTS_VALUE;
track->dts_shift = AV_NOPTS_VALUE;
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||

View File

@ -107,6 +107,7 @@ typedef struct MOVTrack {
int64_t start_cts;
int64_t end_pts;
int end_reliable;
int64_t dts_shift;
int hint_track; ///< the track that hints this track, -1 if no hint track is set
int src_track; ///< the track that this hint track describes
@ -195,6 +196,7 @@ typedef struct MOVMuxContext {
#define FF_MOV_FLAG_DELAY_MOOV (1 << 13)
#define FF_MOV_FLAG_GLOBAL_SIDX (1 << 14)
#define FF_MOV_FLAG_SKIP_TRAILER (1 << 15)
#define FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS (1 << 16)
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);