blob: 53b30c9240558aa763aad19411ebf0af782c8384 [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>
14
15#include "webrtc/base/checks.h"
16#include "webrtc/modules/video_coding/frame_object.h"
17#include "webrtc/modules/video_coding/jitter_estimator.h"
18#include "webrtc/modules/video_coding/sequence_number_util.h"
19#include "webrtc/modules/video_coding/timing.h"
20#include "webrtc/system_wrappers/include/clock.h"
21
22namespace webrtc {
23namespace video_coding {
24
25namespace {
26// The maximum age of decoded frames tracked by frame buffer, compared to
27// |newest_picture_id_|.
28constexpr int kMaxFrameAge = 4096;
29
30// The maximum number of decoded frames being tracked by the frame buffer.
31constexpr int kMaxNumHistoryFrames = 256;
32} // namespace
33
34bool FrameBuffer::FrameComp::operator()(const FrameKey& f1,
35 const FrameKey& f2) const {
36 // first = picture id
37 // second = spatial layer
38 if (f1.first == f2.first)
39 return f1.second < f2.second;
40 return AheadOf(f2.first, f1.first);
41}
42
43FrameBuffer::FrameBuffer(Clock* clock,
44 VCMJitterEstimator* jitter_estimator,
45 const VCMTiming* timing)
46 : clock_(clock),
47 frame_inserted_event_(false, false),
48 jitter_estimator_(jitter_estimator),
49 timing_(timing),
philipel504c47d2016-06-30 17:33:02 +020050 newest_picture_id_(-1),
51 stopped_(false) {}
philipelbe7a9e52016-05-19 12:19:35 +020052
53std::unique_ptr<FrameObject> FrameBuffer::NextFrame(int64_t max_wait_time_ms) {
54 int64_t latest_return_time = clock_->TimeInMilliseconds() + max_wait_time_ms;
philipel504c47d2016-06-30 17:33:02 +020055 int64_t now = clock_->TimeInMilliseconds();
56 int64_t wait_ms = max_wait_time_ms;
philipelbe7a9e52016-05-19 12:19:35 +020057 while (true) {
philipel504c47d2016-06-30 17:33:02 +020058 std::map<FrameKey, std::unique_ptr<FrameObject>, FrameComp>::iterator
59 next_frame;
60 {
61 rtc::CritScope lock(&crit_);
62 frame_inserted_event_.Reset();
63 if (stopped_)
64 return std::unique_ptr<FrameObject>();
philipelbe7a9e52016-05-19 12:19:35 +020065
philipel504c47d2016-06-30 17:33:02 +020066 now = clock_->TimeInMilliseconds();
67 wait_ms = max_wait_time_ms;
68 next_frame = frames_.end();
69 for (auto frame_it = frames_.begin(); frame_it != frames_.end();
70 ++frame_it) {
71 const FrameObject& frame = *frame_it->second;
72 if (IsContinuous(frame)) {
73 next_frame = frame_it;
74 int64_t render_time = timing_->RenderTimeMs(frame.timestamp, now);
75 wait_ms = timing_->MaxWaitingTime(render_time, now);
philipelbe7a9e52016-05-19 12:19:35 +020076
philipel504c47d2016-06-30 17:33:02 +020077 // This will cause the frame buffer to prefer high framerate rather
78 // than high resolution in the case of the decoder not decoding fast
79 // enough and the stream has multiple spatial and temporal layers.
80 if (wait_ms == 0)
81 continue;
philipelbe7a9e52016-05-19 12:19:35 +020082
philipel504c47d2016-06-30 17:33:02 +020083 break;
84 }
philipelbe7a9e52016-05-19 12:19:35 +020085 }
86 }
philipelbe7a9e52016-05-19 12:19:35 +020087
88 // If the timout occures, return. Otherwise a new frame has been inserted
89 // and the best frame to decode next will be selected again.
90 wait_ms = std::min<int64_t>(wait_ms, latest_return_time - now);
91 wait_ms = std::max<int64_t>(wait_ms, 0);
92 if (!frame_inserted_event_.Wait(wait_ms)) {
philipel504c47d2016-06-30 17:33:02 +020093 rtc::CritScope lock(&crit_);
philipelbe7a9e52016-05-19 12:19:35 +020094 if (next_frame != frames_.end()) {
95 // TODO(philipel): update jitter estimator with correct values.
96 jitter_estimator_->UpdateEstimate(100, 100);
97
98 decoded_frames_.insert(next_frame->first);
99 std::unique_ptr<FrameObject> frame = std::move(next_frame->second);
100 frames_.erase(frames_.begin(), ++next_frame);
philipelbe7a9e52016-05-19 12:19:35 +0200101 return frame;
102 } else {
philipelbe7a9e52016-05-19 12:19:35 +0200103 return std::unique_ptr<FrameObject>();
104 }
105 }
106 }
107}
108
philipel504c47d2016-06-30 17:33:02 +0200109void FrameBuffer::Start() {
110 rtc::CritScope lock(&crit_);
111 stopped_ = false;
112}
113
114void FrameBuffer::Stop() {
115 rtc::CritScope lock(&crit_);
116 stopped_ = true;
117 frame_inserted_event_.Set();
118}
119
philipelbe7a9e52016-05-19 12:19:35 +0200120void FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) {
121 rtc::CritScope lock(&crit_);
122 if (newest_picture_id_ == -1)
123 newest_picture_id_ = frame->picture_id;
124
125 if (AheadOf<uint16_t>(frame->picture_id, newest_picture_id_))
126 newest_picture_id_ = frame->picture_id;
127
128 // Remove frames as long as we have too many, |kMaxNumHistoryFrames|.
129 while (decoded_frames_.size() > kMaxNumHistoryFrames)
130 decoded_frames_.erase(decoded_frames_.begin());
131
132 // Remove frames that are too old, |kMaxNumHistoryFrames|.
133 uint16_t old_picture_id = Subtract<1 << 16>(newest_picture_id_, kMaxFrameAge);
134 auto old_decoded_it =
135 decoded_frames_.lower_bound(FrameKey(old_picture_id, 0));
136 decoded_frames_.erase(decoded_frames_.begin(), old_decoded_it);
137
138 FrameKey key(frame->picture_id, frame->spatial_layer);
139 frames_[key] = std::move(frame);
140 frame_inserted_event_.Set();
141}
142
143bool FrameBuffer::IsContinuous(const FrameObject& frame) const {
144 // If a frame with an earlier picture id was inserted compared to the last
145 // decoded frames picture id then that frame arrived too late.
146 if (!decoded_frames_.empty() &&
147 AheadOf(decoded_frames_.rbegin()->first, frame.picture_id)) {
148 return false;
149 }
150
151 // Have we decoded all frames that this frame depend on?
152 for (size_t r = 0; r < frame.num_references; ++r) {
153 FrameKey ref_key(frame.references[r], frame.spatial_layer);
154 if (decoded_frames_.find(ref_key) == decoded_frames_.end())
155 return false;
156 }
157
158 // If this is a layer frame, have we decoded the lower layer of this
159 // super frame.
160 if (frame.inter_layer_predicted) {
161 RTC_DCHECK_GT(frame.spatial_layer, 0);
162 FrameKey ref_key(frame.picture_id, frame.spatial_layer - 1);
163 if (decoded_frames_.find(ref_key) == decoded_frames_.end())
164 return false;
165 }
166
167 return true;
168}
169
170} // namespace video_coding
171} // namespace webrtc