[FFmpeg-devel] [PATCH] avformat/http: fix http reconnect

Hendrik Leppkes h.leppkes at gmail.com
Mon Mar 13 21:56:31 EET 2017


On Mon, Mar 13, 2017 at 12:15 PM, 卢炯健 <lujiongjian1005 at gmail.com> wrote:
> ---
>  .DS_Store          | Bin 0 -> 6148 bytes
>  libavformat/http.c |  56 +++++++++++++++++++++++++++++++++++++----------------
>  2 files changed, 39 insertions(+), 17 deletions(-)
>  create mode 100644 .DS_Store
>

Your patch contains a binary .DS_Store file, please remove it.

> diff --git a/.DS_Store b/.DS_Store
> new file mode 100644
> index 0000000000000000000000000000000000000000..96401baa6bd16b8f5e9d811c77f9d75d64bed634
> GIT binary patch
> literal 6148
> zcmeHKJ5EC}5S%3uibRu=(pTUHRuoQ<3nWS;8b}ZV>R07l9F5se!PA2#5=}HKt;b&P
> z*zy!_-vY4J$Ke530$9);arR+qzVAM<n~FGEoUz0E=jQGBd^$c&vVRXa_ZEAc at Pb#2
> z`8*Rd9JsgtajHjUQa}nw0VyB_q`;*LR3%;9U3!3cQa}n^tpfgiXmrP3I3&iWgG00c
> z#5u!ZoJTJ~Y#t!?!Xc3nnkAK(RI3)llFoRmyk0mYCLI<x^PIZbszb53o$(gwu%4(<
> z3P^#m0<&B$z5YMa|LFh6B(0=?6u2q{Y`)&CSA0^{*2&|%);9W<?m1s{H_n5?A<8i^
> j$}tySj_)HW^P11O-wTJtpfetHqJ9Qk7nv0JZw0;qj)fXE
>
> literal 0
> HcmV?d00001
>
> 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;
>  }
> --


It would help if you explain what exactly the problem is, and what
your changes do to fix it. Without knowing these things, its hard to
judge for us if the changes are an improvement.

- Hendrik


More information about the ffmpeg-devel mailing list