On Sat, 19 Mar 2016, Anton Khirnov wrote:

Quoting Martin Storsjö (2016-03-18 13:01:36)
From: Andrey Utkin <andrey.krieger.ut...@gmail.com>

If set non-zero, this limits duration of the retry_transfer_wrapper()
loop, thus affecting ffurl_read*(), ffurl_write(). As soon as
one single byte is successfully received/transmitted, the timer
restarts.

This has further changes by Michael Niedermayer and Martin Storsjö.
---
Andrey's original version didn't reset the timer on successful
transfers, but I think this is closer to how most people may
want it to work.

I also added an AVOption for setting this, to allow it to be set
generically for any URLProtocol.
---
 libavformat/avio.c | 21 +++++++++++++++++----
 libavformat/url.h  |  1 +
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index 4da6b74..6039990 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -49,7 +49,10 @@ static void *urlcontext_child_next(void *obj, void *prev)
     return NULL;
 }

-static const AVOption options[] = { { NULL } };
+static const AVOption options[] = {
+    { "rw_timeout", "Timeout for IO operations (in microseconds)", 
offsetof(URLContext, rw_timeout), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, 
AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_DECODING_PARAM },
+    { NULL }
+};
 const AVClass ffurl_context_class = {
     .class_name       = "URLContext",
     .item_name        = urlcontext_to_name,
@@ -199,6 +202,7 @@ static inline int retry_transfer_wrapper(URLContext *h, 
uint8_t *buf,
 {
     int ret, len;
     int fast_retries = 5;
+    int64_t wait_since = 0;

     len = 0;
     while (len < size_min) {
@@ -209,14 +213,23 @@ static inline int retry_transfer_wrapper(URLContext *h, 
uint8_t *buf,
             return ret;
         if (ret == AVERROR(EAGAIN)) {
             ret = 0;
-            if (fast_retries)
+            if (fast_retries) {
                 fast_retries--;
-            else
+            } else {
+                if (h->rw_timeout) {
+                    if (!wait_since)
+                        wait_since = av_gettime_relative();
+                    else if (av_gettime_relative() > wait_since + 
h->rw_timeout)
+                        return AVERROR(EIO);

ETIMEDOUT might be more appropriate perhaps?

Possibly, except I don't think all systems we support have got ETIMEDOUT. (In practice we use a narrow range of errno codes, and that doesn't seem to be one of the common ones. In network.h, we have a fallback definition of ETIMEDOUT for winsock, but I don't think we should rely on having winsock and network.h included everywhere.)

+                }
                 av_usleep(1000);
+            }
         } else if (ret < 1)
             return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
-        if (ret)
+        if (ret) {
             fast_retries = FFMAX(fast_retries, 2);
+            wait_since = 0;
+        }
         len += ret;
         if (ff_check_interrupt(&h->interrupt_callback))
             return AVERROR_EXIT;
diff --git a/libavformat/url.h b/libavformat/url.h
index 482658b..5ae6cf2 100644
--- a/libavformat/url.h
+++ b/libavformat/url.h
@@ -49,6 +49,7 @@ typedef struct URLContext {
     int is_streamed;            /**< true if streamed (no seek possible), 
default = false */
     int is_connected;
     AVIOInterruptCB interrupt_callback;
+    int64_t rw_timeout;         /**< maximum time to wait for (network) 
read/write operation completion, in mcs */
                                                                                
                                ^
c?

I'll expand it into "microseconds".

// Martin
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to