@@ -3633,13 +3633,25 @@ static int got_eagain(void)
return 0;
}
-static void reset_eagain(void)
+/* returns the earliest delay in microseconds after which all inputs
should be read again */
+static int64_t reset_eagain(void)
{
+ int64_t now = av_gettime_relative();
+ int64_t d, min_next_read_time = now + 1000000; /* start 1 sec from
now */
int i;
- for (i = 0; i < nb_input_files; i++)
- input_files[i]->eagain = 0;
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile* f = input_files[i];
+ if (f->eagain) {
+ f->eagain = 0;
+ min_next_read_time = FFMIN(min_next_read_time,
f->next_read_time);
+ f->next_read_time = 0;
+ }
+ }
for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost))
ost->unavailable = 0;
+
+ d = min_next_read_time - now;
+ return d > 0 ? d : 0;
}
static void decode_flush(InputFile *ifile)
@@ -3929,8 +3941,8 @@ static int transcode_step(void)
ost = choose_output();
if (!ost) {
if (got_eagain()) {
- reset_eagain();
- av_usleep(10000);
+ int64_t delay = reset_eagain();
+ av_usleep(delay);
return 0;
}
av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from,
finishing.\n");
@@ -453,6 +453,7 @@ typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
+ int64_t next_read_time; /* if eagain, this is the
av_gettime_relative() value after which we should read again */
int64_t input_ts_offset;
int input_sync_ref;
/**
@@ -454,15 +454,18 @@ int ifile_get_packet(InputFile *f, AVPacket **pkt)
);
float scale = f->rate_emu ? 1.0 : f->readrate;
int64_t burst_until = AV_TIME_BASE * f->initial_read_burst;
+ int64_t now = av_gettime_relative();
for (i = 0; i < f->nb_streams; i++) {
InputStream *ist = f->streams[i];
- int64_t stream_ts_offset, pts, now;
+ int64_t stream_ts_offset, pts, now_adj;
if (!ist->nb_packets || (ist->decoding_needed &&
!ist->got_output)) continue;
stream_ts_offset = FFMAX(ist->first_dts != AV_NOPTS_VALUE
? ist->first_dts : 0, file_start);
pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
- now = (av_gettime_relative() - ist->start) * scale +
stream_ts_offset;
- if (pts - burst_until > now)
+ now_adj = (now - ist->start) * scale + stream_ts_offset;
+ if (pts - burst_until > now_adj) {
+ f->next_read_time = now + (pts - now_adj);
return AVERROR(EAGAIN);
+ }
NOTE: This is a resolved patch if the "input burst time" patch is applied first. When the ffmpeg cli tool is given a read rate (i.e. -re or -readrate), the read function is called repeatedly but which may return EAGAIN if it should be called again later. How much later is not indicated and the trancode loop just sleeps for 10ms and tries again. On the next try it may get EGAIN again and this adds up to wasted CPU. For example, conversions of audio files show about a 15-20% higher CPU usage than necessary, when compared to running without a read rate. This patch introduces InputFile::next_read_time which is computed on the way out of the read function, ifile_get_packet(), when it returns EAGAIN. Before sleeping, the transcoding loop now consults this value to determine how long it should sleep rather than blindly sleeping 10ms. Running ffmpeg under the 'time' command shows an improved real+sys time after this change, and these savings improve further if one specifies a larger pkt size to the demuxer (e.g. -max_size for .wav, -raw_packet_size for raw, etc.) since the system is able to sleep longer (and now accurately) each iteration. Signed-off-by: Davy Durham <ddurham@users.sourceforge.net> --- fftools/ffmpeg.c | 22 +++++++++++++++++----- fftools/ffmpeg.h | 1 + fftools/ffmpeg_demux.c | 9 ++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) } } -- 2.25.1