diff --git a/libavformat/avio.c b/libavformat/avio.c
index 3606eb0..34dcf09 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -645,6 +645,13 @@ int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles)
     return h->prot->url_get_multi_file_handle(h, handles, numhandles);
 }
 
+int ffurl_get_stream_size(URLContext *h)
+{
+    if (!h->prot->url_get_stream_size)
+        return -1;
+    return h->prot->url_get_stream_size(h);
+}
+
 int ffurl_shutdown(URLContext *h, int flags)
 {
     if (!h->prot->url_shutdown)
diff --git a/libavformat/http.c b/libavformat/http.c
index 944a6cf..0026168 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -1462,6 +1462,61 @@ static int http_close(URLContext *h)
     return ret;
 }
 
+#define DISCARD_BUFFER_SIZE (256 * 1024)
+static int http_stream_forward(HTTPContext *s, int amount)
+{
+    int len;
+    int ret;
+    int discard = amount;
+    int discard_buf_size;
+    uint8_t * discard_buf;
+
+    /* advance local buffer first */
+    len = FFMIN(discard, s->buf_end - s->buf_ptr);
+    if (len > 0) {
+        av_log(s, AV_LOG_DEBUG, "advancing input buffer by %d bytes\n", len);
+        s->buf_ptr += len;
+        discard -= len;
+        if (discard == 0) {
+            return amount;
+        }
+    }
+
+    /* if underlying protocol is a stream with flow control and we are seeking
+    within the stream buffer size, it performs better to advance through the stream
+    rather than abort the connection and open a new one */
+    len = ffurl_get_stream_size(s->hd);
+    av_log(s, AV_LOG_DEBUG, "stream buffer size: %d\n", len);
+    if ((len <= 0) || (discard > len)) {
+        return AVERROR(EINVAL);
+    }
+
+    /* forward stream by discarding data till new position */
+    discard_buf_size = FFMIN(discard, DISCARD_BUFFER_SIZE);
+    discard_buf = av_malloc(discard_buf_size);
+    if (!discard_buf) {
+        return AVERROR(ENOMEM);
+    }
+
+    av_log(s, AV_LOG_DEBUG, "advancing stream by discarding %d bytes\n", discard);
+    while (discard > 0) {
+        ret = ffurl_read(s->hd, discard_buf, FFMIN(discard, discard_buf_size));
+        if (ret > 0) {
+            discard -= ret;
+        } else {
+            ret = (!ret ? AVERROR_EOF : ff_neterrno());
+            av_log(s, AV_LOG_DEBUG, "read error: %d\n", ret);
+            break;
+        }
+    }
+    av_freep(&discard_buf);
+
+    if (discard == 0) {
+        return amount;
+    }
+    return ret;
+}
+
 static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
 {
     HTTPContext *s = h->priv_data;
@@ -1493,6 +1548,20 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo
     if (s->off && h->is_streamed)
         return AVERROR(ENOSYS);
 
+    /* if seeking forward, see if we can satisfy the seek with our current connection */
+    if ((s->off > old_off) &&
+        (s->off - old_off <= INT32_MAX)) {
+        int amount = (int)(s->off - old_off);
+        int res;
+
+        av_log(s, AV_LOG_DEBUG, "attempting stream forwarding, old: %lld, new: %lld bytes: %d\n",
+           old_off, s->off, amount);
+        res = http_stream_forward(s, amount);
+        if (res == amount) {
+            return off;
+        }
+    }
+
     /* we save the old context in case the seek fails */
     old_buf_size = s->buf_end - s->buf_ptr;
     memcpy(old_buf, s->buf_ptr, old_buf_size);
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 25abafc..b73e500 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -265,6 +265,26 @@ static int tcp_get_file_handle(URLContext *h)
     return s->fd;
 }
 
+static int tcp_get_window_size(URLContext *h)
+{
+    TCPContext *s = h->priv_data;
+    int avail;
+    int avail_len = sizeof(avail);
+
+    #if HAVE_WINSOCK2_H
+    /* SO_RCVBUF with winsock only reports the actual TCP window size when
+    auto-tuning has been disabled via setting SO_RCVBUF */
+    if (s->recv_buffer_size < 0) {
+        return AVERROR(EINVAL);
+    }
+    #endif
+
+    if (getsockopt(s->fd, SOL_SOCKET, SO_RCVBUF, &avail, &avail_len)) {
+           return ff_neterrno();
+    }
+    return avail;
+}
+
 const URLProtocol ff_tcp_protocol = {
     .name                = "tcp",
     .url_open            = tcp_open,
@@ -273,6 +293,7 @@ const URLProtocol ff_tcp_protocol = {
     .url_write           = tcp_write,
     .url_close           = tcp_close,
     .url_get_file_handle = tcp_get_file_handle,
+    .url_get_stream_size = tcp_get_window_size,
     .url_shutdown        = tcp_shutdown,
     .priv_data_size      = sizeof(TCPContext),
     .flags               = URL_PROTOCOL_FLAG_NETWORK,
diff --git a/libavformat/url.h b/libavformat/url.h
index 5c50245..5e607c9 100644
--- a/libavformat/url.h
+++ b/libavformat/url.h
@@ -84,6 +84,7 @@ typedef struct URLProtocol {
     int (*url_get_file_handle)(URLContext *h);
     int (*url_get_multi_file_handle)(URLContext *h, int **handles,
                                      int *numhandles);
+    int (*url_get_stream_size)(URLContext *h);
     int (*url_shutdown)(URLContext *h, int flags);
     int priv_data_size;
     const AVClass *priv_data_class;
@@ -249,6 +250,13 @@ int ffurl_get_file_handle(URLContext *h);
 int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles);
 
 /**
+ * Return sizes (in bytes) of stream based URL buffer.
+ *
+ * @return size on success or <0 on error.
+ */
+int ffurl_get_stream_size(URLContext *h);
+
+/**
  * Signal the URLContext that we are done reading or writing the stream.
  *
  * @param h pointer to the resource
