[FFmpeg-devel] [PATCH] HTTP: optimize forward seek performance

Ronald S. Bultje rsbultje at gmail.com
Thu Jan 12 14:47:32 EET 2017

Hi Joel,

On Wed, Jan 11, 2017 at 6:01 PM, Joel Cunningham <joel.cunningham at me.com>

> Hi,
> I’ve been working on optimizing HTTP forward seek performance for ffmpeg
> and would like to contribute this patch into mainline ffmpeg.  Please see
> the below patch for an explanation of the issue and proposed fix.  I have
> provided evidence of the current performance issue and my sample MP4 so
> others can reproduce and observe the behavior.
> Files are located in Dropbox here: https://www.dropbox.com/sh/
> 4q4ru8isdv22joj/AABU3XyXmgLMiEFqucf1LdZ3a?dl=0
> GRMT0003.MP4 - test video file
> mac-ffplay-baseline.pcapng - wireshark capture of ffplay (49abd) playing
> the above test file on MacOS 10.12.2 from a remote NGINX server
> mac-ffplay-optimize-patch.pcapng - same ffplay setup but with patch
> applied
> ffplay_output.log - console output of ffplay with patch (loglevel debug)
> I’m happy to discuss this issue further if the below description doesn’t
> fully communicate the issue.
> Thanks,
> Joel
> From 89a3ed8aab9168313b4f7e83c00857f9b715ba4e Mon Sep 17 00:00:00 2001
> From: Joel Cunningham <joel.cunningham at me.com>
> Date: Wed, 11 Jan 2017 13:55:02 -0600
> Subject: [PATCH] HTTP: optimize forward seek performance
> This commit optimizes HTTP forward seeks by advancing the stream on
> the current connection when the seek amount is within the current
> TCP window rather than closing the connection and opening a new one.
> This improves performance because with TCP flow control, a window's
> worth of data is always either in the local socket buffer already or
> in-flight from the sender.
> The previous behavior of closing the connection, then opening a new
> with a new HTTP range value results in a massive amounts of discarded
> and re-sent data when large TCP windows are used.  This has been observed
> on MacOS/iOS which starts with an inital window of 256KB and grows up to
> 1MB depending on the bandwidth-product delay.
> When seeking within a window's worth of data and we close the connection,
> then open a new one within the same window's worth of data, we discard
> from the current offset till the end of the window.  Then on the new
> connection the server ends up re-sending the previous data from new
> offset till the end of old window.
> Example:
> TCP window size: 64KB
> Position: 32KB
> Forward seek position: 40KB
>       *                      (Next window)
> 32KB |--------------| 96KB |---------------| 160KB
>         *
>   40KB |---------------| 104KB
> Re-sent amount: 96KB - 40KB = 56KB
> For a real world test example, I have MP4 file of ~25MB, which ffplay
> only reads ~16MB and performs 177 seeks. With current ffmpeg, this results
> in 177 HTTP GETs and ~73MB worth of TCP data communication.  With this
> patch, ffmpeg issues 4 HTTP GETs for a total of ~20MB of TCP data
> communication.
> To support this feature, a new URL function has been added to get the
> stream buffer size from the TCP protocol.  The stream advancement logic
> has been implemented in the HTTP layer since this the layer in charge of
> the seek and creating/destroying the TCP connections.
> This feature has been tested on Windows 7 and MacOS/iOS.  Windows support
> is slightly complicated by the fact that when TCP window auto-tuning is
> enabled, SO_RCVBUF doesn't report the real window size, but it does if
> SO_RCVBUF was manually set (disabling auto-tuning). So we can only use
> this optimization on Windows in the later case
> ---
>  libavformat/avio.c |  7 ++++++
>  libavformat/http.c | 69 ++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++
>  libavformat/tcp.c  | 21 +++++++++++++++++
>  libavformat/url.h  |  8 +++++++
>  4 files changed, 105 insertions(+)

Very interesting. There's some minor stylistic nits (double brackets where
there shouldn't be, I didn't check super-closely for that), but overall
this is a pretty thoughtful patch in what it's trying to do.

As for Windows, I'm surprised that there wouldn't be any API to get the
real current window size. I mean, I understand that they would decrease
window size on-demand, but I would expect them to do that w/o throwing out
already-downloaded data - so essentially I expect delayed auto-tuning. In
that case, getting the current window size should be trivial and valid
until the next read. Very strange. I suppose no workarounds (perhaps with
windows-specific API) exist? Also, what is the practical implication? Does
it work as before? Or better but not optimal? Or worse?

I'm wondering if there's some way to make the interaction between tcp and
http less awkward. Similar problems exist between rtp/udp, where we want
deeper protocol integration and the generic API basically inhibits us.
Probably out of scope for this patch and not a terribly big deal because
the URL API is currently not exposed, but we eventually want to expose this
API (IMO) so at some point this will need some more thoughts.

If nobody else has comments, I'm inclined to accept this patch (I'll fix
the cosmetics myself).


More information about the ffmpeg-devel mailing list