diff options
Diffstat (limited to 'webrtc/video/receive_statistics_proxy.cc')
-rw-r--r-- | webrtc/video/receive_statistics_proxy.cc | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc new file mode 100644 index 0000000000..eec2bc8301 --- /dev/null +++ b/webrtc/video/receive_statistics_proxy.cc @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/video/receive_statistics_proxy.h" + +#include <cmath> + +#include "webrtc/base/checks.h" +#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" +#include "webrtc/system_wrappers/include/clock.h" +#include "webrtc/system_wrappers/include/critical_section_wrapper.h" +#include "webrtc/system_wrappers/include/metrics.h" + +namespace webrtc { + +ReceiveStatisticsProxy::ReceiveStatisticsProxy(uint32_t ssrc, Clock* clock) + : clock_(clock), + // 1000ms window, scale 1000 for ms to s. + decode_fps_estimator_(1000, 1000), + renders_fps_estimator_(1000, 1000), + render_fps_tracker_(100u, 10u), + render_pixel_tracker_(100u, 10u) { + stats_.ssrc = ssrc; +} + +ReceiveStatisticsProxy::~ReceiveStatisticsProxy() { + UpdateHistograms(); +} + +void ReceiveStatisticsProxy::UpdateHistograms() { + int fraction_lost = report_block_stats_.FractionLostInPercent(); + if (fraction_lost != -1) { + RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.ReceivedPacketsLostInPercent", + fraction_lost); + } + const int kMinRequiredSamples = 200; + int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount()); + if (samples > kMinRequiredSamples) { + RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.RenderFramesPerSecond", + static_cast<int>(render_fps_tracker_.ComputeTotalRate())); + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.RenderSqrtPixelsPerSecond", + static_cast<int>(render_pixel_tracker_.ComputeTotalRate())); + } + int width = render_width_counter_.Avg(kMinRequiredSamples); + int height = render_height_counter_.Avg(kMinRequiredSamples); + if (width != -1) { + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels", width); + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels", height); + } + int qp = qp_counters_.vp8.Avg(kMinRequiredSamples); + if (qp != -1) + RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp); + + // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and + // not per frame. Change decode time to include every frame. + const int kMinRequiredDecodeSamples = 5; + int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples); + if (decode_ms != -1) + RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.DecodeTimeInMs", decode_ms); + + int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples); + if (delay_ms != -1) + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.OnewayDelayInMs", delay_ms); +} + +VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const { + rtc::CritScope lock(&crit_); + return stats_; +} + +void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { + rtc::CritScope lock(&crit_); + stats_.current_payload_type = payload_type; +} + +void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, + unsigned int bitrate_bps) { + rtc::CritScope lock(&crit_); + stats_.network_frame_rate = framerate; + stats_.total_bitrate_bps = bitrate_bps; +} + +void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms, + int max_decode_ms, + int current_delay_ms, + int target_delay_ms, + int jitter_buffer_ms, + int min_playout_delay_ms, + int render_delay_ms, + int64_t rtt_ms) { + rtc::CritScope lock(&crit_); + stats_.decode_ms = decode_ms; + stats_.max_decode_ms = max_decode_ms; + stats_.current_delay_ms = current_delay_ms; + stats_.target_delay_ms = target_delay_ms; + stats_.jitter_buffer_ms = jitter_buffer_ms; + stats_.min_playout_delay_ms = min_playout_delay_ms; + stats_.render_delay_ms = render_delay_ms; + decode_time_counter_.Add(decode_ms); + // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time + + // render delay). + delay_counter_.Add(target_delay_ms + rtt_ms / 2); +} + +void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated( + uint32_t ssrc, + const RtcpPacketTypeCounter& packet_counter) { + rtc::CritScope lock(&crit_); + if (stats_.ssrc != ssrc) + return; + stats_.rtcp_packet_type_counts = packet_counter; +} + +void ReceiveStatisticsProxy::StatisticsUpdated( + const webrtc::RtcpStatistics& statistics, + uint32_t ssrc) { + rtc::CritScope lock(&crit_); + // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we + // receive stats from one of them. + if (stats_.ssrc != ssrc) + return; + stats_.rtcp_stats = statistics; + report_block_stats_.Store(statistics, ssrc, 0); +} + +void ReceiveStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) { + rtc::CritScope lock(&crit_); + // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we + // receive stats from one of them. + if (stats_.ssrc != ssrc) + return; + stats_.c_name = cname; +} + +void ReceiveStatisticsProxy::DataCountersUpdated( + const webrtc::StreamDataCounters& counters, + uint32_t ssrc) { + rtc::CritScope lock(&crit_); + if (stats_.ssrc != ssrc) + return; + stats_.rtp_stats = counters; +} + +void ReceiveStatisticsProxy::OnDecodedFrame() { + uint64_t now = clock_->TimeInMilliseconds(); + + rtc::CritScope lock(&crit_); + decode_fps_estimator_.Update(1, now); + stats_.decode_frame_rate = decode_fps_estimator_.Rate(now); +} + +void ReceiveStatisticsProxy::OnRenderedFrame(int width, int height) { + RTC_DCHECK_GT(width, 0); + RTC_DCHECK_GT(height, 0); + uint64_t now = clock_->TimeInMilliseconds(); + + rtc::CritScope lock(&crit_); + renders_fps_estimator_.Update(1, now); + stats_.render_frame_rate = renders_fps_estimator_.Rate(now); + render_width_counter_.Add(width); + render_height_counter_.Add(height); + render_fps_tracker_.AddSamples(1); + render_pixel_tracker_.AddSamples(sqrt(width * height)); +} + +void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate, + uint32_t frameRate) { +} + +void ReceiveStatisticsProxy::OnFrameCountsUpdated( + const FrameCounts& frame_counts) { + rtc::CritScope lock(&crit_); + stats_.frame_counts = frame_counts; +} + +void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) { + rtc::CritScope lock(&crit_); + stats_.discarded_packets = discarded_packets; +} + +void ReceiveStatisticsProxy::OnPreDecode( + const EncodedImage& encoded_image, + const CodecSpecificInfo* codec_specific_info) { + if (codec_specific_info == nullptr || encoded_image.qp_ == -1) { + return; + } + if (codec_specific_info->codecType == kVideoCodecVP8) { + qp_counters_.vp8.Add(encoded_image.qp_); + } +} + +void ReceiveStatisticsProxy::SampleCounter::Add(int sample) { + sum += sample; + ++num_samples; +} + +int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const { + if (num_samples < min_required_samples || num_samples == 0) + return -1; + return sum / num_samples; +} + +} // namespace webrtc |