Chromium Code Reviews| 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/field_trial.h" | 19 #include "webrtc/system_wrappers/include/field_trial.h" |
| 19 #include "webrtc/system_wrappers/include/metrics.h" | 20 #include "webrtc/system_wrappers/include/metrics.h" |
| 20 | 21 |
| 21 namespace webrtc { | 22 namespace webrtc { |
| 22 namespace { | 23 namespace { |
| 23 // Periodic time interval for processing samples for |freq_offset_counter_|. | 24 // Periodic time interval for processing samples for |freq_offset_counter_|. |
| 24 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 25 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
| 26 | |
| 27 // Configuration for bad call detection. | |
| 28 const int kNumMeasurements = 10; | |
| 29 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | |
| 30 const float kBadFraction = 0.8f; | |
| 31 // For fps and framerate variance: | |
| 32 // Low means low enough to be bad, high means high enough to be good | |
| 33 const int kLowFpsThreshold = 12; | |
| 34 const int kHighFpsThreshold = 14; | |
| 35 const int kLowVarianceThreshold = 1; | |
|
åsapersson
2016/12/07 15:34:51
For variance, low enough to be good..?
| |
| 36 const int kHighVarianceThreshold = 2; | |
| 37 // For qp: | |
| 38 // Low means low enough to be good, high means high enough to be bad | |
| 39 const int kLowQpThreshold = 60; | |
| 40 const int kHighQpThreshold = 70; | |
|
åsapersson
2016/12/07 15:34:51
Add Vp8 to variable name (since the qp range depen
| |
| 25 } // namespace | 41 } // namespace |
| 26 | 42 |
| 27 ReceiveStatisticsProxy::ReceiveStatisticsProxy( | 43 ReceiveStatisticsProxy::ReceiveStatisticsProxy( |
| 28 const VideoReceiveStream::Config* config, | 44 const VideoReceiveStream::Config* config, |
| 29 Clock* clock) | 45 Clock* clock) |
| 30 : clock_(clock), | 46 : clock_(clock), |
| 31 config_(*config), | 47 config_(*config), |
| 32 start_ms_(clock->TimeInMilliseconds()), | 48 start_ms_(clock->TimeInMilliseconds()), |
| 33 // 1000ms window, scale 1000 for ms to s. | 49 // 1000ms window, scale 1000 for ms to s. |
|
åsapersson
2016/12/07 15:34:50
Move comment to decode_fps_estimator_
| |
| 50 last_sample_time_(clock->TimeInMilliseconds()), | |
| 51 fps_threshold_(kLowFpsThreshold, | |
| 52 kHighFpsThreshold, | |
| 53 kBadFraction, | |
| 54 kNumMeasurements), | |
| 55 qp_threshold_(kLowQpThreshold, | |
| 56 kHighQpThreshold, | |
| 57 kBadFraction, | |
| 58 kNumMeasurements), | |
| 59 variance_threshold_(kLowVarianceThreshold, | |
| 60 kHighVarianceThreshold, | |
| 61 kBadFraction, | |
| 62 kNumMeasurementsVariance), | |
| 34 decode_fps_estimator_(1000, 1000), | 63 decode_fps_estimator_(1000, 1000), |
| 35 renders_fps_estimator_(1000, 1000), | 64 renders_fps_estimator_(1000, 1000), |
| 36 render_fps_tracker_(100, 10u), | 65 render_fps_tracker_(100, 10u), |
| 37 render_pixel_tracker_(100, 10u), | 66 render_pixel_tracker_(100, 10u), |
| 38 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), | 67 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), |
| 39 first_report_block_time_ms_(-1) { | 68 first_report_block_time_ms_(-1) { |
| 40 stats_.ssrc = config_.rtp.remote_ssrc; | 69 stats_.ssrc = config_.rtp.remote_ssrc; |
| 41 for (auto it : config_.rtp.rtx) | 70 for (auto it : config_.rtp.rtx) |
| 42 rtx_stats_[it.second.ssrc] = StreamDataCounters(); | 71 rtx_stats_[it.second.ssrc] = StreamDataCounters(); |
| 43 } | 72 } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 counters.fir_packets * 60 / elapsed_sec); | 195 counters.fir_packets * 60 / elapsed_sec); |
| 167 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", | 196 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", |
| 168 counters.pli_packets * 60 / elapsed_sec); | 197 counters.pli_packets * 60 / elapsed_sec); |
| 169 if (counters.nack_requests > 0) { | 198 if (counters.nack_requests > 0) { |
| 170 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", | 199 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent", |
| 171 counters.UniqueNackRequestsInPercent()); | 200 counters.UniqueNackRequestsInPercent()); |
| 172 } | 201 } |
| 173 } | 202 } |
| 174 } | 203 } |
| 175 | 204 |
| 205 void ReceiveStatisticsProxy::QualitySample() { | |
| 206 uint64_t now = clock_->TimeInMilliseconds(); | |
| 207 | |
|
åsapersson
2016/12/07 15:34:50
Perhaps check that some minimum time has passed si
| |
| 208 double fps = | |
| 209 render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_); | |
| 210 int qp = qp_sample_.Avg(1); | |
|
åsapersson
2016/12/07 15:34:51
Handle -1 (i.e. no samples)?
palmkvist
2016/12/08 14:15:02
My original thinking was that that was ok, since t
| |
| 211 | |
| 212 bool prev_fps_bad = !fps_threshold_.IsHigh().value_or(true); | |
| 213 bool prev_qp_bad = qp_threshold_.IsHigh().value_or(false); | |
| 214 bool prev_variance_bad = variance_threshold_.IsHigh().value_or(false); | |
| 215 bool prev_any_bad = prev_fps_bad || prev_qp_bad || prev_variance_bad; | |
| 216 | |
| 217 fps_threshold_.AddMeasurement(static_cast<int>(fps)); | |
| 218 qp_threshold_.AddMeasurement(qp); | |
| 219 rtc::Optional<double> fps_variance_opt = fps_threshold_.CalculateVariance(); | |
| 220 double fps_variance = fps_variance_opt.value_or(0); | |
| 221 if (fps_variance_opt) { | |
| 222 variance_threshold_.AddMeasurement(static_cast<int>(fps_variance)); | |
| 223 } | |
| 224 | |
| 225 bool fps_bad = !fps_threshold_.IsHigh().value_or(true); | |
| 226 bool qp_bad = qp_threshold_.IsHigh().value_or(false); | |
| 227 bool variance_bad = variance_threshold_.IsHigh().value_or(false); | |
| 228 bool any_bad = fps_bad || qp_bad || variance_bad; | |
| 229 | |
| 230 if (!prev_any_bad && any_bad) { | |
| 231 LOG(LS_WARNING) << "Bad call (any) start: " << now; | |
| 232 } else if (prev_any_bad && !any_bad) { | |
| 233 LOG(LS_WARNING) << "Bad call (any) end: " << now; | |
| 234 } | |
| 235 | |
| 236 if (!prev_fps_bad && fps_bad) { | |
| 237 LOG(LS_WARNING) << "Bad call (fps) start: " << now; | |
| 238 } else if (prev_fps_bad && !fps_bad) { | |
| 239 LOG(LS_WARNING) << "Bad call (fps) end: " << now; | |
| 240 } | |
| 241 | |
| 242 if (!prev_qp_bad && qp_bad) { | |
| 243 LOG(LS_WARNING) << "Bad call (qp) start: " << now; | |
| 244 } else if (prev_qp_bad && !qp_bad) { | |
| 245 LOG(LS_WARNING) << "Bad call (qp) end: " << now; | |
| 246 } | |
| 247 | |
| 248 if (!prev_variance_bad && variance_bad) { | |
| 249 LOG(LS_WARNING) << "Bad call (variance) start: " << now; | |
| 250 } else if (prev_variance_bad && !variance_bad) { | |
| 251 LOG(LS_WARNING) << "Bad call (variance) end: " << now; | |
| 252 } | |
| 253 | |
| 254 LOG(LS_INFO) << "SAMPLE: sample_length: " << (now - last_sample_time_) | |
| 255 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp | |
| 256 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad | |
| 257 << " fps_variance: " << fps_variance; | |
| 258 | |
| 259 last_sample_time_ = now; | |
| 260 qp_sample_.Reset(); | |
| 261 } | |
| 262 | |
| 176 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { | 263 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { |
| 177 rtc::CritScope lock(&crit_); | 264 rtc::CritScope lock(&crit_); |
| 178 return stats_; | 265 return stats_; |
| 179 } | 266 } |
| 180 | 267 |
| 181 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { | 268 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { |
| 182 rtc::CritScope lock(&crit_); | 269 rtc::CritScope lock(&crit_); |
| 183 stats_.current_payload_type = payload_type; | 270 stats_.current_payload_type = payload_type; |
| 184 } | 271 } |
| 185 | 272 |
| 186 void ReceiveStatisticsProxy::OnDecoderImplementationName( | 273 void ReceiveStatisticsProxy::OnDecoderImplementationName( |
| 187 const char* implementation_name) { | 274 const char* implementation_name) { |
| 188 rtc::CritScope lock(&crit_); | 275 rtc::CritScope lock(&crit_); |
| 189 stats_.decoder_implementation_name = implementation_name; | 276 stats_.decoder_implementation_name = implementation_name; |
| 190 } | 277 } |
| 191 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, | 278 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, |
| 192 unsigned int bitrate_bps) { | 279 unsigned int bitrate_bps) { |
| 193 rtc::CritScope lock(&crit_); | 280 rtc::CritScope lock(&crit_); |
| 281 QualitySample(); | |
| 194 stats_.network_frame_rate = framerate; | 282 stats_.network_frame_rate = framerate; |
| 195 stats_.total_bitrate_bps = bitrate_bps; | 283 stats_.total_bitrate_bps = bitrate_bps; |
| 196 } | 284 } |
| 197 | 285 |
| 198 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, | 286 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, |
| 199 int max_decode_ms, | 287 int max_decode_ms, |
| 200 int current_delay_ms, | 288 int current_delay_ms, |
| 201 int target_delay_ms, | 289 int target_delay_ms, |
| 202 int jitter_buffer_ms, | 290 int jitter_buffer_ms, |
| 203 int min_playout_delay_ms, | 291 int min_playout_delay_ms, |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 } | 421 } |
| 334 | 422 |
| 335 void ReceiveStatisticsProxy::OnPreDecode( | 423 void ReceiveStatisticsProxy::OnPreDecode( |
| 336 const EncodedImage& encoded_image, | 424 const EncodedImage& encoded_image, |
| 337 const CodecSpecificInfo* codec_specific_info) { | 425 const CodecSpecificInfo* codec_specific_info) { |
| 338 if (!codec_specific_info || encoded_image.qp_ == -1) { | 426 if (!codec_specific_info || encoded_image.qp_ == -1) { |
| 339 return; | 427 return; |
| 340 } | 428 } |
| 341 if (codec_specific_info->codecType == kVideoCodecVP8) { | 429 if (codec_specific_info->codecType == kVideoCodecVP8) { |
| 342 qp_counters_.vp8.Add(encoded_image.qp_); | 430 qp_counters_.vp8.Add(encoded_image.qp_); |
| 431 rtc::CritScope lock(&crit_); | |
| 432 qp_sample_.Add(encoded_image.qp_); | |
| 343 } | 433 } |
| 344 } | 434 } |
| 345 | 435 |
| 346 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { | 436 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { |
| 347 sum += sample; | 437 sum += sample; |
| 348 ++num_samples; | 438 ++num_samples; |
| 349 } | 439 } |
| 350 | 440 |
| 351 int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const { | 441 int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const { |
| 352 if (num_samples < min_required_samples || num_samples == 0) | 442 if (num_samples < min_required_samples || num_samples == 0) |
| 353 return -1; | 443 return -1; |
| 354 return sum / num_samples; | 444 return sum / num_samples; |
| 355 } | 445 } |
| 356 | 446 |
| 447 void ReceiveStatisticsProxy::SampleCounter::Reset() { | |
| 448 num_samples = 0; | |
| 449 sum = 0; | |
| 450 } | |
| 451 | |
| 357 } // namespace webrtc | 452 } // namespace webrtc |
| OLD | NEW |