OLD | NEW |
---|---|
1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 1 /* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
2 * | 2 * |
3 * Use of this source code is governed by a BSD-style license | 3 * Use of this source code is governed by a BSD-style license |
4 * that can be found in the LICENSE file in the root of the source | 4 * that can be found in the LICENSE file in the root of the source |
5 * tree. An additional intellectual property rights grant can be found | 5 * tree. An additional intellectual property rights grant can be found |
6 * in the file PATENTS. All contributing project authors may | 6 * in the file PATENTS. All contributing project authors may |
7 * be found in the AUTHORS file in the root of the source tree. | 7 * be found in the AUTHORS file in the root of the source tree. |
8 */ | 8 */ |
9 | 9 |
10 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" | 10 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h" |
11 | 11 |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 | 15 |
16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
17 #include "vpx/vpx_encoder.h" | 17 #include "vpx/vpx_encoder.h" |
18 #include "vpx/vp8cx.h" | 18 #include "vpx/vp8cx.h" |
19 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 19 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
20 #include "webrtc/system_wrappers/include/clock.h" | |
21 #include "webrtc/system_wrappers/include/metrics.h" | |
20 | 22 |
21 namespace webrtc { | 23 namespace webrtc { |
22 | 24 |
23 static const int kOneSecond90Khz = 90000; | 25 static const int kOneSecond90Khz = 90000; |
24 static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5; | 26 static const int kMinTimeBetweenSyncs = kOneSecond90Khz * 5; |
25 static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10; | 27 static const int kMaxTimeBetweenSyncs = kOneSecond90Khz * 10; |
26 static const int kQpDeltaThresholdForSync = 8; | 28 static const int kQpDeltaThresholdForSync = 8; |
27 | 29 |
28 const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5; | 30 const double ScreenshareLayers::kMaxTL0FpsReduction = 2.5; |
29 const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0; | 31 const double ScreenshareLayers::kAcceptableTargetOvershoot = 2.0; |
30 | 32 |
31 // Since this is TL0 we only allow updating and predicting from the LAST | 33 // Since this is TL0 we only allow updating and predicting from the LAST |
32 // reference frame. | 34 // reference frame. |
33 const int ScreenshareLayers::kTl0Flags = | 35 const int ScreenshareLayers::kTl0Flags = |
34 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | | 36 VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF | |
35 VP8_EFLAG_NO_REF_ARF; | 37 VP8_EFLAG_NO_REF_ARF; |
36 | 38 |
37 // Allow predicting from both TL0 and TL1. | 39 // Allow predicting from both TL0 and TL1. |
38 const int ScreenshareLayers::kTl1Flags = | 40 const int ScreenshareLayers::kTl1Flags = |
39 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; | 41 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST; |
40 | 42 |
41 // Allow predicting from only TL0 to allow participants to switch to the high | 43 // Allow predicting from only TL0 to allow participants to switch to the high |
42 // bitrate stream. This means predicting only from the LAST reference frame, but | 44 // bitrate stream. This means predicting only from the LAST reference frame, but |
43 // only updating GF to not corrupt TL0. | 45 // only updating GF to not corrupt TL0. |
44 const int ScreenshareLayers::kTl1SyncFlags = | 46 const int ScreenshareLayers::kTl1SyncFlags = |
45 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | | 47 VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | |
46 VP8_EFLAG_NO_UPD_LAST; | 48 VP8_EFLAG_NO_UPD_LAST; |
47 | 49 |
48 ScreenshareLayers::ScreenshareLayers(int num_temporal_layers, | 50 ScreenshareLayers::ScreenshareLayers(int num_temporal_layers, |
49 uint8_t initial_tl0_pic_idx) | 51 uint8_t initial_tl0_pic_idx, |
50 : number_of_temporal_layers_(num_temporal_layers), | 52 Clock* clock) |
53 : clock_(clock), | |
54 number_of_temporal_layers_(num_temporal_layers), | |
51 last_base_layer_sync_(false), | 55 last_base_layer_sync_(false), |
52 tl0_pic_idx_(initial_tl0_pic_idx), | 56 tl0_pic_idx_(initial_tl0_pic_idx), |
53 active_layer_(-1), | 57 active_layer_(-1), |
54 last_timestamp_(-1), | 58 last_timestamp_(-1), |
55 last_sync_timestamp_(-1), | 59 last_sync_timestamp_(-1), |
56 min_qp_(-1), | 60 min_qp_(-1), |
57 max_qp_(-1), | 61 max_qp_(-1), |
58 max_debt_bytes_(0), | 62 max_debt_bytes_(0), |
59 frame_rate_(-1) { | 63 frame_rate_(-1) { |
60 RTC_CHECK_GT(num_temporal_layers, 0); | 64 RTC_CHECK_GT(num_temporal_layers, 0); |
61 RTC_CHECK_LE(num_temporal_layers, 2); | 65 RTC_CHECK_LE(num_temporal_layers, 2); |
62 } | 66 } |
63 | 67 |
68 ScreenshareLayers::~ScreenshareLayers() { | |
69 UpdateHistograms(); | |
70 } | |
71 | |
64 int ScreenshareLayers::CurrentLayerId() const { | 72 int ScreenshareLayers::CurrentLayerId() const { |
65 // Codec does not use temporal layers for screenshare. | 73 // Codec does not use temporal layers for screenshare. |
66 return 0; | 74 return 0; |
67 } | 75 } |
68 | 76 |
69 int ScreenshareLayers::EncodeFlags(uint32_t timestamp) { | 77 int ScreenshareLayers::EncodeFlags(uint32_t timestamp) { |
70 if (number_of_temporal_layers_ <= 1) { | 78 if (number_of_temporal_layers_ <= 1) { |
71 // No flags needed for 1 layer screenshare. | 79 // No flags needed for 1 layer screenshare. |
72 return 0; | 80 return 0; |
73 } | 81 } |
74 | 82 |
83 if (stats_.first_framt_time_ms_ == -1) | |
stefan-webrtc
2016/02/29 09:10:18
first_frame_time_ms_
sprang_webrtc
2016/02/29 12:43:17
Done.
| |
84 stats_.first_framt_time_ms_ = clock_->TimeInMilliseconds(); | |
85 | |
75 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp); | 86 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp); |
76 int flags = 0; | 87 int flags = 0; |
77 | 88 |
78 if (active_layer_ == -1 || | 89 if (active_layer_ == -1 || |
79 layers_[active_layer_].state != TemporalLayer::State::kDropped) { | 90 layers_[active_layer_].state != TemporalLayer::State::kDropped) { |
80 if (layers_[0].debt_bytes_ > max_debt_bytes_) { | 91 if (layers_[0].debt_bytes_ > max_debt_bytes_) { |
81 // Must drop TL0, encode TL1 instead. | 92 // Must drop TL0, encode TL1 instead. |
82 if (layers_[1].debt_bytes_ > max_debt_bytes_) { | 93 if (layers_[1].debt_bytes_ > max_debt_bytes_) { |
83 // Must drop both TL0 and TL1. | 94 // Must drop both TL0 and TL1. |
84 active_layer_ = -1; | 95 active_layer_ = -1; |
(...skipping 12 matching lines...) Expand all Loading... | |
97 case 1: | 108 case 1: |
98 if (TimeToSync(unwrapped_timestamp)) { | 109 if (TimeToSync(unwrapped_timestamp)) { |
99 last_sync_timestamp_ = unwrapped_timestamp; | 110 last_sync_timestamp_ = unwrapped_timestamp; |
100 flags = kTl1SyncFlags; | 111 flags = kTl1SyncFlags; |
101 } else { | 112 } else { |
102 flags = kTl1Flags; | 113 flags = kTl1Flags; |
103 } | 114 } |
104 break; | 115 break; |
105 case -1: | 116 case -1: |
106 flags = -1; | 117 flags = -1; |
118 ++stats_.num_dropped_frames_; | |
107 break; | 119 break; |
108 default: | 120 default: |
109 flags = -1; | 121 flags = -1; |
110 RTC_NOTREACHED(); | 122 RTC_NOTREACHED(); |
111 } | 123 } |
112 | 124 |
113 // Make sure both frame droppers leak out bits. | 125 // Make sure both frame droppers leak out bits. |
114 int64_t ts_diff; | 126 int64_t ts_diff; |
115 if (last_timestamp_ == -1) { | 127 if (last_timestamp_ == -1) { |
116 ts_diff = kOneSecond90Khz / (frame_rate_ <= 0 ? 5 : frame_rate_); | 128 ts_diff = kOneSecond90Khz / (frame_rate_ <= 0 ? 5 : frame_rate_); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 | 181 |
170 void ScreenshareLayers::FrameEncoded(unsigned int size, | 182 void ScreenshareLayers::FrameEncoded(unsigned int size, |
171 uint32_t timestamp, | 183 uint32_t timestamp, |
172 int qp) { | 184 int qp) { |
173 if (number_of_temporal_layers_ == 1) | 185 if (number_of_temporal_layers_ == 1) |
174 return; | 186 return; |
175 | 187 |
176 RTC_DCHECK_NE(-1, active_layer_); | 188 RTC_DCHECK_NE(-1, active_layer_); |
177 if (size == 0) { | 189 if (size == 0) { |
178 layers_[active_layer_].state = TemporalLayer::State::kDropped; | 190 layers_[active_layer_].state = TemporalLayer::State::kDropped; |
191 ++stats_.num_overshoots_; | |
179 return; | 192 return; |
180 } | 193 } |
181 | 194 |
182 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) { | 195 if (layers_[active_layer_].state == TemporalLayer::State::kDropped) { |
183 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost; | 196 layers_[active_layer_].state = TemporalLayer::State::kQualityBoost; |
184 } | 197 } |
185 | 198 |
186 if (qp != -1) | 199 if (qp != -1) |
187 layers_[active_layer_].last_qp = qp; | 200 layers_[active_layer_].last_qp = qp; |
188 | 201 |
189 if (active_layer_ == 0) { | 202 if (active_layer_ == 0) { |
190 layers_[0].debt_bytes_ += size; | 203 layers_[0].debt_bytes_ += size; |
191 layers_[1].debt_bytes_ += size; | 204 layers_[1].debt_bytes_ += size; |
205 ++stats_.num_tl0_frames_; | |
206 stats_.tl0_target_bitrate_sum_ += layers_[0].target_rate_kbps_; | |
207 stats_.tl0_qp_sum_ += qp; | |
192 } else if (active_layer_ == 1) { | 208 } else if (active_layer_ == 1) { |
193 layers_[1].debt_bytes_ += size; | 209 layers_[1].debt_bytes_ += size; |
210 ++stats_.num_tl1_frames_; | |
211 stats_.tl1_target_bitrate_sum_ += layers_[1].target_rate_kbps_; | |
212 stats_.tl1_qp_sum_ += qp; | |
194 } | 213 } |
195 } | 214 } |
196 | 215 |
197 void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync, | 216 void ScreenshareLayers::PopulateCodecSpecific(bool base_layer_sync, |
198 CodecSpecificInfoVP8* vp8_info, | 217 CodecSpecificInfoVP8* vp8_info, |
199 uint32_t timestamp) { | 218 uint32_t timestamp) { |
200 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp); | 219 int64_t unwrapped_timestamp = time_wrap_handler_.Unwrap(timestamp); |
201 if (number_of_temporal_layers_ == 1) { | 220 if (number_of_temporal_layers_ == 1) { |
202 vp8_info->temporalIdx = kNoTemporalIdx; | 221 vp8_info->temporalIdx = kNoTemporalIdx; |
203 vp8_info->layerSync = false; | 222 vp8_info->layerSync = false; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 | 295 |
277 void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) { | 296 void ScreenshareLayers::TemporalLayer::UpdateDebt(int64_t delta_ms) { |
278 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8; | 297 uint32_t debt_reduction_bytes = target_rate_kbps_ * delta_ms / 8; |
279 if (debt_reduction_bytes >= debt_bytes_) { | 298 if (debt_reduction_bytes >= debt_bytes_) { |
280 debt_bytes_ = 0; | 299 debt_bytes_ = 0; |
281 } else { | 300 } else { |
282 debt_bytes_ -= debt_reduction_bytes; | 301 debt_bytes_ -= debt_reduction_bytes; |
283 } | 302 } |
284 } | 303 } |
285 | 304 |
305 void ScreenshareLayers::UpdateHistograms() { | |
306 if (stats_.first_framt_time_ms_ == -1) | |
307 return; | |
308 int64_t duration_sec = | |
309 (clock_->TimeInMilliseconds() - stats_.first_framt_time_ms_ + 500) / 1000; | |
310 if (duration_sec >= metrics::kMinRunTimeInSeconds) { | |
311 RTC_HISTOGRAM_COUNTS_10000( | |
312 "WebRTC.Video.Screenshare.FrameRateLayer0", | |
313 (stats_.num_tl0_frames_ + (duration_sec / 2)) / duration_sec); | |
314 RTC_HISTOGRAM_COUNTS_10000( | |
315 "WebRTC.Video.Screenshare.FrameRateLayer1", | |
316 (stats_.num_tl1_frames_ + (duration_sec / 2)) / duration_sec); | |
stefan-webrtc
2016/02/29 09:10:18
Should this report tl0+tl1 instead, since that's t
sprang_webrtc
2016/02/29 12:43:17
I think I'd rather keep them separate. The total f
stefan-webrtc
2016/02/29 15:04:51
ack
| |
317 RTC_HISTOGRAM_COUNTS_10000( | |
318 "WebRTC.Video.Screenshare.FramesPerDrop", | |
319 stats_.num_dropped_frames_ == 0 ? 0 : (stats_.num_tl0_frames_ + | |
320 stats_.num_tl1_frames_) / | |
321 stats_.num_dropped_frames_); | |
322 RTC_HISTOGRAM_COUNTS_10000( | |
323 "WebRTC.Video.Screenshare.FramesPerOvershoot", | |
324 stats_.num_overshoots_ == 0 ? 0 : (stats_.num_tl0_frames_ + | |
325 stats_.num_tl1_frames_) / | |
326 stats_.num_overshoots_); | |
327 if (stats_.num_tl0_frames_ > 0) { | |
328 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.AverageQpLayer0", | |
329 stats_.tl0_qp_sum_ / stats_.num_tl0_frames_); | |
330 RTC_HISTOGRAM_COUNTS_10000( | |
331 "WebRTC.Video.Screenshare.TargetBitrateLayer0", | |
332 stats_.tl0_target_bitrate_sum_ / stats_.num_tl0_frames_); | |
333 } | |
334 if (stats_.num_tl1_frames_ > 0) { | |
335 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.Screenshare.AverageQpLayer1", | |
336 stats_.tl1_qp_sum_ / stats_.num_tl1_frames_); | |
337 RTC_HISTOGRAM_COUNTS_10000( | |
338 "WebRTC.Video.Screenshare.TargetBitrateLayer1", | |
339 stats_.tl1_target_bitrate_sum_ / stats_.num_tl1_frames_); | |
340 } | |
341 } | |
342 } | |
343 | |
286 } // namespace webrtc | 344 } // namespace webrtc |
OLD | NEW |