[FFmpeg-devel] [PATCH] http: block while waiting for reconnecting

wm4 nfxjfg at googlemail.com
Sat Dec 30 19:07:26 EET 2017


It makes no sense to return an error after the first reconnect, and then
somehow resume the next time it's called.

Also make the wait reasonably interruptible. Since there is no mechanism
for this in the API, polling is the best we can do. (Some effort could
be put into making the wait more accurate, since the av_usleep() will
not wait exactly 1000 microseconds, and the error will add up.)

(The original code would work if it returned AVERROR(EAGAIN) or so,
which would make retry_transfer_wrapper() repeat the read call. But I
think having an explicit loop for this is better anyway.)
---
 libavformat/http.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index a376f1a488..2957648d61 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -1443,25 +1443,29 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
         return http_buf_read_compressed(h, buf, size);
 #endif /* CONFIG_ZLIB */
     read_ret = http_buf_read(h, buf, size);
-    if (   (read_ret  < 0 && s->reconnect        && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize)
+    while (   (read_ret  < 0 && s->reconnect        && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize)
         || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) {
+        unsigned int wait = 0;
         uint64_t target = h->is_streamed ? 0 : s->off;
 
         if (s->reconnect_delay > s->reconnect_delay_max)
             return AVERROR(EIO);
 
         av_log(h, AV_LOG_INFO, "Will reconnect at %"PRIu64" error=%s.\n", s->off, av_err2str(read_ret));
-        av_usleep(1000U*1000*s->reconnect_delay);
+        for (wait = 0; wait < 1000U*s->reconnect_delay; wait++) {
+            if (ff_check_interrupt(&h->interrupt_callback))
+                return AVERROR(EIO);
+            av_usleep(1000);
+        }
         s->reconnect_delay = 1 + 2*s->reconnect_delay;
         seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
-        if (seek_ret != target) {
+        if (seek_ret >= 0 && seek_ret != target) {
             av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
-            return read_ret;
-        }
-
-        read_ret = http_buf_read(h, buf, size);
-    } else
-        s->reconnect_delay = 0;
+            return AVERROR(EIO);
+        } else
+            read_ret = http_buf_read(h, buf, size);
+    }
+    s->reconnect_delay = 0;
 
     return read_ret;
 }
-- 
2.15.1



More information about the ffmpeg-devel mailing list