[FFmpeg-devel] [PATCH] ffmpeg: add option readrate

Gyan Doshi ffmpeg at gyani.pro
Fri Jul 16 15:34:10 EEST 2021


Allows to read inputs at arbitrary rates.
-re is equivalent to -readrate 1

Tested with -copyts {+ start_at_zero}, -ss, streamcopied & decoded streams.
---
 doc/ffmpeg.texi      | 18 +++++++++++-------
 fftools/ffmpeg.c     | 13 ++++++++++---
 fftools/ffmpeg.h     |  2 ++
 fftools/ffmpeg_opt.c | 19 ++++++++++++++++++-
 4 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index b27b9fe2c4..d4363f7cc8 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1568,14 +1568,18 @@ Exit after ffmpeg has been running for @var{duration} seconds in CPU user time.
 Dump each input packet to stderr.
 @item -hex (@emph{global})
 When dumping packets, also dump the payload.
- at item -re (@emph{input})
-Read input at native frame rate. Mainly used to simulate a grab device,
-or live input stream (e.g. when reading from a file). Should not be used
-with actual grab devices or live input streams (where it can cause packet
-loss).
+ at item -readrate @var{speed} (@emph{input})
+Limit input read speed to specified floating-point positive value.
 By default @command{ffmpeg} attempts to read the input(s) as fast as possible.
-This option will slow down the reading of the input(s) to the native frame rate
-of the input(s). It is useful for real-time output (e.g. live streaming).
+This option sets a ceiling which will have an effect when packets are available
+to be read at a faster rate.
+Mainly used to simulate a grab device, or live input stream (e.g. when reading from a file).
+Should not be used with actual grab devices or live input streams (where it can cause packet
+loss).
+It is useful for output where flow control is important, such as live streaming.
+Value @code{1} represents real-time speed. Default is @code{0}, which disables any ceiling.
+ at item -re (@emph{input})
+Read input at native frame rate. This option is deprecated. Use @code{-readrate 1} instead.
 @item -vsync @var{parameter}
 Video sync method.
 For compatibility reasons old values can be specified as numbers.
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index e97d879cb3..efbd513f01 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -3759,7 +3759,7 @@ static int transcode_init(void)
     /* init framerate emulation */
     for (i = 0; i < nb_input_files; i++) {
         InputFile *ifile = input_files[i];
-        if (ifile->rate_emu)
+        if (ifile->readrate || ifile->rate_emu)
             for (j = 0; j < ifile->nb_streams; j++)
                 input_streams[j + ifile->ist_index]->start = av_gettime_relative();
     }
@@ -4219,12 +4219,19 @@ static int get_input_packet_mt(InputFile *f, AVPacket **pkt)
 
 static int get_input_packet(InputFile *f, AVPacket **pkt)
 {
-    if (f->rate_emu) {
+    if (f->readrate || f->rate_emu) {
         int i;
+        int64_t file_start = copy_ts * (
+                              (f->ctx->start_time != AV_NOPTS_VALUE ? f->ctx->start_time * !start_at_zero : 0) +
+                              (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0)
+                             );
+        float scale = f->rate_emu ? 1.0 : f->readrate;
         for (i = 0; i < f->nb_streams; i++) {
             InputStream *ist = input_streams[f->ist_index + i];
+            if (!ist->nb_packets) continue;
+            int64_t stream_ts_offset = FFMAX(ist->first_dts != AV_NOPTS_VALUE ? ist->first_dts : 0, file_start);
             int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
-            int64_t now = av_gettime_relative() - ist->start;
+            int64_t now = (av_gettime_relative() - ist->start)*scale + stream_ts_offset;
             if (pts > now)
                 return AVERROR(EAGAIN);
         }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index e9d30fbd67..eda1c82c43 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -119,6 +119,7 @@ typedef struct OptionsContext {
     int64_t input_ts_offset;
     int loop;
     int rate_emu;
+    float readrate;
     int accurate_seek;
     int thread_queue_size;
 
@@ -418,6 +419,7 @@ typedef struct InputFile {
                              from ctx.nb_streams if new streams appear during av_read_frame() */
     int nb_streams_warn;  /* number of streams that the user was warned of */
     int rate_emu;
+    float readrate;
     int accurate_seek;
 
     AVPacket *pkt;
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index cb7d6ceefc..73e2aaaa65 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -1286,6 +1286,20 @@ static int open_input_file(OptionsContext *o, const char *filename)
     f->loop = o->loop;
     f->duration = 0;
     f->time_base = (AVRational){ 1, 1 };
+
+    f->readrate = o->readrate ? o->readrate : 0.0;
+    if (f->readrate < 0.0f) {
+        av_log(NULL, AV_LOG_ERROR, "Option -readrate for Input #%d is %0.3f; it must be non-negative.\n", nb_input_files, f->readrate);
+        exit_program(1);
+    }
+    if (f->readrate && f->rate_emu) {
+        av_log(NULL, AV_LOG_WARNING, "Both -readrate and -re set for Input #%d. Using -readrate %0.3f.\n", nb_input_files, f->readrate);
+        f->rate_emu = 0;
+    }
+    if (f->rate_emu) {
+        av_log(NULL, AV_LOG_WARNING, "-re is deprecated and will be removed soon. Use -readrate\n");
+    }
+
     f->pkt = av_packet_alloc();
     if (!f->pkt)
         exit_program(1);
@@ -3507,7 +3521,10 @@ const OptionDef options[] = {
         "when dumping packets, also dump the payload" },
     { "re",             OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
                         OPT_INPUT,                                   { .off = OFFSET(rate_emu) },
-        "read input at native frame rate", "" },
+        "read input at native frame rate; deprecated, use -readrate 1", "" },
+    { "readrate",       HAS_ARG | OPT_FLOAT | OPT_OFFSET |
+                        OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(readrate) },
+        "read input at specified rate", "speed" },
     { "target",         HAS_ARG | OPT_PERFILE | OPT_OUTPUT,          { .func_arg = opt_target },
         "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "
         "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")", "type" },
-- 
2.32.0



More information about the ffmpeg-devel mailing list