blob: daac7d5c2b2d691e84a7c0a83e93ec3b20e3823f [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
17#include "webrtc/base/checks.h"
philipele0b2f152016-09-28 10:23:49 +020018#include "webrtc/base/logging.h"
philipelbe7a9e52016-05-19 12:19:35 +020019#include "webrtc/modules/video_coding/jitter_estimator.h"
philipelbe7a9e52016-05-19 12:19:35 +020020#include "webrtc/modules/video_coding/timing.h"
21#include "webrtc/system_wrappers/include/clock.h"
22
23namespace webrtc {
24namespace video_coding {
25
26namespace {
philipele0b2f152016-09-28 10:23:49 +020027// Max number of frames the buffer will hold.
28constexpr int kMaxFramesBuffered = 600;
philipelbe7a9e52016-05-19 12:19:35 +020029
philipele0b2f152016-09-28 10:23:49 +020030// Max number of decoded frame info that will be saved.
31constexpr int kMaxFramesHistory = 20;
philipelbe7a9e52016-05-19 12:19:35 +020032} // namespace
33
philipelbe7a9e52016-05-19 12:19:35 +020034FrameBuffer::FrameBuffer(Clock* clock,
35 VCMJitterEstimator* jitter_estimator,
philipel4f6cd6a2016-08-03 10:59:32 +020036 VCMTiming* timing)
philipelbe7a9e52016-05-19 12:19:35 +020037 : clock_(clock),
philipele0b2f152016-09-28 10:23:49 +020038 new_countinuous_frame_event_(false, false),
philipelbe7a9e52016-05-19 12:19:35 +020039 jitter_estimator_(jitter_estimator),
40 timing_(timing),
philipel4f6cd6a2016-08-03 10:59:32 +020041 inter_frame_delay_(clock_->TimeInMilliseconds()),
philipele0b2f152016-09-28 10:23:49 +020042 last_decoded_frame_it_(frames_.end()),
43 last_continuous_frame_it_(frames_.end()),
44 num_frames_history_(0),
45 num_frames_buffered_(0),
philipel4f6cd6a2016-08-03 10:59:32 +020046 stopped_(false),
47 protection_mode_(kProtectionNack) {}
philipelbe7a9e52016-05-19 12:19:35 +020048
philipel75562822016-09-05 10:57:41 +020049FrameBuffer::ReturnReason FrameBuffer::NextFrame(
50 int64_t max_wait_time_ms,
51 std::unique_ptr<FrameObject>* frame_out) {
philipelbe7a9e52016-05-19 12:19:35 +020052 int64_t latest_return_time = clock_->TimeInMilliseconds() + max_wait_time_ms;
philipel504c47d2016-06-30 17:33:02 +020053 int64_t wait_ms = max_wait_time_ms;
philipele0b2f152016-09-28 10:23:49 +020054 FrameMap::iterator next_frame_it;
55
56 do {
57 int64_t now_ms = clock_->TimeInMilliseconds();
philipel504c47d2016-06-30 17:33:02 +020058 {
59 rtc::CritScope lock(&crit_);
philipele0b2f152016-09-28 10:23:49 +020060 new_countinuous_frame_event_.Reset();
philipel504c47d2016-06-30 17:33:02 +020061 if (stopped_)
philipel75562822016-09-05 10:57:41 +020062 return kStopped;
philipelbe7a9e52016-05-19 12:19:35 +020063
philipel504c47d2016-06-30 17:33:02 +020064 wait_ms = max_wait_time_ms;
philipele0b2f152016-09-28 10:23:49 +020065
66 // Need to hold |crit_| in order to use |frames_|, therefore we
67 // set it here in the loop instead of outside the loop in order to not
68 // acquire the lock unnecesserily.
philipel4f6cd6a2016-08-03 10:59:32 +020069 next_frame_it = frames_.end();
philipelbe7a9e52016-05-19 12:19:35 +020070
philipele0b2f152016-09-28 10:23:49 +020071 // |frame_it| points to the first frame after the
72 // |last_decoded_frame_it_|.
73 auto frame_it = frames_.end();
74 if (last_decoded_frame_it_ == frames_.end()) {
75 frame_it = frames_.begin();
philipelbe7a9e52016-05-19 12:19:35 +020076 } else {
philipele0b2f152016-09-28 10:23:49 +020077 frame_it = last_decoded_frame_it_;
78 ++frame_it;
philipelbe7a9e52016-05-19 12:19:35 +020079 }
philipele0b2f152016-09-28 10:23:49 +020080
81 // |continuous_end_it| points to the first frame after the
82 // |last_continuous_frame_it_|.
83 auto continuous_end_it = last_continuous_frame_it_;
84 if (continuous_end_it != frames_.end())
85 ++continuous_end_it;
86
87 for (; frame_it != continuous_end_it; ++frame_it) {
philipel93e451b2016-10-06 12:25:13 +020088 if (!frame_it->second.continuous ||
89 frame_it->second.num_missing_decodable > 0) {
philipele0b2f152016-09-28 10:23:49 +020090 continue;
philipel93e451b2016-10-06 12:25:13 +020091 }
philipele0b2f152016-09-28 10:23:49 +020092
93 FrameObject* frame = frame_it->second.frame.get();
94 next_frame_it = frame_it;
95 if (frame->RenderTime() == -1)
96 frame->SetRenderTime(timing_->RenderTimeMs(frame->timestamp, now_ms));
97 wait_ms = timing_->MaxWaitingTime(frame->RenderTime(), now_ms);
98
99 // This will cause the frame buffer to prefer high framerate rather
100 // than high resolution in the case of the decoder not decoding fast
101 // enough and the stream has multiple spatial and temporal layers.
102 if (wait_ms == 0)
103 continue;
104
105 break;
106 }
107 } // rtc::Critscope lock(&crit_);
108
109 wait_ms = std::min<int64_t>(wait_ms, latest_return_time - now_ms);
110 wait_ms = std::max<int64_t>(wait_ms, 0);
111 } while (new_countinuous_frame_event_.Wait(wait_ms));
112
113 rtc::CritScope lock(&crit_);
114 if (next_frame_it != frames_.end()) {
115 std::unique_ptr<FrameObject> frame = std::move(next_frame_it->second.frame);
116 int64_t received_time = frame->ReceivedTime();
117 uint32_t timestamp = frame->Timestamp();
118
119 int64_t frame_delay;
120 if (inter_frame_delay_.CalculateDelay(timestamp, &frame_delay,
121 received_time)) {
nisse37abf532016-10-28 00:37:29 -0700122 jitter_estimator_->UpdateEstimate(frame_delay, frame->size());
philipelbe7a9e52016-05-19 12:19:35 +0200123 }
philipele0b2f152016-09-28 10:23:49 +0200124 float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0;
125 timing_->SetJitterDelay(jitter_estimator_->GetJitterEstimate(rtt_mult));
126 timing_->UpdateCurrentDelay(frame->RenderTime(),
127 clock_->TimeInMilliseconds());
128
129 PropagateDecodability(next_frame_it->second);
130 AdvanceLastDecodedFrame(next_frame_it);
131 *frame_out = std::move(frame);
132 return kFrameFound;
133 } else {
134 return kTimeout;
philipelbe7a9e52016-05-19 12:19:35 +0200135 }
136}
137
philipel4f6cd6a2016-08-03 10:59:32 +0200138void FrameBuffer::SetProtectionMode(VCMVideoProtection mode) {
139 rtc::CritScope lock(&crit_);
140 protection_mode_ = mode;
141}
142
philipel504c47d2016-06-30 17:33:02 +0200143void FrameBuffer::Start() {
144 rtc::CritScope lock(&crit_);
145 stopped_ = false;
146}
147
148void FrameBuffer::Stop() {
149 rtc::CritScope lock(&crit_);
150 stopped_ = true;
philipele0b2f152016-09-28 10:23:49 +0200151 new_countinuous_frame_event_.Set();
philipel504c47d2016-06-30 17:33:02 +0200152}
153
philipele0b2f152016-09-28 10:23:49 +0200154int FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) {
philipelbe7a9e52016-05-19 12:19:35 +0200155 rtc::CritScope lock(&crit_);
philipel93e451b2016-10-06 12:25:13 +0200156 RTC_DCHECK(frame);
157
philipelbe7a9e52016-05-19 12:19:35 +0200158 FrameKey key(frame->picture_id, frame->spatial_layer);
philipele0b2f152016-09-28 10:23:49 +0200159 int last_continuous_picture_id =
160 last_continuous_frame_it_ == frames_.end()
161 ? -1
162 : last_continuous_frame_it_->first.picture_id;
163
164 if (num_frames_buffered_ >= kMaxFramesBuffered) {
165 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
166 << ":" << static_cast<int>(key.spatial_layer)
167 << ") could not be inserted due to the frame "
168 << "buffer being full, dropping frame.";
169 return last_continuous_picture_id;
170 }
171
172 if (frame->inter_layer_predicted && frame->spatial_layer == 0) {
173 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
174 << ":" << static_cast<int>(key.spatial_layer)
175 << ") is marked as inter layer predicted, dropping frame.";
176 return last_continuous_picture_id;
177 }
178
179 if (last_decoded_frame_it_ != frames_.end() &&
180 key < last_decoded_frame_it_->first) {
181 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
182 << ":" << static_cast<int>(key.spatial_layer)
183 << ") inserted after frame ("
184 << last_decoded_frame_it_->first.picture_id << ":"
185 << static_cast<int>(
186 last_decoded_frame_it_->first.spatial_layer)
187 << ") was handed off for decoding, dropping frame.";
188 return last_continuous_picture_id;
189 }
190
191 auto info = frames_.insert(std::make_pair(key, FrameInfo())).first;
192
philipel93e451b2016-10-06 12:25:13 +0200193 if (info->second.frame) {
194 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
195 << ":" << static_cast<int>(key.spatial_layer)
196 << ") already inserted, dropping frame.";
philipele0b2f152016-09-28 10:23:49 +0200197 return last_continuous_picture_id;
198 }
199
philipel93e451b2016-10-06 12:25:13 +0200200 if (!UpdateFrameInfoWithIncomingFrame(*frame, info))
201 return last_continuous_picture_id;
202
philipele0b2f152016-09-28 10:23:49 +0200203 info->second.frame = std::move(frame);
204 ++num_frames_buffered_;
205
206 if (info->second.num_missing_continuous == 0) {
207 info->second.continuous = true;
208 PropagateContinuity(info);
209 last_continuous_picture_id = last_continuous_frame_it_->first.picture_id;
210
211 // Since we now have new continuous frames there might be a better frame
212 // to return from NextFrame. Signal that thread so that it again can choose
213 // which frame to return.
214 new_countinuous_frame_event_.Set();
215 }
216
217 return last_continuous_picture_id;
philipelbe7a9e52016-05-19 12:19:35 +0200218}
219
philipele0b2f152016-09-28 10:23:49 +0200220void FrameBuffer::PropagateContinuity(FrameMap::iterator start) {
221 RTC_DCHECK(start->second.continuous);
222 if (last_continuous_frame_it_ == frames_.end())
223 last_continuous_frame_it_ = start;
224
225 std::queue<FrameMap::iterator> continuous_frames;
226 continuous_frames.push(start);
227
228 // A simple BFS to traverse continuous frames.
229 while (!continuous_frames.empty()) {
230 auto frame = continuous_frames.front();
231 continuous_frames.pop();
232
233 if (last_continuous_frame_it_->first < frame->first)
234 last_continuous_frame_it_ = frame;
235
236 // Loop through all dependent frames, and if that frame no longer has
237 // any unfulfilled dependencies then that frame is continuous as well.
238 for (size_t d = 0; d < frame->second.num_dependent_frames; ++d) {
239 auto frame_ref = frames_.find(frame->second.dependent_frames[d]);
240 --frame_ref->second.num_missing_continuous;
241
242 if (frame_ref->second.num_missing_continuous == 0) {
243 frame_ref->second.continuous = true;
244 continuous_frames.push(frame_ref);
245 }
246 }
247 }
248}
249
250void FrameBuffer::PropagateDecodability(const FrameInfo& info) {
251 for (size_t d = 0; d < info.num_dependent_frames; ++d) {
252 auto ref_info = frames_.find(info.dependent_frames[d]);
philipel93e451b2016-10-06 12:25:13 +0200253 RTC_DCHECK(ref_info != frames_.end());
philipele0b2f152016-09-28 10:23:49 +0200254 RTC_DCHECK_GT(ref_info->second.num_missing_decodable, 0U);
255 --ref_info->second.num_missing_decodable;
256 }
257}
258
259void FrameBuffer::AdvanceLastDecodedFrame(FrameMap::iterator decoded) {
260 if (last_decoded_frame_it_ == frames_.end()) {
261 last_decoded_frame_it_ = frames_.begin();
262 } else {
263 RTC_DCHECK(last_decoded_frame_it_->first < decoded->first);
264 ++last_decoded_frame_it_;
265 }
266 --num_frames_buffered_;
267 ++num_frames_history_;
268
269 // First, delete non-decoded frames from the history.
270 while (last_decoded_frame_it_ != decoded) {
271 if (last_decoded_frame_it_->second.frame)
272 --num_frames_buffered_;
273 last_decoded_frame_it_ = frames_.erase(last_decoded_frame_it_);
philipelbe7a9e52016-05-19 12:19:35 +0200274 }
275
philipele0b2f152016-09-28 10:23:49 +0200276 // Then remove old history if we have too much history saved.
277 if (num_frames_history_ > kMaxFramesHistory) {
278 frames_.erase(frames_.begin());
279 --num_frames_history_;
280 }
281}
282
283bool FrameBuffer::UpdateFrameInfoWithIncomingFrame(const FrameObject& frame,
284 FrameMap::iterator info) {
285 FrameKey key(frame.picture_id, frame.spatial_layer);
286 info->second.num_missing_continuous = frame.num_references;
287 info->second.num_missing_decodable = frame.num_references;
288
289 RTC_DCHECK(last_decoded_frame_it_ == frames_.end() ||
290 last_decoded_frame_it_->first < info->first);
291
292 // Check how many dependencies that have already been fulfilled.
293 for (size_t i = 0; i < frame.num_references; ++i) {
294 FrameKey ref_key(frame.references[i], frame.spatial_layer);
295 auto ref_info = frames_.find(ref_key);
296
297 // Does |frame| depend on a frame earlier than the last decoded frame?
298 if (last_decoded_frame_it_ != frames_.end() &&
299 ref_key <= last_decoded_frame_it_->first) {
300 if (ref_info == frames_.end()) {
301 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
302 << key.picture_id << ":"
303 << static_cast<int>(key.spatial_layer)
304 << " depends on a non-decoded frame more previous than "
305 << "the last decoded frame, dropping frame.";
306 return false;
307 }
308
309 --info->second.num_missing_continuous;
310 --info->second.num_missing_decodable;
311 } else {
312 if (ref_info == frames_.end())
313 ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
314
315 if (ref_info->second.continuous)
316 --info->second.num_missing_continuous;
317
318 // Add backwards reference so |frame| can be updated when new
319 // frames are inserted or decoded.
320 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
321 key;
322 ++ref_info->second.num_dependent_frames;
323 }
philipel93e451b2016-10-06 12:25:13 +0200324 RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
325 ref_info->second.num_missing_decodable);
philipelbe7a9e52016-05-19 12:19:35 +0200326 }
327
philipele0b2f152016-09-28 10:23:49 +0200328 // Check if we have the lower spatial layer frame.
philipelbe7a9e52016-05-19 12:19:35 +0200329 if (frame.inter_layer_predicted) {
philipele0b2f152016-09-28 10:23:49 +0200330 ++info->second.num_missing_continuous;
331 ++info->second.num_missing_decodable;
332
philipelbe7a9e52016-05-19 12:19:35 +0200333 FrameKey ref_key(frame.picture_id, frame.spatial_layer - 1);
philipele0b2f152016-09-28 10:23:49 +0200334 // Gets or create the FrameInfo for the referenced frame.
335 auto ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
336 if (ref_info->second.continuous)
337 --info->second.num_missing_continuous;
338
339 if (ref_info == last_decoded_frame_it_) {
340 --info->second.num_missing_decodable;
341 } else {
342 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
343 key;
344 ++ref_info->second.num_dependent_frames;
345 }
philipel93e451b2016-10-06 12:25:13 +0200346 RTC_DCHECK_LE(ref_info->second.num_missing_continuous,
347 ref_info->second.num_missing_decodable);
philipelbe7a9e52016-05-19 12:19:35 +0200348 }
349
philipel93e451b2016-10-06 12:25:13 +0200350 RTC_DCHECK_LE(info->second.num_missing_continuous,
351 info->second.num_missing_decodable);
352
philipelbe7a9e52016-05-19 12:19:35 +0200353 return true;
354}
355
356} // namespace video_coding
357} // namespace webrtc