OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/video_coding/frame_buffer2.h" | 11 #include "webrtc/modules/video_coding/frame_buffer2.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <cstring> | |
15 #include <queue> | |
14 | 16 |
15 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
16 #include "webrtc/modules/video_coding/frame_object.h" | 18 #include "webrtc/base/logging.h" |
17 #include "webrtc/modules/video_coding/jitter_estimator.h" | 19 #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/modules/video_coding/timing.h" |
20 #include "webrtc/system_wrappers/include/clock.h" | 21 #include "webrtc/system_wrappers/include/clock.h" |
21 | 22 |
22 namespace webrtc { | 23 namespace webrtc { |
23 namespace video_coding { | 24 namespace video_coding { |
24 | 25 |
25 namespace { | 26 namespace { |
26 // The maximum age of decoded frames tracked by frame buffer, compared to | 27 // The maximum age of decoded frames tracked by frame buffer, compared to |
27 // |newest_picture_id_|. | 28 // |newest_picture_id_|. |
28 constexpr int kMaxFrameAge = 4096; | 29 constexpr int kMaxHistoryFrameAge = 4096; |
29 | 30 |
30 // The maximum number of decoded frames being tracked by the frame buffer. | 31 // The maximum number of decoded frames being tracked by the frame buffer. |
31 constexpr int kMaxNumHistoryFrames = 256; | 32 constexpr int kMaxNumHistoryFrames = 256; |
32 } // namespace | 33 } // namespace |
33 | 34 |
34 bool 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 | |
43 FrameBuffer::FrameBuffer(Clock* clock, | 35 FrameBuffer::FrameBuffer(Clock* clock, |
44 VCMJitterEstimator* jitter_estimator, | 36 VCMJitterEstimator* jitter_estimator, |
45 VCMTiming* timing) | 37 VCMTiming* timing) |
46 : clock_(clock), | 38 : clock_(clock), |
47 frame_inserted_event_(false, false), | 39 frame_inserted_event_(false, false), |
48 jitter_estimator_(jitter_estimator), | 40 jitter_estimator_(jitter_estimator), |
49 timing_(timing), | 41 timing_(timing), |
50 inter_frame_delay_(clock_->TimeInMilliseconds()), | 42 inter_frame_delay_(clock_->TimeInMilliseconds()), |
51 newest_picture_id_(-1), | 43 newest_picture_id_(-1), |
44 last_continuous_picture_id_(-1), | |
45 last_decoded_picture_id_(-1), | |
52 stopped_(false), | 46 stopped_(false), |
53 protection_mode_(kProtectionNack) {} | 47 protection_mode_(kProtectionNack) {} |
54 | 48 |
55 FrameBuffer::ReturnReason FrameBuffer::NextFrame( | 49 FrameBuffer::ReturnReason FrameBuffer::NextFrame( |
56 int64_t max_wait_time_ms, | 50 int64_t max_wait_time_ms, |
57 std::unique_ptr<FrameObject>* frame_out) { | 51 std::unique_ptr<FrameObject>* frame_out) { |
58 int64_t latest_return_time = clock_->TimeInMilliseconds() + max_wait_time_ms; | 52 int64_t latest_return_time = clock_->TimeInMilliseconds() + max_wait_time_ms; |
59 int64_t now = clock_->TimeInMilliseconds(); | 53 int64_t now = clock_->TimeInMilliseconds(); |
60 int64_t wait_ms = max_wait_time_ms; | 54 int64_t wait_ms = max_wait_time_ms; |
55 decltype(frames_.end()) next_frame_it; | |
danilchap
2016/09/12 12:20:14
may be add
using Frames = std::map<FrameKey, Frame
philipel
2016/09/16 14:01:20
Done.
| |
56 | |
61 while (true) { | 57 while (true) { |
62 std::map<FrameKey, std::unique_ptr<FrameObject>, FrameComp>::iterator | |
63 next_frame_it; | |
64 { | 58 { |
65 rtc::CritScope lock(&crit_); | 59 rtc::CritScope lock(&crit_); |
66 frame_inserted_event_.Reset(); | 60 frame_inserted_event_.Reset(); |
67 if (stopped_) | 61 if (stopped_) |
68 return kStopped; | 62 return kStopped; |
69 | 63 |
70 now = clock_->TimeInMilliseconds(); | 64 now = clock_->TimeInMilliseconds(); |
71 wait_ms = max_wait_time_ms; | 65 wait_ms = max_wait_time_ms; |
72 next_frame_it = frames_.end(); | 66 next_frame_it = frames_.end(); |
73 for (auto frame_it = frames_.begin(); frame_it != frames_.end(); | 67 for (auto it = frames_.begin(); it != frames_.end(); ++it) { |
74 ++frame_it) { | 68 const FrameKey& frame_key = it->first; |
75 const FrameObject& frame = *frame_it->second; | 69 const FrameInfo& frame_info = frame_history_.find(frame_key)->second; |
danilchap
2016/09/12 12:20:14
frame_history_ can through out frames when there a
philipel
2016/09/16 14:01:20
Done, rewrote FrameBuffer to only have one map for
| |
76 if (IsContinuous(frame)) { | 70 FrameObject* frame = it->second.get(); |
77 next_frame_it = frame_it; | 71 |
72 if (frame_info.num_missing_decodable == 0) { | |
73 next_frame_it = it; | |
78 int64_t render_time = | 74 int64_t render_time = |
79 next_frame_it->second->RenderTime() == -1 | 75 frame->RenderTime() == -1 |
80 ? timing_->RenderTimeMs(frame.timestamp, now) | 76 ? timing_->RenderTimeMs(frame->timestamp, now) |
81 : next_frame_it->second->RenderTime(); | 77 : frame->RenderTime(); |
82 wait_ms = timing_->MaxWaitingTime(render_time, now); | 78 wait_ms = timing_->MaxWaitingTime(render_time, now); |
83 frame_it->second->SetRenderTime(render_time); | 79 frame->SetRenderTime(render_time); |
84 | 80 |
85 // This will cause the frame buffer to prefer high framerate rather | 81 // This will cause the frame buffer to prefer high framerate rather |
86 // than high resolution in the case of the decoder not decoding fast | 82 // than high resolution in the case of the decoder not decoding fast |
87 // enough and the stream has multiple spatial and temporal layers. | 83 // enough and the stream has multiple spatial and temporal layers. |
88 if (wait_ms == 0) | 84 if (wait_ms == 0) |
89 continue; | 85 continue; |
90 | 86 |
91 break; | 87 break; |
92 } | 88 } |
93 } | 89 } |
(...skipping 13 matching lines...) Expand all Loading... | |
107 if (inter_frame_delay_.CalculateDelay(timestamp, &frame_delay, | 103 if (inter_frame_delay_.CalculateDelay(timestamp, &frame_delay, |
108 received_timestamp)) { | 104 received_timestamp)) { |
109 jitter_estimator_->UpdateEstimate(frame_delay, | 105 jitter_estimator_->UpdateEstimate(frame_delay, |
110 next_frame_it->second->size); | 106 next_frame_it->second->size); |
111 } | 107 } |
112 float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0; | 108 float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0; |
113 timing_->SetJitterDelay(jitter_estimator_->GetJitterEstimate(rtt_mult)); | 109 timing_->SetJitterDelay(jitter_estimator_->GetJitterEstimate(rtt_mult)); |
114 timing_->UpdateCurrentDelay(next_frame_it->second->RenderTime(), | 110 timing_->UpdateCurrentDelay(next_frame_it->second->RenderTime(), |
115 clock_->TimeInMilliseconds()); | 111 clock_->TimeInMilliseconds()); |
116 | 112 |
117 decoded_frames_.insert(next_frame_it->first); | 113 PropagateDecodability(next_frame_it->first); |
118 std::unique_ptr<FrameObject> frame = std::move(next_frame_it->second); | 114 std::unique_ptr<FrameObject> frame = std::move(next_frame_it->second); |
115 last_decoded_picture_id_ = frame->picture_id; | |
119 frames_.erase(frames_.begin(), ++next_frame_it); | 116 frames_.erase(frames_.begin(), ++next_frame_it); |
120 *frame_out = std::move(frame); | 117 *frame_out = std::move(frame); |
121 return kFrameFound; | 118 return kFrameFound; |
122 } else { | 119 } else { |
123 return kTimeout; | 120 return kTimeout; |
124 } | 121 } |
125 } | 122 } |
126 } | 123 } |
127 } | 124 } |
128 | 125 |
129 void FrameBuffer::SetProtectionMode(VCMVideoProtection mode) { | 126 void FrameBuffer::SetProtectionMode(VCMVideoProtection mode) { |
130 rtc::CritScope lock(&crit_); | 127 rtc::CritScope lock(&crit_); |
131 protection_mode_ = mode; | 128 protection_mode_ = mode; |
132 } | 129 } |
133 | 130 |
134 void FrameBuffer::Start() { | 131 void FrameBuffer::Start() { |
135 rtc::CritScope lock(&crit_); | 132 rtc::CritScope lock(&crit_); |
136 stopped_ = false; | 133 stopped_ = false; |
137 } | 134 } |
138 | 135 |
139 void FrameBuffer::Stop() { | 136 void FrameBuffer::Stop() { |
140 rtc::CritScope lock(&crit_); | 137 rtc::CritScope lock(&crit_); |
141 stopped_ = true; | 138 stopped_ = true; |
142 frame_inserted_event_.Set(); | 139 frame_inserted_event_.Set(); |
143 } | 140 } |
144 | 141 |
145 void FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) { | 142 int FrameBuffer::InsertFrame(std::unique_ptr<FrameObject> frame) { |
146 rtc::CritScope lock(&crit_); | 143 rtc::CritScope lock(&crit_); |
147 // If |newest_picture_id_| is -1 then this is the first frame we received. | 144 if (frame->inter_layer_predicted && frame->spatial_layer == 0) { |
148 if (newest_picture_id_ == -1) | 145 LOG(LS_INFO) << "Spatial layer 0 frame with picture id " |
146 << frame->picture_id | |
147 << " is marked as inter layer predicted, dropping frame."; | |
148 return last_continuous_picture_id_; | |
149 } | |
150 | |
151 if (last_decoded_picture_id_ != -1 && | |
152 AheadOf<uint16_t>(last_decoded_picture_id_, frame->picture_id)) { | |
153 LOG(LS_INFO) << "Frame with picture id " << frame->picture_id | |
154 << " inserted after frame with picture id " | |
155 << last_decoded_picture_id_ | |
156 << " was handed off for decoding, dropping frame."; | |
157 return last_continuous_picture_id_; | |
158 } | |
159 | |
160 if (newest_picture_id_ == -1 || | |
161 AheadOf<uint16_t>(frame->picture_id, newest_picture_id_)) { | |
149 newest_picture_id_ = frame->picture_id; | 162 newest_picture_id_ = frame->picture_id; |
163 } | |
150 | 164 |
151 if (AheadOf<uint16_t>(frame->picture_id, newest_picture_id_)) | 165 // Remove frames while we have too many or if they are too old. |
152 newest_picture_id_ = frame->picture_id; | 166 while (frame_history_.size() > kMaxNumHistoryFrames || |
danilchap
2016/09/12 12:20:14
probably cleaner to have two loops like before.
Th
philipel
2016/09/16 14:01:20
Clear logic moved to new function ClearOldInfo.
| |
153 | 167 (!frame_history_.empty() && |
154 // Remove frames as long as we have too many, |kMaxNumHistoryFrames|. | 168 AheadOf<uint16_t>(newest_picture_id_ - kMaxHistoryFrameAge, |
155 while (decoded_frames_.size() > kMaxNumHistoryFrames) | 169 frame_history_.begin()->first.picture_id))) { |
156 decoded_frames_.erase(decoded_frames_.begin()); | 170 frame_history_.erase(frame_history_.begin()); |
157 | 171 } |
158 // Remove frames that are too old. | |
159 uint16_t old_picture_id = Subtract<1 << 16>(newest_picture_id_, kMaxFrameAge); | |
160 auto old_decoded_it = | |
161 decoded_frames_.lower_bound(FrameKey(old_picture_id, 0)); | |
162 decoded_frames_.erase(decoded_frames_.begin(), old_decoded_it); | |
163 | 172 |
164 FrameKey key(frame->picture_id, frame->spatial_layer); | 173 FrameKey key(frame->picture_id, frame->spatial_layer); |
174 auto info = frame_history_.insert(std::make_pair(key, FrameInfo())).first; | |
danilchap
2016/09/12 12:20:14
since your ignore .second anyway, may be cleaner
philipel
2016/09/16 14:01:20
I can't rely on the pointers being stable since I
| |
175 info->second.num_missing_continuous = frame->num_references; | |
176 info->second.num_missing_decodable = frame->num_references; | |
177 | |
178 // Check how many dependencies that has already been fulfilled. | |
179 for (size_t r = 0; r < frame->num_references; ++r) { | |
180 FrameKey ref_key(frame->references[r], frame->spatial_layer); | |
181 auto ref_info = | |
182 frame_history_.insert(std::make_pair(ref_key, FrameInfo())).first; | |
183 if (ref_info->second.continuous) { | |
184 --info->second.num_missing_continuous; | |
185 if (ref_info->second.decoded) { | |
danilchap
2016/09/12 12:20:14
do you distinguish decoded (returned by NextFrame)
philipel
2016/09/16 14:01:20
Since a FrameInfo can be inserted without the corr
| |
186 --info->second.num_missing_decodable; | |
187 continue; | |
188 } | |
189 } | |
190 | |
191 // If either the frame isn't continuous or not decodable or both then we | |
192 // add the backwards reference so this frame can be updated when new frames | |
193 // are inserted or decoded. | |
194 ref_info->second.dependent_frames[ref_info->second.num_dependent_frames] = | |
195 key; | |
196 ++ref_info->second.num_dependent_frames; | |
197 } | |
198 | |
165 frames_[key] = std::move(frame); | 199 frames_[key] = std::move(frame); |
166 frame_inserted_event_.Set(); | 200 |
201 if (info->second.num_missing_continuous == 0) { | |
202 info->second.continuous = true; | |
203 PropagateContinuity(key); | |
204 | |
205 // Since we now have new continuous frames there might be a better frame | |
206 // to return from NextFrame. Signal that thread so that it can again choose | |
207 // which frame to return. | |
208 frame_inserted_event_.Set(); | |
209 } | |
210 | |
211 return last_continuous_picture_id_; | |
167 } | 212 } |
168 | 213 |
169 bool FrameBuffer::IsContinuous(const FrameObject& frame) const { | 214 void FrameBuffer::PropagateContinuity(const FrameKey& key) { |
170 // If a frame with an earlier picture id was inserted compared to the last | 215 std::queue<decltype(frame_history_.end())> continuous_frames_; |
171 // decoded frames picture id then that frame arrived too late. | 216 |
172 if (!decoded_frames_.empty() && | 217 auto start_frame = frame_history_.find(key); |
173 AheadOf(decoded_frames_.rbegin()->first, frame.picture_id)) { | 218 RTC_DCHECK(start_frame->second.continuous); |
174 return false; | 219 continuous_frames_.push(start_frame); |
220 | |
221 while (!continuous_frames_.empty()) { | |
222 auto frame = continuous_frames_.front(); | |
223 continuous_frames_.pop(); | |
224 | |
225 if (last_continuous_picture_id_ == -1 || | |
226 AheadOf<uint16_t>(frame->first.picture_id, | |
227 last_continuous_picture_id_)) { | |
228 last_continuous_picture_id_ = frame->first.picture_id; | |
229 } | |
230 | |
231 // Loop through all dependent frames, and if that frame no longer has | |
232 // any unfulfilled dependencies then that frame is continuous as well. | |
233 for (size_t d = 0; d < frame->second.num_dependent_frames; ++d) { | |
234 auto frame_ref = frame_history_.find(frame->second.dependent_frames[d]); | |
235 --frame_ref->second.num_missing_continuous; | |
236 | |
237 if (frame_ref->second.num_missing_continuous == 0) { | |
238 frame_ref->second.continuous = true; | |
239 continuous_frames_.push(frame_ref); | |
240 } | |
241 } | |
175 } | 242 } |
243 } | |
176 | 244 |
177 // Have we decoded all frames that this frame depend on? | 245 void FrameBuffer::PropagateDecodability(const FrameKey& key) { |
178 for (size_t r = 0; r < frame.num_references; ++r) { | 246 auto info = frame_history_.find(key); |
179 FrameKey ref_key(frame.references[r], frame.spatial_layer); | 247 info->second.decoded = true; |
180 if (decoded_frames_.find(ref_key) == decoded_frames_.end()) | 248 |
181 return false; | 249 for (size_t d = 0; d < info->second.num_dependent_frames; ++d) { |
250 auto ref_info = frame_history_.find(info->second.dependent_frames[d]); | |
danilchap
2016/09/12 12:20:14
You sure info->second.dependent_frames[d] is in th
| |
251 --ref_info->second.num_missing_decodable; | |
182 } | 252 } |
183 | |
184 // If this is a layer frame, have we decoded the lower layer of this | |
185 // super frame. | |
186 if (frame.inter_layer_predicted) { | |
187 RTC_DCHECK_GT(frame.spatial_layer, 0); | |
188 FrameKey ref_key(frame.picture_id, frame.spatial_layer - 1); | |
189 if (decoded_frames_.find(ref_key) == decoded_frames_.end()) | |
190 return false; | |
191 } | |
192 | |
193 return true; | |
194 } | 253 } |
195 | 254 |
196 } // namespace video_coding | 255 } // namespace video_coding |
197 } // namespace webrtc | 256 } // namespace webrtc |
OLD | NEW |