Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] fftools/ffmpeg: sleep more efficiently when using -re or -readrate
@ 2023-04-07  7:22 Davy Durham
  0 siblings, 0 replies; 2+ messages in thread
From: Davy Durham @ 2023-04-07  7:22 UTC (permalink / raw)
  To: ffmpeg-devel

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(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 438bee8fef..42bb14556e 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -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");
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 823218e214..c2d279f163 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -452,6 +452,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;
      /**
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index db05ddb8e9..b3fdbe0c9e 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -453,15 +453,18 @@ int ifile_get_packet(InputFile *f, AVPacket **pkt)
                                (f->start_time != AV_NOPTS_VALUE ? 
f->start_time : 0)
                               );
          float scale = f->rate_emu ? 1.0 : f->readrate;
+        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 > now)
+            now_adj = (now - ist->start) * scale + stream_ts_offset;
+            if (pts > now_adj) {
+                f->next_read_time = now + (pts - now_adj);
                  return AVERROR(EAGAIN);
+            }
          }
      }
  -- 2.25.1

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 2+ messages in thread
* [FFmpeg-devel] [PATCH] fftools/ffmpeg: sleep more efficiently when using -re or -readrate
@ 2023-04-07  8:17 Davy Durham
  0 siblings, 0 replies; 2+ messages in thread
From: Davy Durham @ 2023-04-07  8:17 UTC (permalink / raw)
  To: ffmpeg-devel

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(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 438bee8fef..42bb14556e 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -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");
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index e057e6da3a..e077950eaa 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -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;
      /**
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index af423c9be4..fc2feda344 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -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);
+            }
          }
      }
  -- 2.25.1

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-04-07  8:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-07  7:22 [FFmpeg-devel] [PATCH] fftools/ffmpeg: sleep more efficiently when using -re or -readrate Davy Durham
2023-04-07  8:17 Davy Durham

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