[FFmpeg-devel] [PATCH] udp: add option "timeout" for read

Andrey Utkin andrey.krieger.utkin at gmail.com
Wed Aug 15 20:24:14 CEST 2012


Let UDP reading return error if cannot get data in timeout.
Parameter takes value in same units as av_gettime(), microseconds.
---
 doc/protocols.texi |    3 +++
 libavformat/udp.c  |   23 +++++++++++++++++++++--
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index be19239..265fe13 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -686,6 +686,9 @@ packets with size of 188 bytes. If not specified defaults to 7*4096.
 @item overrun_nonfatal=@var{1|0}
 Survive in case of UDP receiving circular buffer overrun. Default
 value is 0.
+
+ at item timeout=@var{microseconds}
+In read mode: if no data arrived in more than this time interval, raise error.
 @end table
 
 Some usage examples of the UDP protocol with @command{ffmpeg} follow.
diff --git a/libavformat/udp.c b/libavformat/udp.c
index f93c607..5ed47e8 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -64,6 +64,7 @@ typedef struct {
     struct sockaddr_storage dest_addr;
     int dest_addr_len;
     int is_connected;
+    int64_t read_timeout;
 
     /* Circular Buffer variables for use in UDP receive code */
     int circular_buffer_size;
@@ -77,6 +78,7 @@ typedef struct {
 #endif
     uint8_t tmp[UDP_MAX_PKT_SIZE+4];
     int remaining_in_dg;
+    int64_t waiting_data_since_time;  /* used for 'timeout' option */
 } UDPContext;
 
 static void log_net_error(void *ctx, int level, const char* prefix)
@@ -549,6 +551,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
                     break;
             }
         }
+        if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p))
+            s->read_timeout = strtol(buf, NULL, 10);
     }
 
     /* fill the dest addr */
@@ -700,6 +704,8 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
     int ret;
     int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK;
 
+    if (s->waiting_data_since_time && (av_gettime() - s->waiting_data_since_time > s->read_timeout))
+        return AVERROR(EIO);
 #if HAVE_PTHREAD_CANCEL
     if (s->fifo) {
         pthread_mutex_lock(&s->mutex);
@@ -718,6 +724,7 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
                 av_fifo_generic_read(s->fifo, buf, avail, NULL);
                 av_fifo_drain(s->fifo, AV_RL32(tmp) - avail);
                 pthread_mutex_unlock(&s->mutex);
+                s->waiting_data_since_time = 0;
                 return avail;
             } else if(s->circular_buffer_error){
                 int err = s->circular_buffer_error;
@@ -725,9 +732,13 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
                 return err;
             } else if(nonblock) {
                 pthread_mutex_unlock(&s->mutex);
+                if (s->read_timeout && !s->waiting_data_since_time)
+                    s->waiting_data_since_time = av_gettime();
                 return AVERROR(EAGAIN);
             }
             else {
+                if (s->read_timeout && !s->waiting_data_since_time)
+                    s->waiting_data_since_time = av_gettime();
                 /* FIXME: using the monotonic clock would be better,
                    but it does not exist on all supported platforms. */
                 int64_t t = av_gettime() + 100000;
@@ -743,12 +754,20 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
 
     if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
         ret = ff_network_wait_fd(s->udp_fd, 0);
-        if (ret < 0)
+        if (ret < 0) {
+            if (s->read_timeout && (ret == AVERROR(EAGAIN)) && !s->waiting_data_since_time)
+                s->waiting_data_since_time = av_gettime();
             return ret;
+        }
     }
     ret = recv(s->udp_fd, buf, size, 0);
 
-    return ret < 0 ? ff_neterrno() : ret;
+    if (ret < 0) {
+        return ff_neterrno();
+    } else {
+        s->waiting_data_since_time = 0;
+        return ret;
+    }
 }
 
 static int udp_write(URLContext *h, const uint8_t *buf, int size)
-- 
1.7.8.6



More information about the ffmpeg-devel mailing list