> On Jan 12, 2017, at 6:47 AM, Ronald S. Bultje <rsbul...@gmail.com> wrote: > > Hi Joel, > > On Wed, Jan 11, 2017 at 6:01 PM, Joel Cunningham <joel.cunning...@me.com> > wrote: > >> 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.cunning...@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.
My apologies for any stylistic issues, this is my first ffmpeg change and I’m still getting familiar with the style > > 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? For Windows, when TCP receive window auto-tuning is enabled, SO_RCVBUF returns 8192 regardless of what the window value is. According TCP RFCs, a receiver is not allowed to decrease the window, so the stack will only grow the window. Typically in Windows it starts out at 17KB (on a WiFi link) and then grows upwards of 256KB depending on bandwidth-product delay. If you manually set SO_RCVBUF via setsockopt, the TCP window is set to the specified value, auto-tuning is disabled and you can retrieve the correct value at anytime. I didn’t find any windows specific API that worked when auto-tuning is enabled. This issue isn’t as bad on Windows platforms because the window starts out small and grows very conservatively, thus less data is discarded and re-sent during each seek. In terms of practical implications, Windows platforms will behave the same as before this patch. The call to ffurl_get_stream_size() returns an error and then http_seek_internal proceeds with closing the connection and opening a new one at the new offset. I did add support for checking if s->recv_buffer_size had been set in the TCP layer, which would mean the window had been manually set and retrieving the buffer size should be correct. Unfortunately there is not currently a way to set recv_buffer_size for an HTTP protocol via options, so that would need an additional patch, but I tested with hardcoding s->recv_buffer_size to test the feature on Windows. > > 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. > I agree there is some clunkiness in the abstraction since TCP specific things have to be generalized into a concept that could fit into other protocols, thus I came up with “stream size” nomenclature for the function. > If nobody else has comments, I'm inclined to accept this patch (I'll fix > the cosmetics myself). > Joel _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel