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 <algorithm> | |
13 #include <cmath> | 14 #include <cmath> |
15 #include <utility> | |
14 | 16 |
15 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
16 #include "webrtc/base/logging.h" | 18 #include "webrtc/base/logging.h" |
17 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 19 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
18 #include "webrtc/system_wrappers/include/clock.h" | 20 #include "webrtc/system_wrappers/include/clock.h" |
19 #include "webrtc/system_wrappers/include/field_trial.h" | 21 #include "webrtc/system_wrappers/include/field_trial.h" |
20 #include "webrtc/system_wrappers/include/metrics.h" | 22 #include "webrtc/system_wrappers/include/metrics.h" |
21 | 23 |
22 namespace webrtc { | 24 namespace webrtc { |
23 namespace { | 25 namespace { |
24 // Periodic time interval for processing samples for |freq_offset_counter_|. | 26 // Periodic time interval for processing samples for |freq_offset_counter_|. |
25 const int64_t kFreqOffsetProcessIntervalMs = 40000; | 27 const int64_t kFreqOffsetProcessIntervalMs = 40000; |
26 | 28 |
27 // Configuration for bad call detection. | 29 // Configuration for bad call detection. |
28 const int kMinSampleLengthMs = 990; | 30 const int kMinSampleLengthMs = 990; |
29 const int kNumMeasurements = 10; | 31 const int kNumMeasurements = 10; |
30 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; | 32 const int kNumMeasurementsVariance = kNumMeasurements * 1.5; |
31 const float kBadFraction = 0.8f; | 33 const float kBadFraction = 0.8f; |
32 // For fps: | 34 // For fps: |
33 // Low means low enough to be bad, high means high enough to be good | 35 // Low means low enough to be bad, high means high enough to be good |
34 const int kLowFpsThreshold = 12; | 36 const int kLowFpsThreshold = 12; |
35 const int kHighFpsThreshold = 14; | 37 const int kHighFpsThreshold = 14; |
36 // For qp and fps variance: | 38 // For qp and fps variance: |
37 // Low means low enough to be good, high means high enough to be bad | 39 // Low means low enough to be good, high means high enough to be bad |
38 const int kLowQpThresholdVp8 = 60; | 40 const int kLowQpThresholdVp8 = 60; |
39 const int kHighQpThresholdVp8 = 70; | 41 const int kHighQpThresholdVp8 = 70; |
40 const int kLowVarianceThreshold = 1; | 42 const int kLowVarianceThreshold = 1; |
41 const int kHighVarianceThreshold = 2; | 43 const int kHighVarianceThreshold = 2; |
44 | |
45 // How large window we use to calculate the framerate/bitrate. | |
46 const int kRateStatisticsWindowSizeMs = 1000; | |
42 } // namespace | 47 } // namespace |
43 | 48 |
44 ReceiveStatisticsProxy::ReceiveStatisticsProxy( | 49 ReceiveStatisticsProxy::ReceiveStatisticsProxy( |
45 const VideoReceiveStream::Config* config, | 50 const VideoReceiveStream::Config* config, |
46 Clock* clock) | 51 Clock* clock) |
47 : clock_(clock), | 52 : clock_(clock), |
48 config_(*config), | 53 config_(*config), |
49 start_ms_(clock->TimeInMilliseconds()), | 54 start_ms_(clock->TimeInMilliseconds()), |
50 last_sample_time_(clock->TimeInMilliseconds()), | 55 last_sample_time_(clock->TimeInMilliseconds()), |
51 fps_threshold_(kLowFpsThreshold, | 56 fps_threshold_(kLowFpsThreshold, |
52 kHighFpsThreshold, | 57 kHighFpsThreshold, |
53 kBadFraction, | 58 kBadFraction, |
54 kNumMeasurements), | 59 kNumMeasurements), |
55 qp_threshold_(kLowQpThresholdVp8, | 60 qp_threshold_(kLowQpThresholdVp8, |
56 kHighQpThresholdVp8, | 61 kHighQpThresholdVp8, |
57 kBadFraction, | 62 kBadFraction, |
58 kNumMeasurements), | 63 kNumMeasurements), |
59 variance_threshold_(kLowVarianceThreshold, | 64 variance_threshold_(kLowVarianceThreshold, |
60 kHighVarianceThreshold, | 65 kHighVarianceThreshold, |
61 kBadFraction, | 66 kBadFraction, |
62 kNumMeasurementsVariance), | 67 kNumMeasurementsVariance), |
63 // 1000ms window, scale 1000 for ms to s. | 68 // 1000ms window, scale 1000 for ms to s. |
64 decode_fps_estimator_(1000, 1000), | 69 decode_fps_estimator_(1000, 1000), |
65 renders_fps_estimator_(1000, 1000), | 70 renders_fps_estimator_(1000, 1000), |
66 render_fps_tracker_(100, 10u), | 71 render_fps_tracker_(100, 10u), |
67 render_pixel_tracker_(100, 10u), | 72 render_pixel_tracker_(100, 10u), |
68 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), | 73 freq_offset_counter_(clock, nullptr, kFreqOffsetProcessIntervalMs), |
69 first_report_block_time_ms_(-1) { | 74 first_report_block_time_ms_(-1), |
75 avg_rtt_ms_(0) { | |
70 stats_.ssrc = config_.rtp.remote_ssrc; | 76 stats_.ssrc = config_.rtp.remote_ssrc; |
71 for (auto it : config_.rtp.rtx) | 77 for (auto it : config_.rtp.rtx) |
72 rtx_stats_[it.second.ssrc] = StreamDataCounters(); | 78 rtx_stats_[it.second.ssrc] = StreamDataCounters(); |
73 } | 79 } |
74 | 80 |
75 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { | 81 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { |
76 UpdateHistograms(); | 82 UpdateHistograms(); |
77 } | 83 } |
78 | 84 |
79 void ReceiveStatisticsProxy::UpdateHistograms() { | 85 void ReceiveStatisticsProxy::UpdateHistograms() { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); | 117 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.AVSyncOffsetInMs", sync_offset_ms); |
112 } | 118 } |
113 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); | 119 AggregatedStats freq_offset_stats = freq_offset_counter_.GetStats(); |
114 if (freq_offset_stats.num_samples > 0) { | 120 if (freq_offset_stats.num_samples > 0) { |
115 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", | 121 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtpToNtpFreqOffsetInKhz", |
116 freq_offset_stats.average); | 122 freq_offset_stats.average); |
117 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " | 123 LOG(LS_INFO) << "WebRTC.Video.RtpToNtpFreqOffsetInKhz, " |
118 << freq_offset_stats.ToString(); | 124 << freq_offset_stats.ToString(); |
119 } | 125 } |
120 | 126 |
127 if (stats_.frame_counts.key_frames > 0 || | |
128 stats_.frame_counts.delta_frames > 0) { | |
129 float num_key_frames = stats_.frame_counts.key_frames; | |
130 float num_total_frames = | |
131 stats_.frame_counts.key_frames + stats_.frame_counts.delta_frames; | |
132 int key_frames_permille = | |
133 (num_key_frames * 1000.0f / num_total_frames + 0.5f); | |
134 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesReceivedInPermille", | |
135 key_frames_permille); | |
136 } | |
137 | |
121 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples); | 138 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples); |
122 if (qp != -1) | 139 if (qp != -1) |
123 RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp); | 140 RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp); |
124 | 141 |
125 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and | 142 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and |
126 // not per frame. Change decode time to include every frame. | 143 // not per frame. Change decode time to include every frame. |
127 const int kMinRequiredDecodeSamples = 5; | 144 const int kMinRequiredDecodeSamples = 5; |
128 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples); | 145 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples); |
129 if (decode_ms != -1) | 146 if (decode_ms != -1) |
130 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms); | 147 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms); |
131 | 148 |
132 if (field_trial::FindFullName("WebRTC-NewVideoJitterBuffer") != | 149 int jb_delay_ms = jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples); |
133 "Enabled") { | 150 if (jb_delay_ms != -1) { |
134 int jb_delay_ms = | 151 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs", |
135 jitter_buffer_delay_counter_.Avg(kMinRequiredDecodeSamples); | 152 jb_delay_ms); |
136 if (jb_delay_ms != -1) { | |
137 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.JitterBufferDelayInMs", | |
138 jb_delay_ms); | |
139 } | |
140 } | 153 } |
154 | |
141 int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples); | 155 int target_delay_ms = target_delay_counter_.Avg(kMinRequiredDecodeSamples); |
142 if (target_delay_ms != -1) { | 156 if (target_delay_ms != -1) { |
143 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs", target_delay_ms); | 157 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.TargetDelayInMs", target_delay_ms); |
144 } | 158 } |
145 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples); | 159 int current_delay_ms = current_delay_counter_.Avg(kMinRequiredDecodeSamples); |
146 if (current_delay_ms != -1) { | 160 if (current_delay_ms != -1) { |
147 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", | 161 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.CurrentDelayInMs", |
148 current_delay_ms); | 162 current_delay_ms); |
149 } | 163 } |
150 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples); | 164 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 | 271 |
258 LOG(LS_VERBOSE) << "SAMPLE: sample_length: " << (now - last_sample_time_) | 272 LOG(LS_VERBOSE) << "SAMPLE: sample_length: " << (now - last_sample_time_) |
259 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp | 273 << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp |
260 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad | 274 << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad |
261 << " fps_variance: " << fps_variance; | 275 << " fps_variance: " << fps_variance; |
262 | 276 |
263 last_sample_time_ = now; | 277 last_sample_time_ = now; |
264 qp_sample_.Reset(); | 278 qp_sample_.Reset(); |
265 } | 279 } |
266 | 280 |
281 void ReceiveStatisticsProxy::UpdateFrameAndBitrate(int64_t now_ms) const { | |
282 int64_t old_frames_ms = now_ms - kRateStatisticsWindowSizeMs; | |
283 while (!frame_window_.empty() && | |
284 frame_window_.begin()->first < old_frames_ms) { | |
285 frame_window_accumulated_bytes_ -= frame_window_.begin()->second; | |
286 frame_window_.erase(frame_window_.begin()); | |
287 } | |
288 | |
289 int framerate = | |
290 (frame_window_.size() * 1000 + 500) / kRateStatisticsWindowSizeMs; | |
291 size_t bitrate_bps = | |
292 frame_window_accumulated_bytes_ * 8000 / kRateStatisticsWindowSizeMs; | |
293 stats_.network_frame_rate = framerate; | |
294 stats_.total_bitrate_bps = bitrate_bps; | |
295 } | |
296 | |
267 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { | 297 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { |
268 rtc::CritScope lock(&crit_); | 298 rtc::CritScope lock(&crit_); |
299 UpdateFrameAndBitrate(clock_->TimeInMilliseconds()); | |
269 return stats_; | 300 return stats_; |
270 } | 301 } |
271 | 302 |
272 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { | 303 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { |
273 rtc::CritScope lock(&crit_); | 304 rtc::CritScope lock(&crit_); |
274 stats_.current_payload_type = payload_type; | 305 stats_.current_payload_type = payload_type; |
275 } | 306 } |
276 | 307 |
277 void ReceiveStatisticsProxy::OnDecoderImplementationName( | 308 void ReceiveStatisticsProxy::OnDecoderImplementationName( |
278 const char* implementation_name) { | 309 const char* implementation_name) { |
279 rtc::CritScope lock(&crit_); | 310 rtc::CritScope lock(&crit_); |
280 stats_.decoder_implementation_name = implementation_name; | 311 stats_.decoder_implementation_name = implementation_name; |
281 } | 312 } |
282 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, | 313 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, |
283 unsigned int bitrate_bps) { | 314 unsigned int bitrate_bps) { |
284 rtc::CritScope lock(&crit_); | 315 rtc::CritScope lock(&crit_); |
285 QualitySample(); | 316 QualitySample(); |
philipel
2017/01/11 16:12:34
This function is still called about every second f
stefan-webrtc
2017/01/12 14:16:15
Ouch... Why is it called here? Can we move it to s
philipel
2017/01/12 16:41:35
I will take a look at it in one of my clean up CLs
| |
286 stats_.network_frame_rate = framerate; | |
287 stats_.total_bitrate_bps = bitrate_bps; | |
288 } | 317 } |
289 | 318 |
290 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, | 319 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, |
291 int max_decode_ms, | 320 int max_decode_ms, |
292 int current_delay_ms, | 321 int current_delay_ms, |
293 int target_delay_ms, | 322 int target_delay_ms, |
294 int jitter_buffer_ms, | 323 int jitter_buffer_ms, |
295 int min_playout_delay_ms, | 324 int min_playout_delay_ms, |
296 int render_delay_ms, | 325 int render_delay_ms) { |
297 int64_t rtt_ms) { | |
298 rtc::CritScope lock(&crit_); | 326 rtc::CritScope lock(&crit_); |
299 stats_.decode_ms = decode_ms; | 327 stats_.decode_ms = decode_ms; |
300 stats_.max_decode_ms = max_decode_ms; | 328 stats_.max_decode_ms = max_decode_ms; |
301 stats_.current_delay_ms = current_delay_ms; | 329 stats_.current_delay_ms = current_delay_ms; |
302 stats_.target_delay_ms = target_delay_ms; | 330 stats_.target_delay_ms = target_delay_ms; |
303 stats_.jitter_buffer_ms = jitter_buffer_ms; | 331 stats_.jitter_buffer_ms = jitter_buffer_ms; |
304 stats_.min_playout_delay_ms = min_playout_delay_ms; | 332 stats_.min_playout_delay_ms = min_playout_delay_ms; |
305 stats_.render_delay_ms = render_delay_ms; | 333 stats_.render_delay_ms = render_delay_ms; |
306 decode_time_counter_.Add(decode_ms); | 334 decode_time_counter_.Add(decode_ms); |
307 jitter_buffer_delay_counter_.Add(jitter_buffer_ms); | 335 jitter_buffer_delay_counter_.Add(jitter_buffer_ms); |
308 target_delay_counter_.Add(target_delay_ms); | 336 target_delay_counter_.Add(target_delay_ms); |
309 current_delay_counter_.Add(current_delay_ms); | 337 current_delay_counter_.Add(current_delay_ms); |
310 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time + | 338 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time + |
311 // render delay). | 339 // render delay). |
312 delay_counter_.Add(target_delay_ms + rtt_ms / 2); | 340 delay_counter_.Add(target_delay_ms + avg_rtt_ms_ / 2); |
313 } | 341 } |
314 | 342 |
315 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated( | 343 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated( |
316 uint32_t ssrc, | 344 uint32_t ssrc, |
317 const RtcpPacketTypeCounter& packet_counter) { | 345 const RtcpPacketTypeCounter& packet_counter) { |
318 rtc::CritScope lock(&crit_); | 346 rtc::CritScope lock(&crit_); |
319 if (stats_.ssrc != ssrc) | 347 if (stats_.ssrc != ssrc) |
320 return; | 348 return; |
321 stats_.rtcp_packet_type_counts = packet_counter; | 349 stats_.rtcp_packet_type_counts = packet_counter; |
322 } | 350 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) | 434 if (estimated_freq_khz < kMaxFreqKhz && estimated_freq_khz > 0.0) |
407 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); | 435 offset_khz = static_cast<int>(std::fabs(estimated_freq_khz - 90.0) + 0.5); |
408 | 436 |
409 freq_offset_counter_.Add(offset_khz); | 437 freq_offset_counter_.Add(offset_khz); |
410 } | 438 } |
411 | 439 |
412 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, | 440 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, |
413 uint32_t frameRate) { | 441 uint32_t frameRate) { |
414 } | 442 } |
415 | 443 |
444 void ReceiveStatisticsProxy::OnCompleteFrame(bool is_keyframe, | |
445 size_t size_bytes) { | |
446 rtc::CritScope lock(&crit_); | |
447 if (is_keyframe) | |
448 ++stats_.frame_counts.key_frames; | |
449 else | |
450 ++stats_.frame_counts.delta_frames; | |
451 | |
452 int64_t now_ms = clock_->TimeInMilliseconds(); | |
453 frame_window_accumulated_bytes_ += size_bytes; | |
454 frame_window_.insert(std::make_pair(now_ms, size_bytes)); | |
455 UpdateFrameAndBitrate(now_ms); | |
456 } | |
457 | |
416 void ReceiveStatisticsProxy::OnFrameCountsUpdated( | 458 void ReceiveStatisticsProxy::OnFrameCountsUpdated( |
417 const FrameCounts& frame_counts) { | 459 const FrameCounts& frame_counts) { |
418 rtc::CritScope lock(&crit_); | 460 rtc::CritScope lock(&crit_); |
419 stats_.frame_counts = frame_counts; | 461 stats_.frame_counts = frame_counts; |
420 } | 462 } |
421 | 463 |
422 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { | 464 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { |
423 rtc::CritScope lock(&crit_); | 465 rtc::CritScope lock(&crit_); |
424 stats_.discarded_packets = discarded_packets; | 466 stats_.discarded_packets = discarded_packets; |
425 } | 467 } |
(...skipping 21 matching lines...) Expand all Loading... | |
447 if (num_samples < min_required_samples || num_samples == 0) | 489 if (num_samples < min_required_samples || num_samples == 0) |
448 return -1; | 490 return -1; |
449 return static_cast<int>(sum / num_samples); | 491 return static_cast<int>(sum / num_samples); |
450 } | 492 } |
451 | 493 |
452 void ReceiveStatisticsProxy::SampleCounter::Reset() { | 494 void ReceiveStatisticsProxy::SampleCounter::Reset() { |
453 num_samples = 0; | 495 num_samples = 0; |
454 sum = 0; | 496 sum = 0; |
455 } | 497 } |
456 | 498 |
499 void ReceiveStatisticsProxy::OnRttUpdate(int64_t avg_rtt_ms, | |
500 int64_t max_rtt_ms) { | |
501 rtc::CritScope lock(&crit_); | |
502 avg_rtt_ms_ = avg_rtt_ms; | |
503 } | |
504 | |
457 } // namespace webrtc | 505 } // namespace webrtc |
OLD | NEW |