[FFmpeg-devel] [PATCH] avformat/file: fd, pipe and file input/output now honor rw_timeout

Davy Durham ddurham at davyandbeth.com
Fri Mar 17 08:32:11 EET 2023


File descriptors, pipes or even filenames (that may be fifos or
reference other non-regular files) may have upstream or downstream
processess that stall out just like any network channel.  Hence ffmpeg
should respect -rw_timeout for these types too.  This is necessary
when, for example, input from a pipe has stalled and we want ffmpeg
to timeout in order to have a pipeline tear down.
---
  doc/protocols.texi |  4 ++--
  libavformat/file.c | 20 ++++++++++++++++++++
  2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 21ae6181a0..d75521ced2 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -45,8 +45,8 @@ All protocols accept the following options:
   @table @option
  @item rw_timeout
-Maximum time to wait for (network) read/write operations to complete,
-in microseconds.
+Maximum time to wait for (network, file, fd, and pipe) read/write 
operations
+to complete, in microseconds.
  @end table
   A description of the currently available protocols follows.
diff --git a/libavformat/file.c b/libavformat/file.c
index cbdf48de0a..fc1d15a672 100644
--- a/libavformat/file.c
+++ b/libavformat/file.c
@@ -40,6 +40,7 @@
  #include <stdlib.h>
  #include "os_support.h"
  #include "url.h"
+#include "network.h"
   /* Some systems may not have S_ISFIFO */
  #ifndef S_ISFIFO
@@ -140,6 +141,11 @@ static int file_read(URLContext *h, unsigned char 
*buf, int size)
      FileContext *c = h->priv_data;
      int ret;
      size = FFMIN(size, c->blocksize);
+    if (h->rw_timeout > 0) { /* wait for something, anything to read */
+        ret = ff_network_wait_fd_timeout(c->fd, 0, h->rw_timeout, NULL);
+        if (ret)
+            return ret;
+    }
      ret = read(c->fd, buf, size);
      if (ret == 0 && c->follow)
          return AVERROR(EAGAIN);
@@ -152,6 +158,11 @@ static int file_write(URLContext *h, const unsigned 
char *buf, int size)
  {
      FileContext *c = h->priv_data;
      int ret;
+    if (h->rw_timeout > 0) { /* wait for something, anything to read */
+        ret = ff_network_wait_fd_timeout(c->fd, 1, h->rw_timeout, NULL);
+        if (ret)
+            return ret;
+    }
      size = FFMIN(size, c->blocksize);
      ret = write(c->fd, buf, size);
      return (ret == -1) ? AVERROR(errno) : ret;
@@ -304,6 +315,9 @@ static int file_open(URLContext *h, const char 
*filename, int flags)
      if (fd == -1)
          return AVERROR(errno);
      c->fd = fd;
+    if (h->rw_timeout > 0) { /* if we'll be doing reads w/ timeout, 
mark non-blocking */
+        fcntl(c->fd, F_SETFL, fcntl(c->fd, F_GETFL, 0) | O_NONBLOCK);
+    }
       h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
  @@ -448,6 +462,9 @@ static int pipe_open(URLContext *h, const char 
*filename, int flags)
      c->fd = fd_dup(h, c->fd);
      if (c->fd == -1)
          return AVERROR(errno);
+    if (h->rw_timeout > 0) { /* if we'll be doing reads w/ timeout, 
mark non-blocking */
+        fcntl(c->fd, F_SETFL, fcntl(c->fd, F_GETFL, 0) | O_NONBLOCK);
+    }
      h->is_streamed = 1;
      return 0;
  }
@@ -493,6 +510,9 @@ static int fd_open(URLContext *h, const char 
*filename, int flags)
      c->fd = fd_dup(h, c->fd);
      if (c->fd == -1)
          return AVERROR(errno);
+    if (h->rw_timeout > 0) { /* if we'll be doing reads w/ timeout, 
mark non-blocking */
+        fcntl(c->fd, F_SETFL, fcntl(c->fd, F_GETFL, 0) | O_NONBLOCK);
+    }
       return 0;
  }
-- 
2.25.1



More information about the ffmpeg-devel mailing list