diff mbox series

[FFmpeg-devel,v2,5/6] avformat/mux: Peek into the muxing queue for avoid_negative_ts

Message ID AM7PR03MB6660641EF5BDC44969B6260C8F599@AM7PR03MB6660.eurprd03.prod.outlook.com
State Accepted
Commit c24ee7c275b6374b4b6ef4030e93d416a9c2265f
Headers show
Series [FFmpeg-devel,v2,1/6] avformat/mux: Remove assert based on faulty assumptions | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished
andriy/make_aarch64_jetson success Make finished
andriy/make_fate_aarch64_jetson success Make fate finished

Commit Message

Andreas Rheinhardt Jan. 19, 2022, 9:29 p.m. UTC
Peeking into the muxing queue can improve the estimate of
the lowest timestamp needed for avoid_negative_ts in case
the lowest timestamp is in a packet other than the first packet
to be muxed.
This fixes tickets #4536 and #5784 as well as the output from
the matroska-avoid-negative-ts FATE-test.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavformat/avformat.h                    |  2 +-
 libavformat/mux.c                         | 21 +++++++++++++++++++--
 tests/fate/matroska.mak                   |  2 --
 tests/ref/fate/matroska-avoid-negative-ts |  2 +-
 4 files changed, 21 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index cd253fb28e..b4b8075ae6 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1527,7 +1527,7 @@  typedef struct AVFormatContext {
     /**
      * Avoid negative timestamps during muxing.
      * Any value of the AVFMT_AVOID_NEG_TS_* constants.
-     * Note, this only works when using av_interleaved_write_frame. (interleave_packet_per_dts is in use)
+     * Note, this works better when using av_interleaved_write_frame().
      * - muxing: Set by user
      * - demuxing: unused
      */
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 0810b674a7..53eb56f0af 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -655,16 +655,33 @@  static void handle_avoid_negative_ts(FFFormatContext *si, FFStream *sti,
     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;
+        AVRational tb = sti->pub.time_base;
 
         if (ts == AV_NOPTS_VALUE)
             return;
+
+        /* Peek into the muxing queue to improve our estimate
+         * of the lowest timestamp if av_interleaved_write_frame() is used. */
+        for (const PacketListEntry *pktl = si->packet_buffer.head;
+             pktl; pktl = pktl->next) {
+            AVRational cmp_tb = s->streams[pktl->pkt.stream_index]->time_base;
+            int64_t cmp_ts = use_pts ? pktl->pkt.pts : pktl->pkt.dts;
+            if (cmp_ts == AV_NOPTS_VALUE)
+                continue;
+            if (s->output_ts_offset)
+                cmp_ts += av_rescale_q(s->output_ts_offset, AV_TIME_BASE_Q, cmp_tb);
+            if (av_compare_ts(cmp_ts, cmp_tb, ts, tb) < 0) {
+                ts = cmp_ts;
+                tb = cmp_tb;
+            }
+        }
+
         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,
+                sti2->mux_ts_offset = av_rescale_q_rnd(-ts, tb,
                                                        st2->time_base,
                                                        AV_ROUND_UP);
             }
diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak
index da1fdbd5ea..784b55f6e0 100644
--- a/tests/fate/matroska.mak
+++ b/tests/fate/matroska.mak
@@ -94,8 +94,6 @@  fate-matroska-dovi-write-config7: CMD = transcode mov $(TARGET_SAMPLES)/mov/dovi
 # 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 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 1b9b2f2786..02790a3985 100644
--- a/tests/ref/fate/matroska-avoid-negative-ts
+++ b/tests/ref/fate/matroska-avoid-negative-ts
@@ -1,4 +1,4 @@ 
-90cf5a330659140d47ec11208f525908 *tests/data/fate/matroska-avoid-negative-ts.matroska
+804842437b2be0a1604ce33c6b08c800 *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