1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/video/receive_statistics_proxy.h"
12
13 #include <cmath>
14
15 #include "webrtc/base/checks.h"
16 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
17 #include "webrtc/system_wrappers/include/clock.h"
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/include/metrics.h"
20
21 namespace webrtc {
22
ReceiveStatisticsProxy(uint32_t ssrc,Clock * clock)23 ReceiveStatisticsProxy::ReceiveStatisticsProxy(uint32_t ssrc, Clock* clock)
24 : clock_(clock),
25 // 1000ms window, scale 1000 for ms to s.
26 decode_fps_estimator_(1000, 1000),
27 renders_fps_estimator_(1000, 1000),
28 render_fps_tracker_(100u, 10u),
29 render_pixel_tracker_(100u, 10u) {
30 stats_.ssrc = ssrc;
31 }
32
~ReceiveStatisticsProxy()33 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
34 UpdateHistograms();
35 }
36
UpdateHistograms()37 void ReceiveStatisticsProxy::UpdateHistograms() {
38 int fraction_lost = report_block_stats_.FractionLostInPercent();
39 if (fraction_lost != -1) {
40 RTC_HISTOGRAM_PERCENTAGE_SPARSE("WebRTC.Video.ReceivedPacketsLostInPercent",
41 fraction_lost);
42 }
43 const int kMinRequiredSamples = 200;
44 int samples = static_cast<int>(render_fps_tracker_.TotalSampleCount());
45 if (samples > kMinRequiredSamples) {
46 RTC_HISTOGRAM_COUNTS_SPARSE_100("WebRTC.Video.RenderFramesPerSecond",
47 round(render_fps_tracker_.ComputeTotalRate()));
48 RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Video.RenderSqrtPixelsPerSecond",
49 round(render_pixel_tracker_.ComputeTotalRate()));
50 }
51 int width = render_width_counter_.Avg(kMinRequiredSamples);
52 int height = render_height_counter_.Avg(kMinRequiredSamples);
53 if (width != -1) {
54 RTC_HISTOGRAM_COUNTS_SPARSE_10000("WebRTC.Video.ReceivedWidthInPixels",
55 width);
56 RTC_HISTOGRAM_COUNTS_SPARSE_10000("WebRTC.Video.ReceivedHeightInPixels",
57 height);
58 }
59 int qp = qp_counters_.vp8.Avg(kMinRequiredSamples);
60 if (qp != -1)
61 RTC_HISTOGRAM_COUNTS_SPARSE_200("WebRTC.Video.Decoded.Vp8.Qp", qp);
62
63 // TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and
64 // not per frame. Change decode time to include every frame.
65 const int kMinRequiredDecodeSamples = 5;
66 int decode_ms = decode_time_counter_.Avg(kMinRequiredDecodeSamples);
67 if (decode_ms != -1)
68 RTC_HISTOGRAM_COUNTS_SPARSE_1000("WebRTC.Video.DecodeTimeInMs", decode_ms);
69
70 int delay_ms = delay_counter_.Avg(kMinRequiredDecodeSamples);
71 if (delay_ms != -1)
72 RTC_HISTOGRAM_COUNTS_SPARSE_10000("WebRTC.Video.OnewayDelayInMs", delay_ms);
73 }
74
GetStats() const75 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
76 rtc::CritScope lock(&crit_);
77 return stats_;
78 }
79
OnIncomingPayloadType(int payload_type)80 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) {
81 rtc::CritScope lock(&crit_);
82 stats_.current_payload_type = payload_type;
83 }
84
OnDecoderImplementationName(const char * implementation_name)85 void ReceiveStatisticsProxy::OnDecoderImplementationName(
86 const char* implementation_name) {
87 rtc::CritScope lock(&crit_);
88 stats_.decoder_implementation_name = implementation_name;
89 }
OnIncomingRate(unsigned int framerate,unsigned int bitrate_bps)90 void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate,
91 unsigned int bitrate_bps) {
92 rtc::CritScope lock(&crit_);
93 stats_.network_frame_rate = framerate;
94 stats_.total_bitrate_bps = bitrate_bps;
95 }
96
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)97 void ReceiveStatisticsProxy::OnDecoderTiming(int decode_ms,
98 int max_decode_ms,
99 int current_delay_ms,
100 int target_delay_ms,
101 int jitter_buffer_ms,
102 int min_playout_delay_ms,
103 int render_delay_ms,
104 int64_t rtt_ms) {
105 rtc::CritScope lock(&crit_);
106 stats_.decode_ms = decode_ms;
107 stats_.max_decode_ms = max_decode_ms;
108 stats_.current_delay_ms = current_delay_ms;
109 stats_.target_delay_ms = target_delay_ms;
110 stats_.jitter_buffer_ms = jitter_buffer_ms;
111 stats_.min_playout_delay_ms = min_playout_delay_ms;
112 stats_.render_delay_ms = render_delay_ms;
113 decode_time_counter_.Add(decode_ms);
114 // Network delay (rtt/2) + target_delay_ms (jitter delay + decode time +
115 // render delay).
116 delay_counter_.Add(target_delay_ms + rtt_ms / 2);
117 }
118
RtcpPacketTypesCounterUpdated(uint32_t ssrc,const RtcpPacketTypeCounter & packet_counter)119 void ReceiveStatisticsProxy::RtcpPacketTypesCounterUpdated(
120 uint32_t ssrc,
121 const RtcpPacketTypeCounter& packet_counter) {
122 rtc::CritScope lock(&crit_);
123 if (stats_.ssrc != ssrc)
124 return;
125 stats_.rtcp_packet_type_counts = packet_counter;
126 }
127
StatisticsUpdated(const webrtc::RtcpStatistics & statistics,uint32_t ssrc)128 void ReceiveStatisticsProxy::StatisticsUpdated(
129 const webrtc::RtcpStatistics& statistics,
130 uint32_t ssrc) {
131 rtc::CritScope lock(&crit_);
132 // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
133 // receive stats from one of them.
134 if (stats_.ssrc != ssrc)
135 return;
136 stats_.rtcp_stats = statistics;
137 report_block_stats_.Store(statistics, ssrc, 0);
138 }
139
CNameChanged(const char * cname,uint32_t ssrc)140 void ReceiveStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
141 rtc::CritScope lock(&crit_);
142 // TODO(pbos): Handle both local and remote ssrcs here and RTC_DCHECK that we
143 // receive stats from one of them.
144 if (stats_.ssrc != ssrc)
145 return;
146 stats_.c_name = cname;
147 }
148
DataCountersUpdated(const webrtc::StreamDataCounters & counters,uint32_t ssrc)149 void ReceiveStatisticsProxy::DataCountersUpdated(
150 const webrtc::StreamDataCounters& counters,
151 uint32_t ssrc) {
152 rtc::CritScope lock(&crit_);
153 if (stats_.ssrc != ssrc)
154 return;
155 stats_.rtp_stats = counters;
156 }
157
OnDecodedFrame()158 void ReceiveStatisticsProxy::OnDecodedFrame() {
159 uint64_t now = clock_->TimeInMilliseconds();
160
161 rtc::CritScope lock(&crit_);
162 decode_fps_estimator_.Update(1, now);
163 stats_.decode_frame_rate = decode_fps_estimator_.Rate(now);
164 }
165
OnRenderedFrame(int width,int height)166 void ReceiveStatisticsProxy::OnRenderedFrame(int width, int height) {
167 RTC_DCHECK_GT(width, 0);
168 RTC_DCHECK_GT(height, 0);
169 uint64_t now = clock_->TimeInMilliseconds();
170
171 rtc::CritScope lock(&crit_);
172 renders_fps_estimator_.Update(1, now);
173 stats_.render_frame_rate = renders_fps_estimator_.Rate(now);
174 render_width_counter_.Add(width);
175 render_height_counter_.Add(height);
176 render_fps_tracker_.AddSamples(1);
177 render_pixel_tracker_.AddSamples(sqrt(width * height));
178 }
179
OnReceiveRatesUpdated(uint32_t bitRate,uint32_t frameRate)180 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate,
181 uint32_t frameRate) {
182 }
183
OnFrameCountsUpdated(const FrameCounts & frame_counts)184 void ReceiveStatisticsProxy::OnFrameCountsUpdated(
185 const FrameCounts& frame_counts) {
186 rtc::CritScope lock(&crit_);
187 stats_.frame_counts = frame_counts;
188 }
189
OnDiscardedPacketsUpdated(int discarded_packets)190 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) {
191 rtc::CritScope lock(&crit_);
192 stats_.discarded_packets = discarded_packets;
193 }
194
OnPreDecode(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)195 void ReceiveStatisticsProxy::OnPreDecode(
196 const EncodedImage& encoded_image,
197 const CodecSpecificInfo* codec_specific_info) {
198 if (codec_specific_info == nullptr || encoded_image.qp_ == -1) {
199 return;
200 }
201 if (codec_specific_info->codecType == kVideoCodecVP8) {
202 qp_counters_.vp8.Add(encoded_image.qp_);
203 }
204 }
205
Add(int sample)206 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
207 sum += sample;
208 ++num_samples;
209 }
210
Avg(int min_required_samples) const211 int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
212 if (num_samples < min_required_samples || num_samples == 0)
213 return -1;
214 return sum / num_samples;
215 }
216
217 } // namespace webrtc
218