blob: b2b4c213fe56122ede4477231aaae6378bc4e82c [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) {
88 if (frame_it->second.num_missing_decodable > 0)
89 continue;
90
91 FrameObject* frame = frame_it->second.frame.get();
92 next_frame_it = frame_it;
93 if (frame->RenderTime() == -1)
94 frame->SetRenderTime(timing_->RenderTimeMs(frame->timestamp, now_ms));
95 wait_ms = timing_->MaxWaitingTime(frame->RenderTime(), now_ms);
96
97 // This will cause the frame buffer to prefer high framerate rather
98 // than high resolution in the case of the decoder not decoding fast
99 // enough and the stream has multiple spatial and temporal layers.
100 if (wait_ms == 0)
101 continue;
102
103 break;
104 }
105 } // rtc::Critscope lock(&crit_);
106
107 wait_ms = std::min<int64_t>(wait_ms, latest_return_time - now_ms);
108 wait_ms = std::max<int64_t>(wait_ms, 0);
109 } while (new_countinuous_frame_event_.Wait(wait_ms));
110
111 rtc::CritScope lock(&crit_);
112 if (next_frame_it != frames_.end()) {
113 std::unique_ptr<FrameObject> frame = std::move(next_frame_it->second.frame);
114 int64_t received_time = frame->ReceivedTime();
115 uint32_t timestamp = frame->Timestamp();
116
117 int64_t frame_delay;
118 if (inter_frame_delay_.CalculateDelay(timestamp, &frame_delay,
119 received_time)) {
120 jitter_estimator_->UpdateEstimate(frame_delay, frame->size);
philipelbe7a9e52016-05-19 12:19:35 +0200121 }
philipele0b2f152016-09-28 10:23:49 +0200122 float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0;
123 timing_->SetJitterDelay(jitter_estimator_->GetJitterEstimate(rtt_mult));
124 timing_->UpdateCurrentDelay(frame->RenderTime(),
125 clock_->TimeInMilliseconds());
126
127 PropagateDecodability(next_frame_it->second);
128 AdvanceLastDecodedFrame(next_frame_it);
129 *frame_out = std::move(frame);
130 return kFrameFound;
131 } else {
132 return kTimeout;
philipelbe7a9e52016-05-19 12:19:35 +0200133 }
134}
135
philipel4f6cd6a2016-08-03 10:59:32 +0200136void FrameBuffer::SetProtectionMode(VCMVideoProtection mode) {
137 rtc::CritScope lock(&crit_);
138 protection_mode_ = mode;
139}
140
philipel504c47d2016-06-30 17:33:02 +0200141void FrameBuffer::Start() {
142 rtc::CritScope lock(&crit_);
143 stopped_ = false;
144}
145
146void FrameBuffer::Stop() {
147 rtc::CritScope lock(&crit_);
148 stopped_ = true;
philipele0b2f152016-09-28 10:23:49 +0200149 new_countinuous_frame_event_.Set();
philipel504c47d2016-06-30 17:33:02 +0200150}
151
philipele0b2f152016-09-28 10:23:49 +0200152int FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) {
philipelbe7a9e52016-05-19 12:19:35 +0200153 rtc::CritScope lock(&crit_);
philipelbe7a9e52016-05-19 12:19:35 +0200154 FrameKey key(frame->picture_id, frame->spatial_layer);
philipele0b2f152016-09-28 10:23:49 +0200155 int last_continuous_picture_id =
156 last_continuous_frame_it_ == frames_.end()
157 ? -1
158 : last_continuous_frame_it_->first.picture_id;
159
160 if (num_frames_buffered_ >= kMaxFramesBuffered) {
161 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
162 << ":" << static_cast<int>(key.spatial_layer)
163 << ") could not be inserted due to the frame "
164 << "buffer being full, dropping frame.";
165 return last_continuous_picture_id;
166 }
167
168 if (frame->inter_layer_predicted && frame->spatial_layer == 0) {
169 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
170 << ":" << static_cast<int>(key.spatial_layer)
171 << ") is marked as inter layer predicted, dropping frame.";
172 return last_continuous_picture_id;
173 }
174
175 if (last_decoded_frame_it_ != frames_.end() &&
176 key < last_decoded_frame_it_->first) {
177 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) (" << key.picture_id
178 << ":" << static_cast<int>(key.spatial_layer)
179 << ") inserted after frame ("
180 << last_decoded_frame_it_->first.picture_id << ":"
181 << static_cast<int>(
182 last_decoded_frame_it_->first.spatial_layer)
183 << ") was handed off for decoding, dropping frame.";
184 return last_continuous_picture_id;
185 }
186
187 auto info = frames_.insert(std::make_pair(key, FrameInfo())).first;
188
189 if (!UpdateFrameInfoWithIncomingFrame(*frame, info)) {
190 frames_.erase(info);
191 return last_continuous_picture_id;
192 }
193
194 info->second.frame = std::move(frame);
195 ++num_frames_buffered_;
196
197 if (info->second.num_missing_continuous == 0) {
198 info->second.continuous = true;
199 PropagateContinuity(info);
200 last_continuous_picture_id = last_continuous_frame_it_->first.picture_id;
201
202 // Since we now have new continuous frames there might be a better frame
203 // to return from NextFrame. Signal that thread so that it again can choose
204 // which frame to return.
205 new_countinuous_frame_event_.Set();
206 }
207
208 return last_continuous_picture_id;
philipelbe7a9e52016-05-19 12:19:35 +0200209}
210
philipele0b2f152016-09-28 10:23:49 +0200211void FrameBuffer::PropagateContinuity(FrameMap::iterator start) {
212 RTC_DCHECK(start->second.continuous);
213 if (last_continuous_frame_it_ == frames_.end())
214 last_continuous_frame_it_ = start;
215
216 std::queue<FrameMap::iterator> continuous_frames;
217 continuous_frames.push(start);
218
219 // A simple BFS to traverse continuous frames.
220 while (!continuous_frames.empty()) {
221 auto frame = continuous_frames.front();
222 continuous_frames.pop();
223
224 if (last_continuous_frame_it_->first < frame->first)
225 last_continuous_frame_it_ = frame;
226
227 // Loop through all dependent frames, and if that frame no longer has
228 // any unfulfilled dependencies then that frame is continuous as well.
229 for (size_t d = 0; d < frame->second.num_dependent_frames; ++d) {
230 auto frame_ref = frames_.find(frame->second.dependent_frames[d]);
231 --frame_ref->second.num_missing_continuous;
232
233 if (frame_ref->second.num_missing_continuous == 0) {
234 frame_ref->second.continuous = true;
235 continuous_frames.push(frame_ref);
236 }
237 }
238 }
239}
240
241void FrameBuffer::PropagateDecodability(const FrameInfo& info) {
242 for (size_t d = 0; d < info.num_dependent_frames; ++d) {
243 auto ref_info = frames_.find(info.dependent_frames[d]);
244 RTC_DCHECK_GT(ref_info->second.num_missing_decodable, 0U);
245 --ref_info->second.num_missing_decodable;
246 }
247}
248
249void FrameBuffer::AdvanceLastDecodedFrame(FrameMap::iterator decoded) {
250 if (last_decoded_frame_it_ == frames_.end()) {
251 last_decoded_frame_it_ = frames_.begin();
252 } else {
253 RTC_DCHECK(last_decoded_frame_it_->first < decoded->first);
254 ++last_decoded_frame_it_;
255 }
256 --num_frames_buffered_;
257 ++num_frames_history_;
258
259 // First, delete non-decoded frames from the history.
260 while (last_decoded_frame_it_ != decoded) {
261 if (last_decoded_frame_it_->second.frame)
262 --num_frames_buffered_;
263 last_decoded_frame_it_ = frames_.erase(last_decoded_frame_it_);
philipelbe7a9e52016-05-19 12:19:35 +0200264 }
265
philipele0b2f152016-09-28 10:23:49 +0200266 // Then remove old history if we have too much history saved.
267 if (num_frames_history_ > kMaxFramesHistory) {
268 frames_.erase(frames_.begin());
269 --num_frames_history_;
270 }
271}
272
273bool FrameBuffer::UpdateFrameInfoWithIncomingFrame(const FrameObject& frame,
274 FrameMap::iterator info) {
275 FrameKey key(frame.picture_id, frame.spatial_layer);
276 info->second.num_missing_continuous = frame.num_references;
277 info->second.num_missing_decodable = frame.num_references;
278
279 RTC_DCHECK(last_decoded_frame_it_ == frames_.end() ||
280 last_decoded_frame_it_->first < info->first);
281
282 // Check how many dependencies that have already been fulfilled.
283 for (size_t i = 0; i < frame.num_references; ++i) {
284 FrameKey ref_key(frame.references[i], frame.spatial_layer);
285 auto ref_info = frames_.find(ref_key);
286
287 // Does |frame| depend on a frame earlier than the last decoded frame?
288 if (last_decoded_frame_it_ != frames_.end() &&
289 ref_key <= last_decoded_frame_it_->first) {
290 if (ref_info == frames_.end()) {
291 LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
292 << key.picture_id << ":"
293 << static_cast<int>(key.spatial_layer)
294 << " depends on a non-decoded frame more previous than "
295 << "the last decoded frame, dropping frame.";
296 return false;
297 }
298
299 --info->second.num_missing_continuous;
300 --info->second.num_missing_decodable;
301 } else {
302 if (ref_info == frames_.end())
303 ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
304
305 if (ref_info->second.continuous)
306 --info->second.num_missing_continuous;
307
308 // Add backwards reference so |frame| can be updated when new
309 // frames are inserted or decoded.
310 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
311 key;
312 ++ref_info->second.num_dependent_frames;
313 }
philipelbe7a9e52016-05-19 12:19:35 +0200314 }
315
philipele0b2f152016-09-28 10:23:49 +0200316 // Check if we have the lower spatial layer frame.
philipelbe7a9e52016-05-19 12:19:35 +0200317 if (frame.inter_layer_predicted) {
philipele0b2f152016-09-28 10:23:49 +0200318 ++info->second.num_missing_continuous;
319 ++info->second.num_missing_decodable;
320
philipelbe7a9e52016-05-19 12:19:35 +0200321 FrameKey ref_key(frame.picture_id, frame.spatial_layer - 1);
philipele0b2f152016-09-28 10:23:49 +0200322 // Gets or create the FrameInfo for the referenced frame.
323 auto ref_info = frames_.insert(std::make_pair(ref_key, FrameInfo())).first;
324 if (ref_info->second.continuous)
325 --info->second.num_missing_continuous;
326
327 if (ref_info == last_decoded_frame_it_) {
328 --info->second.num_missing_decodable;
329 } else {
330 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] =
331 key;
332 ++ref_info->second.num_dependent_frames;
333 }
philipelbe7a9e52016-05-19 12:19:35 +0200334 }
335
336 return true;
337}
338
339} // namespace video_coding
340} // namespace webrtc