diff mbox series

[FFmpeg-devel,2/3] ffmpeg: review -dts_delta_threshold and -dts_delta_error options

Message ID 20230211162900.125018-1-stefasab@gmail.com
State New
Headers show
Series None | expand

Commit Message

Stefano Sabatini Feb. 11, 2023, 4:29 p.m. UTC
Review handling of -dts_delta_threshold and -dts_delta_error options
in order to simplify a bit the logic and improve logging.
---
 fftools/ffmpeg.c       | 101 +++++++++++++++++++++++++----------------
 fftools/ffmpeg.h       |   2 +
 fftools/ffmpeg_demux.c |   3 ++
 3 files changed, 68 insertions(+), 38 deletions(-)
diff mbox series

Patch

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 064ec6d4b3..22287f6a5e 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -3671,62 +3671,87 @@  static void decode_flush(InputFile *ifile)
 static void ts_discontinuity_detect(InputFile *ifile, InputStream *ist,
                                     AVPacket *pkt)
 {
-    const int fmt_is_discont = ifile->ctx->iformat->flags & AVFMT_TS_DISCONT;
+    const int fmt_is_discont = !!(ifile->ctx->iformat->flags & AVFMT_TS_DISCONT);
     int disable_discontinuity_correction = copy_ts;
     int64_t pkt_dts = av_rescale_q_rnd(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q,
                                        AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
+    char ist_desc[32];
+    snprintf(ist_desc, sizeof(ist_desc), "input stream #%d:%d", ist->file_index, ist->st->index);
+
+#define BASE_TS(ts_) av_ts2timestr(ts_, &AV_TIME_BASE_Q)
+#define PKT_TS(ts_) av_ts2timestr(ts_, &ist->st->time_base)
+
+    av_log(NULL, AV_LOG_TRACE,
+           "ts discontinuity detection on %s pkt_dts:%s pkt_pts:%s next_dts:%s last_ts:%s fmt_discont:%d copy_ts:%d\n",
+           ist_desc, PKT_TS(pkt->dts), PKT_TS(pkt->pts),
+           BASE_TS(ist->next_dts), BASE_TS(ifile->last_ts),
+           fmt_is_discont, copy_ts);
 
     if (copy_ts && ist->next_dts != AV_NOPTS_VALUE &&
         fmt_is_discont && ist->st->pts_wrap_bits < 60) {
         int64_t wrap_dts = av_rescale_q_rnd(pkt->dts + (1LL<<ist->st->pts_wrap_bits),
                                             ist->st->time_base, AV_TIME_BASE_Q,
                                             AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
-        if (FFABS(wrap_dts - ist->next_dts) < FFABS(pkt_dts - ist->next_dts)/10)
+        if (FFABS(wrap_dts - ist->next_dts) < FFABS(pkt_dts - ist->next_dts)/10) {
             disable_discontinuity_correction = 0;
+            av_log(NULL, AV_LOG_DEBUG,
+                   "wrapped ts detected in copy_ts, enabled discontinuity correction\n");
+        }
     }
 
-    if (ist->next_dts != AV_NOPTS_VALUE && !disable_discontinuity_correction) {
-        int64_t delta = pkt_dts - ist->next_dts;
+#define CHECK_INVALID_TS(delta_, ts_type_, ts_)                         \
+    if (FFABS(delta_) > ist->dts_error_threshold) {                     \
+        av_log(NULL, AV_LOG_WARNING,                                    \
+               "drop invalid " #ts_type_ ":%s on %s delta:%s > dts_error_threshold:%s on %s\n", \
+               PKT_TS(ts_), BASE_TS(delta), ist_desc, BASE_TS(ist->dts_error_threshold), ist_desc); \
+        ts_ = AV_NOPTS_VALUE;                                           \
+    }
+
+    if (!disable_discontinuity_correction) {
+        int64_t delta;
+
         if (fmt_is_discont) {
-            if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE ||
-                pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {
-                ifile->ts_offset_discont -= delta;
-                av_log(NULL, AV_LOG_DEBUG,
-                       "timestamp discontinuity for stream #%d:%d "
-                       "(id=%d, type=%s): %"PRId64", new offset= %"PRId64"\n",
-                       ist->file_index, ist->st->index, ist->st->id,
-                       av_get_media_type_string(ist->par->codec_type),
-                       delta, ifile->ts_offset_discont);
-                pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
-                if (pkt->pts != AV_NOPTS_VALUE)
-                    pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
-            }
-        } else {
-            if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) {
-                av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt->dts, ist->next_dts, pkt->stream_index);
-                pkt->dts = AV_NOPTS_VALUE;
+            delta =
+                ist->next_dts != AV_NOPTS_VALUE ? pkt_dts - ist->next_dts :
+                ifile->last_ts != AV_NOPTS_VALUE ? pkt_dts - ifile->last_ts :
+                AV_NOPTS_VALUE;
+
+            if (delta != AV_NOPTS_VALUE) {
+                char fix_delta = 0;
+                int64_t dts_limit = FFMAX(ist->pts, ist->dts) - AV_TIME_BASE/10;
+
+                if (FFABS(delta) > ist->dts_delta_threshold) {
+                    av_log(NULL, AV_LOG_DEBUG,
+                           "detected dts:%s delta:%s > dts_delta_threshold:%s on %s\n",
+                           BASE_TS(pkt_dts), BASE_TS(delta), BASE_TS(ist->dts_delta_threshold),
+                           ist_desc);
+                    fix_delta = 1;
+                } else if (ist->next_dts != AV_NOPTS_VALUE && pkt_dts < dts_limit) {
+                    av_log(NULL, AV_LOG_DEBUG, "detected dts:%s < dts_limit:%s on %s\n",
+                           BASE_TS(pkt_dts), BASE_TS(dts_limit), ist_desc);
+                    fix_delta = 1;
+                }
+
+                if (fix_delta) {
+                    ifile->ts_offset_discont -= delta;
+                    pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+                    if (pkt->pts != AV_NOPTS_VALUE)
+                        pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+                    av_log(NULL, AV_LOG_DEBUG,
+                           "ts delta:%s applied -> ts_offset_discont:%s dts:%s pts:%s on %s\n",
+                           BASE_TS(-delta), BASE_TS(ifile->ts_offset_discont),
+                           PKT_TS(pkt->dts), PKT_TS(pkt->pts), ist_desc);
+                }
             }
-            if (pkt->pts != AV_NOPTS_VALUE){
+        } else if (ist->next_dts != AV_NOPTS_VALUE) {
+            delta = pkt_dts - ist->next_dts;
+            CHECK_INVALID_TS(delta, dts, pkt->dts);
+            if (pkt->pts != AV_NOPTS_VALUE) {
                 int64_t pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
                 delta = pkt_pts - ist->next_dts;
-                if (FFABS(delta) > 1LL * dts_error_threshold * AV_TIME_BASE) {
-                    av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt->pts, ist->next_dts, pkt->stream_index);
-                    pkt->pts = AV_NOPTS_VALUE;
-                }
+                CHECK_INVALID_TS(delta, pts, pkt->pts);
             }
         }
-    } else if (ist->next_dts == AV_NOPTS_VALUE && !copy_ts &&
-               fmt_is_discont && ifile->last_ts != AV_NOPTS_VALUE) {
-        int64_t delta = pkt_dts - ifile->last_ts;
-        if (FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE) {
-            ifile->ts_offset_discont -= delta;
-            av_log(NULL, AV_LOG_DEBUG,
-                   "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
-                   delta, ifile->ts_offset_discont);
-            pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
-            if (pkt->pts != AV_NOPTS_VALUE)
-                pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
-        }
     }
 
     ifile->last_ts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index f1412f6446..686d38c934 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -368,6 +368,8 @@  typedef struct InputStream {
     int64_t       next_pts;  ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
     int64_t       pts;       ///< current pts of the decoded frame  (in AV_TIME_BASE units)
     int           wrap_correction_done;
+    int64_t       dts_delta_threshold; ///< dts_delta_threshold value rescaled to AV_TIME_BASE units
+    int64_t       dts_error_threshold; ///< dts_error_threshold value rescaled to AV_TIME_BASE units
 
     // the value of AVCodecParserContext.repeat_pict from the AVStream parser
     // for the last packet returned from ifile_get_packet()
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 98da0678f5..18f8ed8946 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -736,6 +736,9 @@  static void add_input_streams(const OptionsContext *o, Demuxer *d)
         ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
         ist->prev_pkt_pts = AV_NOPTS_VALUE;
 
+        ist->dts_delta_threshold = 1LL * dts_delta_threshold * AV_TIME_BASE;
+        ist->dts_error_threshold = 1LL * dts_error_threshold * AV_TIME_BASE;
+
         ist->dec_ctx = avcodec_alloc_context3(ist->dec);
         if (!ist->dec_ctx)
             report_and_exit(AVERROR(ENOMEM));