Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Gyan Doshi <ffmpeg@gyani.pro>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH] ffmpeg_demux: add option readrate_catchup
Date: Sun, 23 Feb 2025 13:06:07 +0530
Message-ID: <644aecdc-b230-4883-af13-91bca2b3878a@gyani.pro> (raw)
In-Reply-To: <20250218094649.6619-1-ffmpeg@gyani.pro>



On 2025-02-18 03:16 pm, Gyan Doshi wrote:
> At present, if reading from a readrate-limited input is stalled,
> then upon resumption, ffmpeg will read the input without any
> throttle till the average readrate matches the specified readrate.
>
> This new option allows to set a speed limit when reading is resumed
> until the average readrate matches the primary readrate.
>
> Fixes #11469

Plan to push tomorrow.

Regards,
Gyan


> ---
>   doc/ffmpeg.texi        |  5 ++++
>   fftools/ffmpeg.h       |  1 +
>   fftools/ffmpeg_demux.c | 62 ++++++++++++++++++++++++++++++++++++------
>   fftools/ffmpeg_opt.c   |  3 ++
>   4 files changed, 63 insertions(+), 8 deletions(-)
>
> diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
> index da6549f043..fca220a334 100644
> --- a/doc/ffmpeg.texi
> +++ b/doc/ffmpeg.texi
> @@ -2325,6 +2325,11 @@ Read input at native frame rate. This is equivalent to setting @code{-readrate 1
>   @item -readrate_initial_burst @var{seconds}
>   Set an initial read burst time, in seconds, after which @option{-re/-readrate}
>   will be enforced.
> +@item -readrate_catchup @var{speed} (@emph{input})
> +If either the input or output is blocked leading to actual read speed falling behind the
> +specified readrate, then this rate takes effect till the input catches up with the
> +specified readrate. Must not be lower than the primary readrate.
> +
>   @item -vsync @var{parameter} (@emph{global})
>   @itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
>   Set video sync method / framerate mode. vsync is applied to all output video streams
> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> index 9439be0f41..c37a085029 100644
> --- a/fftools/ffmpeg.h
> +++ b/fftools/ffmpeg.h
> @@ -163,6 +163,7 @@ typedef struct OptionsContext {
>       int loop;
>       int rate_emu;
>       float readrate;
> +    float readrate_catchup;
>       double readrate_initial_burst;
>       int accurate_seek;
>       int thread_queue_size;
> diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
> index 5ff75eed1a..4a4a134afa 100644
> --- a/fftools/ffmpeg_demux.c
> +++ b/fftools/ffmpeg_demux.c
> @@ -94,6 +94,12 @@ typedef struct DemuxStream {
>       uint64_t                 nb_packets;
>       // combined size of all the packets read
>       uint64_t                 data_size;
> +    // latest wallclock time at which packet reading resumed after a stall - used for readrate
> +    int64_t                  resume_wc;
> +    // timestamp of first packet sent after the latest stall - used for readrate
> +    int64_t                  resume_pts;
> +    // measure of how far behind packet reading is against spceified readrate
> +    int64_t                  lag;
>   } DemuxStream;
>   
>   typedef struct Demuxer {
> @@ -127,6 +133,7 @@ typedef struct Demuxer {
>   
>       float                 readrate;
>       double                readrate_initial_burst;
> +    float                 readrate_catchup;
>   
>       Scheduler            *sch;
>   
> @@ -495,16 +502,42 @@ static void readrate_sleep(Demuxer *d)
>                             (f->start_time_effective != AV_NOPTS_VALUE ? f->start_time_effective * !start_at_zero : 0) +
>                             (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0)
>                            );
> -    int64_t burst_until = AV_TIME_BASE * d->readrate_initial_burst;
> +    int64_t initial_burst = AV_TIME_BASE * d->readrate_initial_burst;
> +    int resume_warn;
> +
>       for (int i = 0; i < f->nb_streams; i++) {
>           InputStream *ist = f->streams[i];
>           DemuxStream  *ds = ds_from_ist(ist);
> -        int64_t stream_ts_offset, pts, now;
> +        int64_t stream_ts_offset, pts, now, wc_elapsed, elapsed, lag, max_pts, limit_pts;
> +
> +        if (ds->discard) continue;
> +
>           stream_ts_offset = FFMAX(ds->first_dts != AV_NOPTS_VALUE ? ds->first_dts : 0, file_start);
>           pts = av_rescale(ds->dts, 1000000, AV_TIME_BASE);
> -        now = (av_gettime_relative() - d->wallclock_start) * d->readrate + stream_ts_offset;
> -        if (pts - burst_until > now)
> -            av_usleep(pts - burst_until - now);
> +        now = av_gettime_relative();
> +        wc_elapsed = now - d->wallclock_start;
> +        max_pts = stream_ts_offset + initial_burst + wc_elapsed * d->readrate;
> +        lag = FFMAX(max_pts - pts, 0);
> +        if ( (!ds->lag && lag > 0.3 * AV_TIME_BASE) || ( lag > ds->lag + 0.3 * AV_TIME_BASE) ) {
> +            ds->lag = lag;
> +            ds->resume_wc = now;
> +            ds->resume_pts = pts;
> +            av_log_once(ds, AV_LOG_WARNING, AV_LOG_DEBUG, &resume_warn,
> +                        "Resumed reading at pts %0.3f with rate %0.3f after a lag of %0.3fs\n",
> +                        (float)pts/AV_TIME_BASE, d->readrate_catchup, (float)lag/AV_TIME_BASE);
> +        }
> +        if (ds->lag && !lag)
> +            ds->lag = ds->resume_wc = ds->resume_pts = 0;
> +        if (ds->resume_wc) {
> +            elapsed = now - ds->resume_wc;
> +            limit_pts = ds->resume_pts + elapsed * d->readrate_catchup;
> +        } else {
> +            elapsed = wc_elapsed;
> +            limit_pts = max_pts;
> +        }
> +
> +        if (pts > limit_pts)
> +            av_usleep(pts - limit_pts);
>       }
>   }
>   
> @@ -1859,9 +1892,22 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
>                      d->readrate_initial_burst);
>               return AVERROR(EINVAL);
>           }
> -    } else if (o->readrate_initial_burst) {
> -        av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored "
> -               "since neither -readrate nor -re were given\n");
> +        d->readrate_catchup = o->readrate_catchup ? o->readrate_catchup : d->readrate;
> +        if (d->readrate_catchup < d->readrate) {
> +            av_log(d, AV_LOG_ERROR,
> +                   "Option -readrate_catchup is %0.3f; it must be at least equal to %0.3f.\n",
> +                   d->readrate_catchup, d->readrate);
> +            return AVERROR(EINVAL);
> +        }
> +    } else {
> +        if (o->readrate_initial_burst) {
> +            av_log(d, AV_LOG_WARNING, "Option -readrate_initial_burst ignored "
> +                   "since neither -readrate nor -re were given\n");
> +        }
> +        if (o->readrate_catchup) {
> +            av_log(d, AV_LOG_WARNING, "Option -readrate_catchup ignored "
> +                   "since neither -readrate nor -re were given\n");
> +        }
>       }
>   
>       /* Add all the streams from the given input file to the demuxer */
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> index 3c0c682594..27a9fc9e42 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -1639,6 +1639,9 @@ const OptionDef options[] = {
>       { "readrate_initial_burst", OPT_TYPE_DOUBLE, OPT_OFFSET | OPT_EXPERT | OPT_INPUT,
>           { .off = OFFSET(readrate_initial_burst) },
>           "The initial amount of input to burst read before imposing any readrate", "seconds" },
> +    { "readrate_catchup",       OPT_TYPE_FLOAT, OPT_OFFSET | OPT_EXPERT | OPT_INPUT,
> +        { .off = OFFSET(readrate_catchup) },
> +        "Temporary readrate used to catch up if an input lags behind the specified readrate", "speed" },
>       { "target",                 OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_PERFILE | OPT_EXPERT | OPT_OUTPUT,
>           { .func_arg = opt_target },
>           "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

      reply	other threads:[~2025-02-23  7:36 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-18  9:46 Gyan Doshi
2025-02-23  7:36 ` Gyan Doshi [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=644aecdc-b230-4883-af13-91bca2b3878a@gyani.pro \
    --to=ffmpeg@gyani.pro \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git