summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/internal.h23
-rw-r--r--libavformat/mux.c111
-rw-r--r--libavformat/options.c1
-rw-r--r--tests/fate/matroska.mak4
-rw-r--r--tests/ref/fate/matroska-avoid-negative-ts6
5 files changed, 81 insertions, 64 deletions
diff --git a/libavformat/internal.h b/libavformat/internal.h
index bffb8e66ff..f24c68703f 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -83,6 +83,17 @@ typedef struct FFFormatContext {
int nb_interleaved_streams;
/**
+ * Whether the timestamp shift offset has already been determined.
+ * -1: disabled, 0: not yet determined, 1: determined.
+ */
+ enum {
+ AVOID_NEGATIVE_TS_DISABLED = -1,
+ AVOID_NEGATIVE_TS_UNKNOWN = 0,
+ AVOID_NEGATIVE_TS_KNOWN = 1,
+ } avoid_negative_ts_status;
+#define AVOID_NEGATIVE_TS_ENABLED(status) ((status) >= 0)
+
+ /**
* The interleavement function in use. Always set for muxers.
*/
int (*interleave_packet)(struct AVFormatContext *s, AVPacket *pkt,
@@ -135,18 +146,6 @@ typedef struct FFFormatContext {
*/
int raw_packet_buffer_size;
- /**
- * Offset to remap timestamps to be non-negative.
- * Expressed in timebase units.
- * @see AVStream.mux_ts_offset
- */
- int64_t offset;
-
- /**
- * Timebase for the timestamp offset.
- */
- AVRational offset_timebase;
-
#if FF_API_COMPUTE_PKT_FIELDS2
int missing_ts_warning;
#endif
diff --git a/libavformat/mux.c b/libavformat/mux.c
index a1917878a5..0810b674a7 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -388,6 +388,8 @@ fail:
static int init_pts(AVFormatContext *s)
{
+ FFFormatContext *const si = ffformatcontext(s);
+
/* init PTS generation */
for (unsigned i = 0; i < s->nb_streams; i++) {
AVStream *const st = s->streams[i];
@@ -418,13 +420,16 @@ static int init_pts(AVFormatContext *s)
}
}
+ si->avoid_negative_ts_status = AVOID_NEGATIVE_TS_UNKNOWN;
if (s->avoid_negative_ts < 0) {
av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_DISABLED;
+ si->avoid_negative_ts_status = AVOID_NEGATIVE_TS_DISABLED;
} else
s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE;
- }
+ } else if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_DISABLED)
+ si->avoid_negative_ts_status = AVOID_NEGATIVE_TS_DISABLED;
return 0;
}
@@ -638,6 +643,64 @@ static void guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
}
}
+static void handle_avoid_negative_ts(FFFormatContext *si, FFStream *sti,
+ AVPacket *pkt)
+{
+ AVFormatContext *const s = &si->pub;
+ int64_t offset;
+
+ if (!AVOID_NEGATIVE_TS_ENABLED(si->avoid_negative_ts_status))
+ return;
+
+ if (si->avoid_negative_ts_status == AVOID_NEGATIVE_TS_UNKNOWN) {
+ int use_pts = si->avoid_negative_ts_use_pts;
+ int64_t ts = use_pts ? pkt->pts : pkt->dts;
+
+ if (ts == AV_NOPTS_VALUE)
+ return;
+ if (ts < 0 ||
+ ts > 0 && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
+ for (unsigned i = 0; i < s->nb_streams; i++) {
+ AVStream *const st2 = s->streams[i];
+ FFStream *const sti2 = ffstream(st2);
+ sti2->mux_ts_offset = av_rescale_q_rnd(-ts,
+ sti->pub.time_base,
+ st2->time_base,
+ AV_ROUND_UP);
+ }
+ }
+ si->avoid_negative_ts_status = AVOID_NEGATIVE_TS_KNOWN;
+ }
+
+ offset = sti->mux_ts_offset;
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+
+ if (si->avoid_negative_ts_use_pts) {
+ if (pkt->pts != AV_NOPTS_VALUE && pkt->pts < 0) {
+ av_log(s, AV_LOG_WARNING, "failed to avoid negative "
+ "pts %s in stream %d.\n"
+ "Try -avoid_negative_ts 1 as a possible workaround.\n",
+ av_ts2str(pkt->pts),
+ pkt->stream_index
+ );
+ }
+ } else {
+ if (pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) {
+ av_log(s, AV_LOG_WARNING,
+ "Packets poorly interleaved, failed to avoid negative "
+ "timestamp %s in stream %d.\n"
+ "Try -max_interleave_delta 0 as a possible workaround.\n",
+ av_ts2str(pkt->dts),
+ pkt->stream_index
+ );
+ }
+ }
+}
+
/**
* Shift timestamps and call muxer; the original pts/dts are not kept.
*
@@ -663,51 +726,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts += offset;
}
-
- if (s->avoid_negative_ts > 0) {
- int64_t offset = sti->mux_ts_offset;
- int64_t ts = si->avoid_negative_ts_use_pts ? pkt->pts : pkt->dts;
-
- if (si->offset == AV_NOPTS_VALUE && ts != AV_NOPTS_VALUE &&
- (ts < 0 || s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)) {
- si->offset = -ts;
- si->offset_timebase = st->time_base;
- }
-
- if (si->offset != AV_NOPTS_VALUE && !offset) {
- offset = sti->mux_ts_offset =
- av_rescale_q_rnd(si->offset,
- si->offset_timebase,
- st->time_base,
- AV_ROUND_UP);
- }
-
- if (pkt->dts != AV_NOPTS_VALUE)
- pkt->dts += offset;
- if (pkt->pts != AV_NOPTS_VALUE)
- pkt->pts += offset;
-
- if (si->avoid_negative_ts_use_pts) {
- if (pkt->pts != AV_NOPTS_VALUE && pkt->pts < 0) {
- av_log(s, AV_LOG_WARNING, "failed to avoid negative "
- "pts %s in stream %d.\n"
- "Try -avoid_negative_ts 1 as a possible workaround.\n",
- av_ts2str(pkt->pts),
- pkt->stream_index
- );
- }
- } else {
- if (pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) {
- av_log(s, AV_LOG_WARNING,
- "Packets poorly interleaved, failed to avoid negative "
- "timestamp %s in stream %d.\n"
- "Try -max_interleave_delta 0 as a possible workaround.\n",
- av_ts2str(pkt->dts),
- pkt->stream_index
- );
- }
- }
- }
+ handle_avoid_negative_ts(si, sti, pkt);
if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
AVFrame **frame = (AVFrame **)pkt->data;
diff --git a/libavformat/options.c b/libavformat/options.c
index 1634388acb..2d55d3ad6e 100644
--- a/libavformat/options.c
+++ b/libavformat/options.c
@@ -174,7 +174,6 @@ AVFormatContext *avformat_alloc_context(void)
return NULL;
}
- si->offset = AV_NOPTS_VALUE;
si->shortest_end = AV_NOPTS_VALUE;
return s;
diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak
index 1a45e8c022..9d47ade08f 100644
--- a/tests/fate/matroska.mak
+++ b/tests/fate/matroska.mak
@@ -101,8 +101,8 @@ fate-matroska-dovi-write-config8: CMD = transcode mov $(TARGET_SAMPLES)/hevc/dv8
# the first packet (with the overall lowest dts) is a video packet,
# whereas an audio packet to be muxed later has the overall lowest pts
# which happens to be negative and therefore needs to be shifted.
-# This is currently buggy (the timestamps of the video frames muxed
-# before the first audio frame are not shifted).
+# This is currently buggy (the timestamps are not shifted properly:
+# the first audio packet has negative pts).
# (-ss 1.09 ensures that a video frame has the lowest dts of all packets;
# yet there is an audio packet with the overall lowest pts. output_ts_offset
# makes the pts of the audio packet, but not the leading video packet negative
diff --git a/tests/ref/fate/matroska-avoid-negative-ts b/tests/ref/fate/matroska-avoid-negative-ts
index a687c8f63c..1b9b2f2786 100644
--- a/tests/ref/fate/matroska-avoid-negative-ts
+++ b/tests/ref/fate/matroska-avoid-negative-ts
@@ -1,4 +1,4 @@
-3349536550047c5c553215003ba2acb7 *tests/data/fate/matroska-avoid-negative-ts.matroska
+90cf5a330659140d47ec11208f525908 *tests/data/fate/matroska-avoid-negative-ts.matroska
973070 tests/data/fate/matroska-avoid-negative-ts.matroska
#extradata 0: 22, 0x2885037c
#tb 0: 1/1000
@@ -12,11 +12,11 @@
#sample_rate 1: 44100
#channel_layout 1: 4
#channel_layout_name 1: mono
-0, -37, 24, 40, 9156, 0xe5bd034a, S=1, 40
+0, -37, 43, 40, 9156, 0xe5bd034a, S=1, 40
1, 0, 0, 26, 417, 0x7198c15e
0, 3, 3, 40, 1740, 0x29ac4480, F=0x0
-0, 24, 123, 40, 3672, 0x98652013, F=0x0
1, 26, 26, 26, 417, 0x3c67c32d
+0, 43, 123, 40, 3672, 0x98652013, F=0x0
1, 52, 52, 26, 417, 0x8c24b1ca
1, 78, 78, 26, 417, 0x6ee576b7
0, 83, 83, 40, 2532, 0xa2c42769, F=0x0