[vlc-devel] [PATCH] Improve HLS startup speed
cs448 at cam.ac.uk
Thu May 31 01:20:30 CEST 2012
My next tweak to the HLS stream filter: this time I'm trying to get it
to start playing a little faster when conditions are good. The attached
patch addresses this by introducing a very simple dynamic buffering
scheme, and by fixing a flaw which was causing more buffering than was
intended at startup.
The existing buffering scheme was hardcoded, and inconsistent.
After an underrun due to the playback thread overtaking the download
thread, we simply rebuffered a single segment, as a side-effect of
trying to acquire the segment mutex in GetSegment() whilst the download
thread was still retrieving the data for that segment (actually this was
slightly racy; it was possible for the playback thread to beat the
download thread to the lock, and so report a false EOF).
At startup, we fetched a hardcoded 2 segments before starting playback.
Finally, after a seek we fetched 3 segments before permitting playback
I've replaced these three with a variable member of hls_playback_t
called buf_segs: the number of segments we want on hand before
recovering from an underrun or a seek. It starts off with an optimistic
value of 1, and is set to the most pessimistic existing value of 3 after
we suffer our first underrun.
The rationale is that there are basically 3 situations that might happen:
1. Download is much faster than playback. In this case we might as well
start as soon as we have enough bytes on hand; with more hacking we
could do just that, but I settle for 1 segment since (a) I'd need to
modify the segment locking discipline and (b) the segment might need
2. Download is much slower than playback; then all is lost whatever we do.
3. Download is roughly the same speed as playback, with some variance
either side. In this case a 1-segment buffer will likely cause underruns
because the following segment will be just arriving when we finish
playing back the current one. This is why after an underrun I switch to
a 3-segment buffer.
So in short, the patch aims to optimistically suppose case #1, then move
to an approach that suits case #3 after it seems there might be trouble.
Finally, I added a special case to Segment_Seek, because every startup
was exhibiting the following behaviour:
1. Prefetch runs, fetching 2 segments before we start.
2. VLC core issues a seek to offset 0
3. Segment_Seek sets p_sys->download.seek and waits for the download
thread to acknowledge...
4. ...but the download thread is busy fetching segment 3!
5. It finishes downloading, the seek completes, and we start playback.
The best fix here would be to permit asynchronously ordering the
download thread to reposition without waiting if our segments are ready,
but this would be tricky because there are lots of places where
download.segment is assumed to have a sensible relationship with
playback.segment. Therefore I catch a more specialised case, which
happens to include the seek-0-at-startup case. If the download pointer
is at segment N, and playback is being seeked to segment M, and N is
sufficiently greater than M that we have enough segments in hand to
satisfy p_sys->playback.buf_segs, and all segments between M and N
(including M, excluding N) are already present, I skip waiting for the
download thread to become available because all that would happen is
that the download thread would immediately skip these itself and return
to its previous position.
Finally, some results: for my simulated 128K listener pulling a 96K MP3,
running with 10s segments, and with a 200ms RTT (representitive of
cross-Atlantic traffic, for example), this allows him to get started in
roughly 9 seconds (4 RTTs plus a segment download time) rather than 24
seconds (8 RTTs plus 3 segments).
Since this is a more involved patch than the others, I guess I'll have
done some of it wrong -- please let me know and I'll tweak it appropriately!
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 10403 bytes
Desc: not available
More information about the vlc-devel