blob: 2540ae594148795ce62280e9df31e525348f988b [file] [log] [blame]
philipelbe7a9e52016-05-19 12:19:35 +02001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/video_coding/frame_buffer2.h"
12
13#include <algorithm>
philipele0b2f152016-09-28 10:23:49 +020014#include <cstring>
15#include <queue>
philipelbe7a9e52016-05-19 12:19:35 +020016
philipela45102f2017-02-22 05:30:39 -080017#include "webrtc/modules/video_coding/include/video_coding_defines.h"
philipelbe7a9e52016-05-19 12:19:35 +020018#include "webrtc/modules/video_coding/jitter_estimator.h"
philipelbe7a9e52016-05-19 12:19:35 +020019#include "webrtc/modules/video_coding/timing.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020020#include "webrtc/rtc_base/checks.h"
21#include "webrtc/rtc_base/logging.h"
22#include "webrtc/rtc_base/trace_event.h"
philipelbe7a9e52016-05-19 12:19:35 +020023#include "webrtc/system_wrappers/include/clock.h"
philipel266f0a42016-11-28 08:49:07 -080024#include "webrtc/system_wrappers/include/metrics.h"
philipelbe7a9e52016-05-19 12:19:35 +020025
26namespace webrtc {
27namespace video_coding {
28
29namespace {
philipele0b2f152016-09-28 10:23:49 +020030// Max number of frames the buffer will hold.
31constexpr int kMaxFramesBuffered = 600;
philipelbe7a9e52016-05-19 12:19:35 +020032
philipele0b2f152016-09-28 10:23:49 +020033// Max number of decoded frame info that will be saved.
philipelfd5a20f2016-11-15 00:57:57 -080034constexpr int kMaxFramesHistory = 50;
philipel65e1f942017-07-24 08:26:53 -070035
36constexpr int64_t kLogNonDecodedIntervalMs = 5000;
philipelbe7a9e52016-05-19 12:19:35 +020037} // namespace
38
philipelbe7a9e52016-05-19 12:19:35 +020039FrameBuffer::FrameBuffer(Clock* clock,
40 VCMJitterEstimator* jitter_estimator,
philipela45102f2017-02-22 05:30:39 -080041 VCMTiming* timing,
42 VCMReceiveStatisticsCallback* stats_callback)
philipelbe7a9e52016-05-19 12:19:35 +020043 : clock_(clock),
tommi0a735642017-03-14 06:23:57 -070044 new_continuous_frame_event_(false, false),
philipelbe7a9e52016-05-19 12:19:35 +020045 jitter_estimator_(jitter_estimator),
46 timing_(timing),
philipel4f6cd6a2016-08-03 10:59:32 +020047 inter_frame_delay_(clock_->TimeInMilliseconds()),
gnishb2a318b2017-05-10 09:21:33 -070048 last_decoded_frame_timestamp_(0),
philipele0b2f152016-09-28 10:23:49 +020049 last_decoded_frame_it_(frames_.end()),
50 last_continuous_frame_it_(frames_.end()),
51 num_frames_history_(0),
52 num_frames_buffered_(0),
philipel29f730e2017-03-15 08:10:08 -070053 stopped_(false),
philipela45102f2017-02-22 05:30:39 -080054 protection_mode_(kProtectionNack),
philipel65e1f942017-07-24 08:26:53 -070055 stats_callback_(stats_callback),
56 last_log_non_decoded_ms_(-kLogNonDecodedIntervalMs) {}
philipel266f0a42016-11-28 08:49:07 -080057
philipela45102f2017-02-22 05:30:39 -080058FrameBuffer::~FrameBuffer() {}
philipelbe7a9e52016-05-19 12:19:35 +020059
philipel75562822016-09-05 10:57:41 +020060FrameBuffer::ReturnReason FrameBuffer::NextFrame(
61 int64_t max_wait_time_ms,
tkchin53959fc2017-08-17 11:01:46 -070062 std::unique_ptr<FrameObject>* frame_out) {
tommidb23ea62017-03-03 07:21:18 -080063 TRACE_EVENT0("webrtc", "FrameBuffer::NextFrame");
philipel1c056252017-01-31 09:53:12 -080064 int64_t latest_return_time_ms =
65 clock_->TimeInMilliseconds() + max_wait_time_ms;
philipel504c47d2016-06-30 17:33:02 +020066 int64_t wait_ms = max_wait_time_ms;
philipel29f730e2017-03-15 08:10:08 -070067 int64_t now_ms = 0;
philipele0b2f152016-09-28 10:23:49 +020068
69 do {
philipel29f730e2017-03-15 08:10:08 -070070 now_ms = clock_->TimeInMilliseconds();
philipel504c47d2016-06-30 17:33:02 +020071 {
72 rtc::CritScope lock(&crit_);
tommi0a735642017-03-14 06:23:57 -070073 new_continuous_frame_event_.Reset();
philipel29f730e2017-03-15 08:10:08 -070074 if (stopped_)
75 return kStopped;
76
77 wait_ms = max_wait_time_ms;
78
philipele0b2f152016-09-28 10:23:49 +020079 // Need to hold |crit_| in order to use |frames_|, therefore we
80 // set it here in the loop instead of outside the loop in order to not
81 // acquire the lock unnecesserily.
philipel1c056252017-01-31 09:53:12 -080082 next_frame_it_ = frames_.end();
philipelbe7a9e52016-05-19 12:19:35 +020083
philipele0b2f152016-09-28 10:23:49 +020084 // |frame_it| points to the first frame after the
85 // |last_decoded_frame_it_|.
86 auto frame_it = frames_.end();
87 if (last_decoded_frame_it_ == frames_.end()) {
88 frame_it = frames_.begin();
philipelbe7a9e52016-05-19 12:19:35 +020089 } else {
philipele0b2f152016-09-28 10:23:49 +020090 frame_it = last_decoded_frame_it_;
91 ++frame_it;
philipelbe7a9e52016-05-19 12:19:35 +020092 }
philipele0b2f152016-09-28 10:23:49 +020093
94 // |continuous_end_it| points to the first frame after the
95 // |last_continuous_frame_it_|.
96 auto continuous_end_it = last_continuous_frame_it_;
97 if (continuous_end_it != frames_.end())
98 ++continuous_end_it;
99
philipel146a48b2017-04-20 04:04:38 -0700100 for (; frame_it != continuous_end_it && frame_it != frames_.end();
101 ++frame_it) {
philipel93e451b2016-10-06 12:25:13 +0200102 if (!frame_it->second.continuous ||
103 frame_it->second.num_missing_decodable > 0) {
philipele0b2f152016-09-28 10:23:49 +0200104 continue;
philipel93e451b2016-10-06 12:25:13 +0200105 }
philipele0b2f152016-09-28 10:23:49 +0200106
107 FrameObject* frame = frame_it->second.frame.get();
philipel1c056252017-01-31 09:53:12 -0800108 next_frame_it_ = frame_it;
philipele0b2f152016-09-28 10:23:49 +0200109 if (frame->RenderTime() == -1)
110 frame->SetRenderTime(timing_->RenderTimeMs(frame->timestamp, now_ms));
111 wait_ms = timing_->MaxWaitingTime(frame->RenderTime(), now_ms);
112
113 // This will cause the frame buffer to prefer high framerate rather
114 // than high resolution in the case of the decoder not decoding fast
115 // enough and the stream has multiple spatial and temporal layers.
116 if (wait_ms == 0)
117 continue;
118
119 break;
120 }
121 } // rtc::Critscope lock(&crit_);
122
philipel1c056252017-01-31 09:53:12 -0800123 wait_ms = std::min<int64_t>(wait_ms, latest_return_time_ms - now_ms);
philipele0b2f152016-09-28 10:23:49 +0200124 wait_ms = std::max<int64_t>(wait_ms, 0);
tommi0a735642017-03-14 06:23:57 -0700125 } while (new_continuous_frame_event_.Wait(wait_ms));
philipele0b2f152016-09-28 10:23:49 +0200126
philipel29f730e2017-03-15 08:10:08 -0700127 {
128 rtc::CritScope lock(&crit_);
129 now_ms = clock_->TimeInMilliseconds();
130 if (next_frame_it_ != frames_.end()) {
131 std::unique_ptr<FrameObject> frame =
132 std::move(next_frame_it_->second.frame);
philipele0b2f152016-09-28 10:23:49 +0200133
philipel29f730e2017-03-15 08:10:08 -0700134 if (!frame->delayed_by_retransmission()) {
135 int64_t frame_delay;
philipele0754302017-01-25 08:56:23 -0800136
philipel29f730e2017-03-15 08:10:08 -0700137 if (inter_frame_delay_.CalculateDelay(frame->timestamp, &frame_delay,
138 frame->ReceivedTime())) {
139 jitter_estimator_->UpdateEstimate(frame_delay, frame->size());
140 }
141
142 float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0;
143 timing_->SetJitterDelay(jitter_estimator_->GetJitterEstimate(rtt_mult));
144 timing_->UpdateCurrentDelay(frame->RenderTime(), now_ms);
gustavogbf1e08d02017-08-09 05:43:08 -0700145 } else {
146 jitter_estimator_->FrameNacked();
philipele0754302017-01-25 08:56:23 -0800147 }
148
stefan95e97542017-05-23 09:52:18 -0700149 // Gracefully handle bad RTP timestamps and render time issues.
150 if (HasBadRenderTiming(*frame, now_ms)) {
151 jitter_estimator_->Reset();
152 timing_->Reset();
153 frame->SetRenderTime(timing_->RenderTimeMs(frame->timestamp, now_ms));
154 }
155
philipel29f730e2017-03-15 08:10:08 -0700156 UpdateJitterDelay();
ilnik2edc6842017-07-06 03:06:50 -0700157 UpdateTimingFrameInfo();
philipel29f730e2017-03-15 08:10:08 -0700158 PropagateDecodability(next_frame_it_->second);
brandtr9078d8c2017-04-27 07:07:27 -0700159
160 // Sanity check for RTP timestamp monotonicity.
161 if (last_decoded_frame_it_ != frames_.end()) {
162 const FrameKey& last_decoded_frame_key = last_decoded_frame_it_->first;
163 const FrameKey& frame_key = next_frame_it_->first;
164
165 const bool frame_is_higher_spatial_layer_of_last_decoded_frame =
166 last_decoded_frame_timestamp_ == frame->timestamp &&
167 last_decoded_frame_key.picture_id == frame_key.picture_id &&
168 last_decoded_frame_key.spatial_layer < frame_key.spatial_layer;
169
170 if (AheadOrAt(last_decoded_frame_timestamp_, frame->timestamp) &&
171 !frame_is_higher_spatial_layer_of_last_decoded_frame) {
172 // TODO(brandtr): Consider clearing the entire buffer when we hit
173 // these conditions.
174 LOG(LS_WARNING) << "Frame with (timestamp:picture_id:spatial_id) ("
175 << frame->timestamp << ":" << frame->picture_id << ":"
176 << static_cast<int>(frame->spatial_layer) << ")"
177 << " sent to decoder after frame with"
178 << " (timestamp:picture_id:spatial_id) ("
179 << last_decoded_frame_timestamp_ << ":"
180 << last_decoded_frame_key.picture_id << ":"
181 << static_cast<int>(
182 last_decoded_frame_key.spatial_layer)
183 << ").";
184 }
185 }
186
philipel29f730e2017-03-15 08:10:08 -0700187 AdvanceLastDecodedFrame(next_frame_it_);
188 last_decoded_frame_timestamp_ = frame->timestamp;
189 *frame_out = std::move(frame);
190 return kFrameFound;
philipelbe7a9e52016-05-19 12:19:35 +0200191 }
tommi0a735642017-03-14 06:23:57 -0700192 }
193
194 if (latest_return_time_ms - now_ms > 0) {
philipel1c056252017-01-31 09:53:12 -0800195 // If |next_frame_it_ == frames_.end()| and there is still time left, it
196 // means that the frame buffer was cleared as the thread in this function
197 // was waiting to acquire |crit_| in order to return. Wait for the
198 // remaining time and then return.
199 return NextFrame(latest_return_time_ms - now_ms, frame_out);
philipelbe7a9e52016-05-19 12:19:35 +0200200 }
tommi0a735642017-03-14 06:23:57 -0700201
202 return kTimeout;
philipelbe7a9e52016-05-19 12:19:35 +0200203}
204
stefan95e97542017-05-23 09:52:18 -0700205bool FrameBuffer::HasBadRenderTiming(const FrameObject& frame, int64_t now_ms) {
206 // Assume that render timing errors are due to changes in the video stream.
207 int64_t render_time_ms = frame.RenderTimeMs();
208 const int64_t kMaxVideoDelayMs = 10000;
209 if (render_time_ms < 0) {
210 return true;
211 }
212 if (std::abs(render_time_ms - now_ms) > kMaxVideoDelayMs) {
213 int frame_delay = static_cast<int>(std::abs(render_time_ms - now_ms));
214 LOG(LS_WARNING) << "A frame about to be decoded is out of the configured "
215 << "delay bounds (" << frame_delay << " > "
216 << kMaxVideoDelayMs
217 << "). Resetting the video jitter buffer.";
218 return true;
219 }
220 if (static_cast<int>(timing_->TargetVideoDelay()) > kMaxVideoDelayMs) {
221 LOG(LS_WARNING) << "The video target delay has grown larger than "
222 << kMaxVideoDelayMs << " ms.";
223 return true;
224 }
225 return false;
226}
227
philipel4f6cd6a2016-08-03 10:59:32 +0200228void FrameBuffer::SetProtectionMode(VCMVideoProtection mode) {
tommidb23ea62017-03-03 07:21:18 -0800229 TRACE_EVENT0("webrtc", "FrameBuffer::SetProtectionMode");
philipel4f6cd6a2016-08-03 10:59:32 +0200230 rtc::CritScope lock(&crit_);
231 protection_mode_ = mode;
232}
233
philipel504c47d2016-06-30 17:33:02 +0200234void FrameBuffer::Start() {
tommidb23ea62017-03-03 07:21:18 -0800235 TRACE_EVENT0("webrtc", "FrameBuffer::Start");
philipel29f730e2017-03-15 08:10:08 -0700236 rtc::CritScope lock(&crit_);
237 stopped_ = false;
philipel504c47d2016-06-30 17:33:02 +0200238}
239
240void FrameBuffer::Stop() {
tommidb23ea62017-03-03 07:21:18 -0800241 TRACE_EVENT0("webrtc", "FrameBuffer::Stop");
philipel29f730e2017-03-15 08:10:08 -0700242 rtc::CritScope lock(&crit_);
243 stopped_ = true;
tommi0a735642017-03-14 06:23:57 -0700244 new_continuous_frame_event_.Set();
philipel504c47d2016-06-30 17:33:02 +0200245}
246
gustavogbf1e08d02017-08-09 05:43:08 -0700247void FrameBuffer::UpdateRtt(int64_t rtt_ms) {
248 rtc::CritScope lock(&crit_);
249 jitter_estimator_->UpdateRtt(rtt_ms);
250}
251
philipel112adf92017-06-15 09:06:21 -0700252bool FrameBuffer::ValidReferences(const FrameObject& frame) const {
253 for (size_t i = 0; i < frame.num_references; ++i) {
254 if (AheadOrAt(frame.references[i], frame.picture_id))
255 return false;
256 for (size_t j = i + 1; j < frame.num_references; ++j) {
257 if (frame.references[i] == frame.references[j])
258 return false;
259 }
260 }
261
262 if (frame.inter_layer_predicted && frame.spatial_layer == 0)
263 return false;
264
265 return true;
266}
267
gnishb2a318b2017-05-10 09:21:33 -0700268void FrameBuffer::UpdatePlayoutDelays(const FrameObject& frame) {
269 TRACE_EVENT0("webrtc", "FrameBuffer::UpdatePlayoutDelays");
270 PlayoutDelay playout_delay = frame.EncodedImage().playout_delay_;
271 if (playout_delay.min_ms >= 0)
272 timing_->set_min_playout_delay(playout_delay.min_ms);
273
274 if (playout_delay.max_ms >= 0)
275 timing_->set_max_playout_delay(playout_delay.max_ms);
276}
277
philipele0b2f152016-09-28 10:23:49 +0200278int FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) {
tommidb23ea62017-03-03 07:21:18 -0800279 TRACE_EVENT0("webrtc", "FrameBuffer::InsertFrame");
philipel93e451b2016-10-06 12:25:13 +0200280 RTC_DCHECK(frame);
philipela45102f2017-02-22 05:30:39 -0800281 if (stats_callback_)
tkchin53959fc2017-08-17 11:01:46 -0700282 stats_callback_->OnCompleteFrame(frame->num_references == 0, frame->size());
philipelbe7a9e52016-05-19 12:19:35 +0200283 FrameKey key(frame->picture_id, frame->spatial_layer);
tommi0a735642017-03-14 06:23:57 -0700284
285 rtc::CritScope lock(&crit_);
philipel29f730e2017-03-15 08:10:08 -0700286
philipele0b2f152016-09-28 10:23:49 +0200287 int last_continuous_picture_id =
288 last_continuous_frame_it_ == frames_.end()
289 ? -1
290 : last_continuous_frame_it_->first.picture_id;
291
philipel112adf92017-06-15 09:06:21 -0700292 if (!ValidReferences(*frame)) {
293 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
294 << ":" << static_cast<int>(key.spatial_layer)
295 << ") has invalid frame references, dropping frame.";
296 return last_continuous_picture_id;
297 }
298
philipele0b2f152016-09-28 10:23:49 +0200299 if (num_frames_buffered_ >= kMaxFramesBuffered) {
300 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
301 << ":" << static_cast<int>(key.spatial_layer)
302 << ") could not be inserted due to the frame "
303 << "buffer being full, dropping frame.";
304 return last_continuous_picture_id;
305 }
306
philipele0b2f152016-09-28 10:23:49 +0200307 if (last_decoded_frame_it_ != frames_.end() &&
philipelf6842692017-04-28 03:29:15 -0700308 key <= last_decoded_frame_it_->first) {
philipelfcc60062017-01-18 05:35:20 -0800309 if (AheadOf(frame->timestamp, last_decoded_frame_timestamp_) &&
tkchin53959fc2017-08-17 11:01:46 -0700310 frame->num_references == 0) {
philipelfcc60062017-01-18 05:35:20 -0800311 // If this frame has a newer timestamp but an earlier picture id then we
312 // assume there has been a jump in the picture id due to some encoder
313 // reconfiguration or some other reason. Even though this is not according
314 // to spec we can still continue to decode from this frame if it is a
315 // keyframe.
316 LOG(LS_WARNING) << "A jump in picture id was detected, clearing buffer.";
317 ClearFramesAndHistory();
318 last_continuous_picture_id = -1;
319 } else {
320 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
321 << key.picture_id << ":"
322 << static_cast<int>(key.spatial_layer)
323 << ") inserted after frame ("
324 << last_decoded_frame_it_->first.picture_id << ":"
325 << static_cast<int>(
326 last_decoded_frame_it_->first.spatial_layer)
327 << ") was handed off for decoding, dropping frame.";
328 return last_continuous_picture_id;
329 }
philipele0b2f152016-09-28 10:23:49 +0200330 }
331
philipel146a48b2017-04-20 04:04:38 -0700332 // Test if inserting this frame would cause the order of the frames to become
333 // ambiguous (covering more than half the interval of 2^16). This can happen
334 // when the picture id make large jumps mid stream.
335 if (!frames_.empty() &&
336 key < frames_.begin()->first &&
337 frames_.rbegin()->first < key) {
338 LOG(LS_WARNING) << "A jump in picture id was detected, clearing buffer.";
339 ClearFramesAndHistory();
340 last_continuous_picture_id = -1;
341 }
342
philipele0b2f152016-09-28 10:23:49 +0200343 auto info = frames_.insert(std::make_pair(key, FrameInfo())).first;
344
philipel93e451b2016-10-06 12:25:13 +0200345 if (info->second.frame) {
346 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
347 << ":" << static_cast<int>(key.spatial_layer)
348 << ") already inserted, dropping frame.";
philipele0b2f152016-09-28 10:23:49 +0200349 return last_continuous_picture_id;
350 }
351
philipel93e451b2016-10-06 12:25:13 +0200352 if (!UpdateFrameInfoWithIncomingFrame(*frame, info))
353 return last_continuous_picture_id;
gnishb2a318b2017-05-10 09:21:33 -0700354 UpdatePlayoutDelays(*frame);
philipele0b2f152016-09-28 10:23:49 +0200355 info->second.frame = std::move(frame);
356 ++num_frames_buffered_;
357
358 if (info->second.num_missing_continuous == 0) {
359 info->second.continuous = true;
360 PropagateContinuity(info);
361 last_continuous_picture_id = last_continuous_frame_it_->first.picture_id;
362
363 // Since we now have new continuous frames there might be a better frame
364 // to return from NextFrame. Signal that thread so that it again can choose
365 // which frame to return.
tommi0a735642017-03-14 06:23:57 -0700366 new_continuous_frame_event_.Set();
philipele0b2f152016-09-28 10:23:49 +0200367 }
368
369 return last_continuous_picture_id;
philipelbe7a9e52016-05-19 12:19:35 +0200370}
371
philipele0b2f152016-09-28 10:23:49 +0200372void FrameBuffer::PropagateContinuity(FrameMap::iterator start) {
tommidb23ea62017-03-03 07:21:18 -0800373 TRACE_EVENT0("webrtc", "FrameBuffer::PropagateContinuity");
philipele0b2f152016-09-28 10:23:49 +0200374 RTC_DCHECK(start->second.continuous);
375 if (last_continuous_frame_it_ == frames_.end())
376 last_continuous_frame_it_ = start;
377
378 std::queue<FrameMap::iterator> continuous_frames;
379 continuous_frames.push(start);
380
381 // A simple BFS to traverse continuous frames.
382 while (!continuous_frames.empty()) {
383 auto frame = continuous_frames.front();
384 continuous_frames.pop();
385
386 if (last_continuous_frame_it_->first < frame->first)
387 last_continuous_frame_it_ = frame;
388
389 // Loop through all dependent frames, and if that frame no longer has
390 // any unfulfilled dependencies then that frame is continuous as well.
391 for (size_t d = 0; d < frame->second.num_dependent_frames; ++d) {
392 auto frame_ref = frames_.find(frame->second.dependent_frames[d]);
philipel112adf92017-06-15 09:06:21 -0700393 RTC_DCHECK(frame_ref != frames_.end());
philipele0b2f152016-09-28 10:23:49 +0200394
philipel112adf92017-06-15 09:06:21 -0700395 // TODO(philipel): Look into why we've seen this happen.
396 if (frame_ref != frames_.end()) {
397 --frame_ref->second.num_missing_continuous;
398 if (frame_ref->second.num_missing_continuous == 0) {
399 frame_ref->second.continuous = true;
400 continuous_frames.push(frame_ref);
401 }
philipele0b2f152016-09-28 10:23:49 +0200402 }
403 }
404 }
405}
406
407void FrameBuffer::PropagateDecodability(const FrameInfo& info) {
tommidb23ea62017-03-03 07:21:18 -0800408 TRACE_EVENT0("webrtc", "FrameBuffer::PropagateDecodability");
tommie95b78b2017-05-14 07:23:11 -0700409 RTC_CHECK(info.num_dependent_frames < FrameInfo::kMaxNumDependentFrames);
philipele0b2f152016-09-28 10:23:49 +0200410 for (size_t d = 0; d < info.num_dependent_frames; ++d) {
411 auto ref_info = frames_.find(info.dependent_frames[d]);
philipel93e451b2016-10-06 12:25:13 +0200412 RTC_DCHECK(ref_info != frames_.end());
tommie95b78b2017-05-14 07:23:11 -0700413 // TODO(philipel): Look into why we've seen this happen.
414 if (ref_info != frames_.end()) {
415 RTC_DCHECK_GT(ref_info->second.num_missing_decodable, 0U);
416 --ref_info->second.num_missing_decodable;
417 }
philipele0b2f152016-09-28 10:23:49 +0200418 }
419}
420
421void FrameBuffer::AdvanceLastDecodedFrame(FrameMap::iterator decoded) {
tommidb23ea62017-03-03 07:21:18 -0800422 TRACE_EVENT0("webrtc", "FrameBuffer::AdvanceLastDecodedFrame");
philipele0b2f152016-09-28 10:23:49 +0200423 if (last_decoded_frame_it_ == frames_.end()) {
424 last_decoded_frame_it_ = frames_.begin();
425 } else {
426 RTC_DCHECK(last_decoded_frame_it_->first < decoded->first);
427 ++last_decoded_frame_it_;
428 }
429 --num_frames_buffered_;
430 ++num_frames_history_;
431
432 // First, delete non-decoded frames from the history.
433 while (last_decoded_frame_it_ != decoded) {
434 if (last_decoded_frame_it_->second.frame)
435 --num_frames_buffered_;
436 last_decoded_frame_it_ = frames_.erase(last_decoded_frame_it_);
philipelbe7a9e52016-05-19 12:19:35 +0200437 }
438
philipele0b2f152016-09-28 10:23:49 +0200439 // Then remove old history if we have too much history saved.
440 if (num_frames_history_ > kMaxFramesHistory) {
441 frames_.erase(frames_.begin());
442 --num_frames_history_;
443 }
444}
445
446bool FrameBuffer::UpdateFrameInfoWithIncomingFrame(const FrameObject& frame,
447 FrameMap::iterator info) {
tommidb23ea62017-03-03 07:21:18 -0800448 TRACE_EVENT0("webrtc", "FrameBuffer::UpdateFrameInfoWithIncomingFrame");
philipele0b2f152016-09-28 10:23:49 +0200449 FrameKey key(frame.picture_id, frame.spatial_layer);
450 info->second.num_missing_continuous = frame.num_references;
451 info->second.num_missing_decodable = frame.num_references;
452
453 RTC_DCHECK(last_decoded_frame_it_ == frames_.end() ||
454 last_decoded_frame_it_->first < info->first);
455
456 // Check how many dependencies that have already been fulfilled.
457 for (size_t i = 0; i < frame.num_references; ++i) {
458 FrameKey ref_key(frame.references[i], frame.spatial_layer);
459 auto ref_info = frames_.find(ref_key);
460
461 // Does |frame| depend on a frame earlier than the last decoded frame?
462 if (last_decoded_frame_it_ != frames_.end() &&
463 ref_key <= last_decoded_frame_it_->first) {
464 if (ref_info == frames_.end()) {
philipel65e1f942017-07-24 08:26:53 -0700465 int64_t now_ms = clock_->TimeInMilliseconds();
466 if (last_log_non_decoded_ms_ + kLogNonDecodedIntervalMs < now_ms) {
467 LOG(LS_WARNING)
468 << "Frame with (picture_id:spatial_id) (" << key.picture_id << ":"
469 << static_cast<int>(key.spatial_layer)
470 << ") depends on a non-decoded frame more previous than"
471 << " the last decoded frame, dropping frame.";
472 last_log_non_decoded_ms_ = now_ms;
473 }
philipele0b2f152016-09-28 10:23:49 +0200474 return false;
475 }
476
477 --info->second.num_missing_continuous;
478 --info->second.num_missing_decodable;
479 } else {
480 if (ref_info == frames_.end())
481 ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
482
483 if (ref_info->second.continuous)
484 --info->second.num_missing_continuous;
485
486 // Add backwards reference so |frame| can be updated when new
487 // frames are inserted or decoded.
488 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
489 key;
tommie95b78b2017-05-14 07:23:11 -0700490 RTC_DCHECK_LT(ref_info->second.num_dependent_frames,
491 (FrameInfo::kMaxNumDependentFrames - 1));
492 // TODO(philipel): Look into why this could happen and handle
493 // appropriately.
494 if (ref_info->second.num_dependent_frames <
495 (FrameInfo::kMaxNumDependentFrames - 1)) {
496 ++ref_info->second.num_dependent_frames;
497 }
philipele0b2f152016-09-28 10:23:49 +0200498 }
philipel93e451b2016-10-06 12:25:13 +0200499 RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
500 ref_info->second.num_missing_decodable);
philipelbe7a9e52016-05-19 12:19:35 +0200501 }
502
philipele0b2f152016-09-28 10:23:49 +0200503 // Check if we have the lower spatial layer frame.
philipelbe7a9e52016-05-19 12:19:35 +0200504 if (frame.inter_layer_predicted) {
philipele0b2f152016-09-28 10:23:49 +0200505 ++info->second.num_missing_continuous;
506 ++info->second.num_missing_decodable;
507
philipelbe7a9e52016-05-19 12:19:35 +0200508 FrameKey ref_key(frame.picture_id, frame.spatial_layer - 1);
philipele0b2f152016-09-28 10:23:49 +0200509 // Gets or create the FrameInfo for the referenced frame.
510 auto ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
511 if (ref_info->second.continuous)
512 --info->second.num_missing_continuous;
513
514 if (ref_info == last_decoded_frame_it_) {
515 --info->second.num_missing_decodable;
516 } else {
517 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
518 key;
519 ++ref_info->second.num_dependent_frames;
520 }
philipel93e451b2016-10-06 12:25:13 +0200521 RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
522 ref_info->second.num_missing_decodable);
philipelbe7a9e52016-05-19 12:19:35 +0200523 }
524
philipel93e451b2016-10-06 12:25:13 +0200525 RTC_DCHECK_LE(info->second.num_missing_continuous,
526 info->second.num_missing_decodable);
527
philipelbe7a9e52016-05-19 12:19:35 +0200528 return true;
529}
530
philipelbe742702016-11-30 01:31:40 -0800531void FrameBuffer::UpdateJitterDelay() {
tommidb23ea62017-03-03 07:21:18 -0800532 TRACE_EVENT0("webrtc", "FrameBuffer::UpdateJitterDelay");
philipela45102f2017-02-22 05:30:39 -0800533 if (!stats_callback_)
534 return;
philipelbe742702016-11-30 01:31:40 -0800535
philipela45102f2017-02-22 05:30:39 -0800536 int decode_ms;
537 int max_decode_ms;
538 int current_delay_ms;
539 int target_delay_ms;
540 int jitter_buffer_ms;
541 int min_playout_delay_ms;
542 int render_delay_ms;
543 if (timing_->GetTimings(&decode_ms, &max_decode_ms, &current_delay_ms,
544 &target_delay_ms, &jitter_buffer_ms,
545 &min_playout_delay_ms, &render_delay_ms)) {
546 stats_callback_->OnFrameBufferTimingsUpdated(
547 decode_ms, max_decode_ms, current_delay_ms, target_delay_ms,
548 jitter_buffer_ms, min_playout_delay_ms, render_delay_ms);
philipelbe742702016-11-30 01:31:40 -0800549 }
philipel266f0a42016-11-28 08:49:07 -0800550}
551
ilnik2edc6842017-07-06 03:06:50 -0700552void FrameBuffer::UpdateTimingFrameInfo() {
553 TRACE_EVENT0("webrtc", "FrameBuffer::UpdateTimingFrameInfo");
554 rtc::Optional<TimingFrameInfo> info = timing_->GetTimingFrameInfo();
555 if (info)
556 stats_callback_->OnTimingFrameInfoUpdated(*info);
557}
558
philipelfcc60062017-01-18 05:35:20 -0800559void FrameBuffer::ClearFramesAndHistory() {
ilnik2edc6842017-07-06 03:06:50 -0700560 TRACE_EVENT0("webrtc", "FrameBuffer::ClearFramesAndHistory");
philipelfcc60062017-01-18 05:35:20 -0800561 frames_.clear();
562 last_decoded_frame_it_ = frames_.end();
563 last_continuous_frame_it_ = frames_.end();
philipel1c056252017-01-31 09:53:12 -0800564 next_frame_it_ = frames_.end();
philipelfcc60062017-01-18 05:35:20 -0800565 num_frames_history_ = 0;
566 num_frames_buffered_ = 0;
567}
568
philipelbe7a9e52016-05-19 12:19:35 +0200569} // namespace video_coding
570} // namespace webrtc