From 30ac56a14d66eb25428b71c9211f401f818bd057 Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Fri, 1 Apr 2011 01:13:35 +0200 Subject: [PATCH 2/2] ffmpeg: review -dts_delta_threshold and -dts_delta_error options Review handling of -dts_delta_threshold and -dts_delta_error options, specify them as floating point expressed in seconds. Also, review and simplify logic. Adjust values for tests, since in some cases the new values does not trigger the correction logic. PR: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=8252 --- doc/ffmpeg.texi | 36 ++++++++++++++++--- fftools/ffmpeg.c | 72 ++++++++++++++++++++----------------- fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_demux.c | 3 ++ tests/fate/filter-audio.mak | 2 +- tests/fate/mpeg4.mak | 2 +- 6 files changed, 77 insertions(+), 40 deletions(-) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 67b3294256..ffffcdd1d7 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1823,12 +1823,38 @@ results, but increase memory use and latency. The default value is 10 seconds. -@item -dts_delta_threshold -Timestamp discontinuity delta threshold. +@item -dts_delta_threshold @var{threshold} +Timestamp discontinuity delta threshold, expressed as a floating point +number of seconds. + +The timestamp discontinuity correction enabled by this option is only +applied to input formats accepting timestamp discontinuity (for which +the @code{AV_FMT_DISCONT} flag is enabled), e.g. MPEG-TS and HLS, and +is automatically disabled when employing the @code{-copy_ts} option +(unless wrapping is detected). + +If a timestamp discontinuity is detected whose absolute value is +greater than @var{threshold}, ffmpeg will remove the discontinuity by +decreasing/increasing the current DTS and PTS by the corresponding +delta value. + +The default value is 10. + @item -dts_error_threshold @var{seconds} -Timestamp error delta threshold. This threshold use to discard crazy/damaged -timestamps and the default is 30 hours which is arbitrarily picked and quite -conservative. +Timestamp error delta threshold, expressed as a floating point number +of seconds. + +The timestamp correction enabled by this option is only applied to +input formats not accepting timestamp discontinuity (for which the +@code{AV_FMT_DISCONT} flag is not enabled). + +If a timestamp discontinuity is detected whose absolute value is +greater than @var{threshold}, ffmpeg will drop the PTS/DTS timestamp +value. + +The default value is @code{3600*30} (30 hours), which is arbitrarily +picked and quite conservative. + @item -muxdelay @var{seconds} (@emph{output}) Set the maximum demux-decode delay. @item -muxpreload @var{seconds} (@emph{output}) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index f722ae7632..cc58d98813 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3411,62 +3411,68 @@ 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); + av_log(NULL, AV_LOG_TRACE, + "ts discontinuity detection on stream #%d:%d pkt_dts:%s pkt_pts:%s next_dts:%s last_ts:%s fmt_discont:%d copy_ts:%d\n", + ist->file_index, ist->st->index, + av_ts2timestr(pkt->dts, &ist->st->time_base), av_ts2timestr(pkt->pts, &ist->st->time_base), + av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q), av_ts2timestr(ifile->last_ts, &AV_TIME_BASE_Q), + 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<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_ " ts:%s delta:%s > dts_error_threshold:%s\n", \ + av_ts2timestr(ts_, &ist->st->time_base), \ + av_ts2timestr(delta_, &AV_TIME_BASE_Q), \ + av_ts2timestr(ist->dts_error_threshold, &AV_TIME_BASE_Q)); \ + 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)) { + 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 && FFABS(delta) > ist->dts_delta_threshold) { 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); + "ts offset corrected ts_offset_discont:%s delta:%s > dts_delta_threshold:%s\n", + av_ts2timestr(ifile->ts_offset_discont, &AV_TIME_BASE_Q), + av_ts2timestr(delta, &AV_TIME_BASE_Q), + av_ts2timestr(ist->dts_delta_threshold, &AV_TIME_BASE_Q)); 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; - } - 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 5527dbe49b..14ad1a10ee 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -352,6 +352,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 71ce7d9a02..c7323c4adc 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)); diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index eff32b9f81..a0d8a78cb4 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -220,7 +220,7 @@ tests/data/hls-list-append.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f segment -segment_time 10 -map 0 -flags +bitexact -codec:a mp2fixed \ -segment_list $(TARGET_PATH)/$@ -y $(TARGET_PATH)/tests/data/hls-append-out-%03d.ts 2>/dev/null; \ $(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin \ - -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_time 10 -map 0 -flags +bitexact \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_time 10 -map 0 -flags +bitexact -dts_delta_threshold 1 \ -hls_flags append_list -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/hls-append-out-%03d.ts \ $(TARGET_PATH)/tests/data/hls-list-append.m3u8 2>/dev/null diff --git a/tests/fate/mpeg4.mak b/tests/fate/mpeg4.mak index 4cec21c547..ece5829aee 100644 --- a/tests/fate/mpeg4.mak +++ b/tests/fate/mpeg4.mak @@ -1,7 +1,7 @@ MPEG4_RESOLUTION_CHANGE = down-down down-up up-down up-up -fate-mpeg4-resolution-change-%: CMD = framemd5 -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/resize_$(@:fate-mpeg4-resolution-change-%=%).h263 -sws_flags +bitexact +fate-mpeg4-resolution-change-%: CMD = framemd5 -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/resize_$(@:fate-mpeg4-resolution-change-%=%).h263 -sws_flags +bitexact -dts_delta_threshold 1 FATE_MPEG4-$(call FRAMEMD5, M4V, MPEG4, SCALE_FILTER) := $(addprefix fate-mpeg4-resolution-change-, $(MPEG4_RESOLUTION_CHANGE)) -- 2.25.1