From 150a9636b58ac912ed4d46e6d8379beb5632f2f8 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 23 Jul 2015 18:31:06 +0200 Subject: [PATCH 1/1] Allow prebuffer to happen by playing data from the backlog. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This won't reduce the latency (although it shouldn't increase it either, unless you have extreme bitrate changes), but it should give a picture on screen much sooner, hopefully getting rid of the “what's going on, why is nothing starting” feeling. --- server.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/server.cpp b/server.cpp index 14162f5..e99dbea 100644 --- a/server.cpp +++ b/server.cpp @@ -469,20 +469,43 @@ sending_header_or_error_again: return; } - // Start sending from the first keyframe we get. In other - // words, we won't send any of the backlog, but we'll start - // sending immediately as we get the next keyframe block. - // This is postcondition #3. Stream *stream = client->stream; if (client->stream_pos == size_t(-2)) { + // Start sending from the beginning of the backlog. client->stream_pos = std::min( stream->bytes_received - stream->backlog_size, 0); client->state = Client::SENDING_DATA; goto sending_data; - } else { + } else if (stream->prebuffering_bytes == 0) { + // Start sending from the first keyframe we get. In other + // words, we won't send any of the backlog, but we'll start + // sending immediately as we get the next keyframe block. + // Note that this is functionally identical to the next if branch, + // except that we save a binary search. client->stream_pos = stream->bytes_received; client->state = Client::WAITING_FOR_KEYFRAME; + } else { + // We're not going to send anything to the client before we have + // N bytes. However, this wait might be boring; we can just as well + // use it to send older data if we have it. We use lower_bound() + // so that we are conservative and never add extra latency over just + // waiting (assuming CBR or nearly so); otherwise, we could want e.g. + // 100 kB prebuffer but end up sending a 10 MB GOP. + deque::const_iterator starting_point_it = + lower_bound(stream->suitable_starting_points.begin(), + stream->suitable_starting_points.end(), + stream->bytes_received - stream->prebuffering_bytes); + if (starting_point_it == stream->suitable_starting_points.end()) { + // None found. Just put us at the end, and then wait for the + // first keyframe to appear. + client->stream_pos = stream->bytes_received; + client->state = Client::WAITING_FOR_KEYFRAME; + } else { + client->stream_pos = *starting_point_it; + client->state = Client::PREBUFFERING; + goto prebuffering; + } } // Fall through. } @@ -501,6 +524,7 @@ sending_header_or_error_again: // Fall through. } case Client::PREBUFFERING: { +prebuffering: Stream *stream = client->stream; size_t bytes_to_send = stream->bytes_received - client->stream_pos; assert(bytes_to_send <= stream->backlog_size); -- 2.39.2