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. -@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). +@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. +@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".