• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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