OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 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/video/receive_statistics_proxy.h" | 11 #include "webrtc/video/receive_statistics_proxy.h" |
12 | 12 |
13 #include <cmath> | 13 #include <cmath> |
14 | 14 |
15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
16 #include "webrtc/base/logging.h" | |
16 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 17 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
17 #include "webrtc/system_wrappers/include/clock.h" | 18 #include "webrtc/system_wrappers/include/clock.h" |
18 #include "webrtc/system_wrappers/include/metrics.h" | 19 #include "webrtc/system_wrappers/include/metrics.h" |
19 | 20 |
20 namespace webrtc { | 21 namespace webrtc { |
21 namespace { | 22 namespace { |
22 // Periodic time interval for processing samples for |freq_offset_counter_|. | 23 // Periodic time interval for processing samples for |freq_offset_counter_|. |
23 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 24 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
25 | |
26 // Configuration for bad call detection. | |
27 const int kNumMeasurements = 10; | |
28 const float kBadFraction = 0.8f; | |
29 const int kLowFpsThreshold = 12; | |
30 const int kHighFpsThreshold = 14; | |
31 const int kLowQpThreshold = 60; | |
stefan-webrtc
2016/11/28 15:55:25
seems like a high threshold to be considered "low"
palmkvist
2016/12/01 13:03:45
It means it is low enough to not be considered bad
stefan-webrtc
2016/12/02 09:31:55
Ok, I'd rename it I think. Comment is probably fin
| |
32 const int kHighQpThreshold = 70; | |
33 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | |
34 const int kLowVarianceThreshold = 1; | |
35 const int kHighVarianceThreshold = 2; | |
24 } // namespace | 36 } // namespace |
25 | 37 |
26 ReceiveStatisticsProxy::ReceiveStatisticsProxy( | 38 ReceiveStatisticsProxy::ReceiveStatisticsProxy( |
27 const VideoReceiveStream::Config* config, | 39 const VideoReceiveStream::Config* config, |
28 Clock* clock) | 40 Clock* clock) |
29 : clock_(clock), | 41 : clock_(clock), |
30 config_(*config), | 42 config_(*config), |
31 start_ms_(clock->TimeInMilliseconds()), | 43 start_ms_(clock->TimeInMilliseconds()), |
32 // 1000ms window, scale 1000 for ms to s. | 44 // 1000ms window, scale 1000 for ms to s. |
45 last_sample_time_(clock->TimeInMilliseconds()), | |
46 fps_threshold_(kLowFpsThreshold, | |
47 kHighFpsThreshold, | |
48 kBadFraction, | |
49 kNumMeasurements), | |
50 qp_threshold_(kLowQpThreshold, | |
51 kHighQpThreshold, | |
52 kBadFraction, | |
53 kNumMeasurements), | |
54 variance_threshold_(kLowVarianceThreshold, | |
55 kHighVarianceThreshold, | |
56 kBadFraction, | |
57 kNumMeasurementsVariance), | |
33 decode_fps_estimator_(1000, 1000), | 58 decode_fps_estimator_(1000, 1000), |
34 renders_fps_estimator_(1000, 1000), | 59 renders_fps_estimator_(1000, 1000), |
35 render_fps_tracker_(100, 10u), | 60 render_fps_tracker_(100, 10u), |
36 render_pixel_tracker_(100, 10u), | 61 render_pixel_tracker_(100, 10u), |
37 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs) { | 62 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs) { |
38 stats_.ssrc = config_.rtp.remote_ssrc; | 63 stats_.ssrc = config_.rtp.remote_ssrc; |
39 for (auto it : config_.rtp.rtx) | 64 for (auto it : config_.rtp.rtx) |
40 rtx_stats_[it.second.ssrc] = StreamDataCounters(); | 65 rtx_stats_[it.second.ssrc] = StreamDataCounters(); |
41 } | 66 } |
42 | 67 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
153 counters.fir_packets * 60 / elapsed_sec); | 178 counters.fir_packets * 60 / elapsed_sec); |
154 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", | 179 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", |
155 counters.pli_packets * 60 / elapsed_sec); | 180 counters.pli_packets * 60 / elapsed_sec); |
156 if (counters.nack_requests > 0) { | 181 if (counters.nack_requests > 0) { |
157 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", | 182 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", |
158 counters.UniqueNackRequestsInPercent()); | 183 counters.UniqueNackRequestsInPercent()); |
159 } | 184 } |
160 } | 185 } |
161 } | 186 } |
162 | 187 |
188 void ReceiveStatisticsProxy::QualitySample() { | |
189 uint64_t now = clock_->TimeInMilliseconds(); | |
190 | |
191 double fps = | |
192 render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_); | |
193 int qp = qp_sample_.Avg(1); | |
stefan-webrtc
2016/11/28 15:55:24
What does 1 mean here?
palmkvist
2016/12/01 13:03:45
It's number of samples required to return an avera
stefan-webrtc
2016/12/02 09:31:55
I see. I guess it's fine as is.
| |
194 | |
195 bool prev_fps_bad = !fps_threshold_.IsHigh().value_or(true); | |
196 bool prev_qp_bad = qp_threshold_.IsHigh().value_or(false); | |
197 bool prev_variance_bad = variance_threshold_.IsHigh().value_or(false); | |
198 bool prev_any_bad = prev_fps_bad || prev_qp_bad || prev_variance_bad; | |
199 | |
200 fps_threshold_.AddMeasurement(static_cast<int>(fps)); | |
201 qp_threshold_.AddMeasurement(qp); | |
202 rtc::Optional<double> fps_variance_opt = fps_threshold_.CalculateVariance(); | |
203 double fps_variance = fps_variance_opt.value_or(0); | |
204 if (fps_variance_opt) { | |
205 variance_threshold_.AddMeasurement(static_cast<int>(fps_variance)); | |
206 } | |
207 | |
208 bool fps_bad = !fps_threshold_.IsHigh().value_or(true); | |
209 bool qp_bad = qp_threshold_.IsHigh().value_or(false); | |
210 bool variance_bad = variance_threshold_.IsHigh().value_or(false); | |
211 bool any_bad = fps_bad || qp_bad || variance_bad; | |
212 | |
213 if (!prev_any_bad && any_bad) { | |
214 LOG(LS_WARNING) << "Bad call (any) start: " << now; | |
215 } else if (prev_any_bad && !any_bad) { | |
216 LOG(LS_WARNING) << "Bad call (any) end: " << now; | |
217 } | |
218 | |
219 if (!prev_fps_bad && fps_bad) { | |
220 LOG(LS_WARNING) << "Bad call (fps) start: " << now; | |
221 } else if (prev_fps_bad && !fps_bad) { | |
222 LOG(LS_WARNING) << "Bad call (fps) end: " << now; | |
223 } | |
224 | |
225 if (!prev_qp_bad && qp_bad) { | |
226 LOG(LS_WARNING) << "Bad call (qp) start: " << now; | |
227 } else if (prev_qp_bad && !qp_bad) { | |
228 LOG(LS_WARNING) << "Bad call (qp) end: " << now; | |
229 } | |
230 | |
231 if (!prev_variance_bad && variance_bad) { | |
232 LOG(LS_WARNING) << "Bad call (variance) start: " << now; | |
233 } else if (prev_variance_bad && !variance_bad) { | |
234 LOG(LS_WARNING) << "Bad call (variance) end: " << now; | |
235 } | |
236 | |
237 LOG(LS_INFO) << "SAMPLE: sample_length: " << (now - last_sample_time_) | |
238 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp | |
239 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad | |
240 << " fps_variance: " << fps_variance; | |
241 | |
242 last_sample_time_ = now; | |
243 qp_sample_.Reset(); | |
244 } | |
245 | |
163 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { | 246 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { |
164 rtc::CritScope lock(&crit_); | 247 rtc::CritScope lock(&crit_); |
165 return stats_; | 248 return stats_; |
166 } | 249 } |
167 | 250 |
168 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { | 251 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { |
169 rtc::CritScope lock(&crit_); | 252 rtc::CritScope lock(&crit_); |
170 stats_.current_payload_type = payload_type; | 253 stats_.current_payload_type = payload_type; |
171 } | 254 } |
172 | 255 |
173 void ReceiveStatisticsProxy::OnDecoderImplementationName( | 256 void ReceiveStatisticsProxy::OnDecoderImplementationName( |
174 const char* implementation_name) { | 257 const char* implementation_name) { |
175 rtc::CritScope lock(&crit_); | 258 rtc::CritScope lock(&crit_); |
176 stats_.decoder_implementation_name = implementation_name; | 259 stats_.decoder_implementation_name = implementation_name; |
177 } | 260 } |
178 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, | 261 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, |
179 unsigned int bitrate_bps) { | 262 unsigned int bitrate_bps) { |
180 rtc::CritScope lock(&crit_); | 263 rtc::CritScope lock(&crit_); |
264 QualitySample(); | |
181 stats_.network_frame_rate = framerate; | 265 stats_.network_frame_rate = framerate; |
182 stats_.total_bitrate_bps = bitrate_bps; | 266 stats_.total_bitrate_bps = bitrate_bps; |
183 } | 267 } |
184 | 268 |
185 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, | 269 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, |
186 int max_decode_ms, | 270 int max_decode_ms, |
187 int current_delay_ms, | 271 int current_delay_ms, |
188 int target_delay_ms, | 272 int target_delay_ms, |
189 int jitter_buffer_ms, | 273 int jitter_buffer_ms, |
190 int min_playout_delay_ms, | 274 int min_playout_delay_ms, |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 } | 401 } |
318 | 402 |
319 void ReceiveStatisticsProxy::OnPreDecode( | 403 void ReceiveStatisticsProxy::OnPreDecode( |
320 const EncodedImage& encoded_image, | 404 const EncodedImage& encoded_image, |
321 const CodecSpecificInfo* codec_specific_info) { | 405 const CodecSpecificInfo* codec_specific_info) { |
322 if (!codec_specific_info || encoded_image.qp_ == -1) { | 406 if (!codec_specific_info || encoded_image.qp_ == -1) { |
323 return; | 407 return; |
324 } | 408 } |
325 if (codec_specific_info->codecType == kVideoCodecVP8) { | 409 if (codec_specific_info->codecType == kVideoCodecVP8) { |
326 qp_counters_.vp8.Add(encoded_image.qp_); | 410 qp_counters_.vp8.Add(encoded_image.qp_); |
411 rtc::CritScope lock(&crit_); | |
412 qp_sample_.Add(encoded_image.qp_); | |
327 } | 413 } |
328 } | 414 } |
329 | 415 |
330 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { | 416 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { |
331 sum += sample; | 417 sum += sample; |
332 ++num_samples; | 418 ++num_samples; |
333 } | 419 } |
334 | 420 |
335 int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const { | 421 int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const { |
336 if (num_samples < min_required_samples || num_samples == 0) | 422 if (num_samples < min_required_samples || num_samples == 0) |
337 return -1; | 423 return -1; |
338 return sum / num_samples; | 424 return sum / num_samples; |
339 } | 425 } |
340 | 426 |
427 void ReceiveStatisticsProxy::SampleCounter::Reset() { | |
428 num_samples = 0; | |
429 sum = 0; | |
stefan-webrtc
2016/11/28 15:55:25
num_samples_
sum_
| |
430 } | |
431 | |
341 } // namespace webrtc | 432 } // namespace webrtc |
OLD | NEW |