From 95931bd9a797a335efa977941ae064cd32b7e365 Mon Sep 17 00:00:00 2001 From: devindengloom <94390260+devindengloom@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:16:57 -0800 Subject: [PATCH] Patch force dts monotonicity branch (#6) * patch for force_dts_monotonicity option to enforce continuity timestamps * update travis --- .travis.yml | 4 +++- fftools/ffmpeg.c | 53 +++++++++++++++++++++++++++++++++++++++----- fftools/ffmpeg.h | 7 ++++++ fftools/ffmpeg_opt.c | 8 +++++++ 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 784b7bdf73d8c..75fff481a073a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: c sudo: false os: - linux - - osx addons: apt: packages: @@ -12,6 +11,9 @@ compiler: - clang - gcc matrix: + include: + - os: osx + osx_image: xcode13.2 exclude: - os: osx compiler: gcc diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 2e9448ea2ba9c..41b845a740ab9 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -4398,10 +4398,14 @@ static int process_input(int file_index) pkt.dts *= ist->ts_scale; pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); - if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || - ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && - pkt_dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts - && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) { + if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && + pkt_dts != AV_NOPTS_VALUE && + ist->next_dts == AV_NOPTS_VALUE && + !copy_ts && + (is->iformat->flags & AVFMT_TS_DISCONT) && + ifile->last_ts != AV_NOPTS_VALUE && + !force_dts_monotonicity + ) { int64_t delta = pkt_dts - ifile->last_ts; if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE || delta > 1LL*dts_delta_threshold*AV_TIME_BASE){ @@ -4439,7 +4443,9 @@ static int process_input(int file_index) if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && - !disable_discontinuity_correction) { + !disable_discontinuity_correction && + !force_dts_monotonicity + ) { int64_t delta = pkt_dts - ist->next_dts; if (is->iformat->flags & AVFMT_TS_DISCONT) { if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE || @@ -4477,6 +4483,43 @@ static int process_input(int file_index) if (pkt.dts != AV_NOPTS_VALUE) ifile->last_ts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q); + if (force_dts_monotonicity && + (pkt.pts != AV_NOPTS_VALUE || pkt.dts != AV_NOPTS_VALUE) && + (ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) + ) { + int64_t ff_pts_error = 0; + int64_t ff_dts_error = 0; + int64_t ff_dts_threshold = av_rescale_q(dts_monotonicity_threshold, AV_TIME_BASE_Q, ist->st->time_base); + + // adjust the incoming packet by the accumulated monotonicity error + if (pkt.pts != AV_NOPTS_VALUE) { + pkt.pts += ifile->ff_timestamp_monotonicity_offset; + if (ist->next_pts != AV_NOPTS_VALUE) { + ff_pts_error = av_rescale_q(ist->next_pts, AV_TIME_BASE_Q, ist->st->time_base) - pkt.pts; + } + } + if (pkt.dts != AV_NOPTS_VALUE) { + pkt.dts += ifile->ff_timestamp_monotonicity_offset; + if (ist->next_dts != AV_NOPTS_VALUE) { + ff_dts_error = av_rescale_q(ist->next_dts, AV_TIME_BASE_Q, ist->st->time_base) - pkt.dts; + } + } + + if(ff_dts_error > 0 || ff_dts_error < (-ff_dts_threshold) || ff_pts_error < (-ff_dts_threshold)) { + if(pkt.dts == AV_NOPTS_VALUE /* || ist->next_dts != AV_NOPTS_VALUE */ ) { + pkt.pts += ff_pts_error; + ifile->ff_timestamp_monotonicity_offset += ff_pts_error; + av_log(is, AV_LOG_INFO, "Incoming PTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_pts_error, ifile->ff_timestamp_monotonicity_offset); + } + else { + pkt.pts += ff_dts_error; + pkt.dts += ff_dts_error; + ifile->ff_timestamp_monotonicity_offset += ff_dts_error; + av_log(is, AV_LOG_INFO, "Incoming DTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_dts_error, ifile->ff_timestamp_monotonicity_offset); + } + } + } + if (debug_ts) { av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n", ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type), diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 828cb2a4ff92d..85d0572a51968 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -419,6 +419,10 @@ typedef struct InputFile { int joined; /* the thread has been joined */ int thread_queue_size; /* maximum number of queued packets */ #endif + + // A value added to inbound timestamps to prevent them from going "backward" in cases such as HLS discontinuities + int64_t ff_timestamp_monotonicity_offset; + } InputFile; enum forced_keyframes_const { @@ -584,6 +588,9 @@ extern float audio_drift_threshold; extern float dts_delta_threshold; extern float dts_error_threshold; +extern int dts_monotonicity_threshold; +extern int force_dts_monotonicity; + extern int audio_volume; extern int audio_sync_method; extern int video_sync_method; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 2eb4e1c973fbc..2a85c0c5f4662 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -148,6 +148,9 @@ float audio_drift_threshold = 0.1; float dts_delta_threshold = 10; float dts_error_threshold = 3600*30; +int dts_monotonicity_threshold = AV_TIME_BASE; +int force_dts_monotonicity = 0; + int audio_volume = 256; int audio_sync_method = 0; int video_sync_method = VSYNC_AUTO; @@ -1262,6 +1265,7 @@ static int open_input_file(OptionsContext *o, const char *filename) f->recording_time = o->recording_time; f->input_ts_offset = o->input_ts_offset; f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp); + f->ff_timestamp_monotonicity_offset = 0; f->nb_streams = ic->nb_streams; f->rate_emu = o->rate_emu; f->accurate_seek = o->accurate_seek; @@ -3499,6 +3503,10 @@ const OptionDef options[] = { { "apad", OPT_STRING | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(apad) }, "audio pad", "" }, + { "force_dts_monotonicity", OPT_BOOL | OPT_EXPERT, { &force_dts_monotonicity }, + "correct dts monotonicity errors" }, + { "dts_monotonicity_threshold", HAS_ARG | OPT_INT | OPT_EXPERT,{ &dts_monotonicity_threshold }, + "dts correction threshold for forward jumps", "microseconds" }, { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold }, "timestamp discontinuity delta threshold", "threshold" }, { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_error_threshold },