I use the commad line below: ffplay -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 4000 http://movie_url.mp4 I find that if network source down, ffplay keep reconnect only a few seconds even if I set -reconnect_delay_max 4000. So I reopen http connection cyclically until timeout, reconnect successfully or user quit. My patch's commad line is as below: ffplay -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_timeout 30 http://movie_url.mp4
Signed-off-by: Wing Lo <lujiongjian1...@gmail.com> --- libavformat/http.c | 56 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 293a8a7..d38c569 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -112,8 +112,8 @@ typedef struct HTTPContext { int reconnect; int reconnect_at_eof; int reconnect_streamed; - int reconnect_delay; - int reconnect_delay_max; + int reconnect_timeout; + uint8_t can_reconnect; int listen; char *resource; int reply_code; @@ -156,7 +156,7 @@ static const AVOption options[] = { { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D }, { "reconnect_at_eof", "auto reconnect at EOF", OFFSET(reconnect_at_eof), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D }, { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D }, - { "reconnect_delay_max", "max reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_max), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D }, + { "reconnect_timeout", "set timeout (in seconds) for http reconnection", OFFSET(reconnect_timeout), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D }, { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E }, { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E}, @@ -489,6 +489,7 @@ static int http_open(URLContext *h, const char *uri, int flags, else h->is_streamed = 1; + s->can_reconnect = 1; s->filesize = UINT64_MAX; s->location = av_strdup(uri); if (!s->location) @@ -1270,11 +1271,42 @@ static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size) static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect); +static int http_reconnect(URLContext *h) +{ + int64_t wait_start = 0; + int64_t seek_ret; + HTTPContext *s = h->priv_data; + uint64_t target = h->is_streamed ? 0 : s->off; + int timeout = s->reconnect_timeout * 1000*1000; + + if (!s->can_reconnect) + return -1; + + av_log(h, AV_LOG_INFO, "Will reconnect at %"PRIu64".\n", s->off); + do { + if (ff_check_interrupt(&h->interrupt_callback)) + return AVERROR_EXIT; + seek_ret = http_seek_internal(h, target, SEEK_SET, 1); + usleep(1000*1000); + if (timeout > 0) { + if (!wait_start) + wait_start = av_gettime_relative(); + else if (av_gettime_relative() - wait_start > timeout) { + av_log(h, AV_LOG_ERROR, "Reconnect time out. Failed to reconnect at %"PRIu64".\n", target); + s->can_reconnect = 0; + return AVERROR(ETIMEDOUT); + } + } + }while (seek_ret != target); + + av_log(h, AV_LOG_INFO, "Successful to reconnect at %"PRIu64".\n", target); + return 0; +} + static int http_read_stream(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int err, new_location, read_ret; - int64_t seek_ret; if (!s->hd) return AVERROR_EOF; @@ -1292,23 +1324,13 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) 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) || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { - uint64_t target = h->is_streamed ? 0 : s->off; + av_log(h, AV_LOG_INFO, "http buffer read error=%s.\n", av_err2str(read_ret)); - 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); - s->reconnect_delay = 1 + 2*s->reconnect_delay; - seek_ret = http_seek_internal(h, target, SEEK_SET, 1); - if (seek_ret != target) { - av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target); + if (http_reconnect(h) < 0) return read_ret; - } read_ret = http_buf_read(h, buf, size); - } else - s->reconnect_delay = 0; + } return read_ret; } -- 2.10.1 (Apple Git-78) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel