Home | History | Annotate | Download | only in video
      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 
     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 
     33 ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
     34   UpdateHistograms();
     35 }
     36 
     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 
     75 VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
     76   rtc::CritScope lock(&crit_);
     77   return stats_;
     78 }
     79 
     80 void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) {
     81   rtc::CritScope lock(&crit_);
     82   stats_.current_payload_type = payload_type;
     83 }
     84 
     85 void ReceiveStatisticsProxy::OnDecoderImplementationName(
     86     const char* implementation_name) {
     87   rtc::CritScope lock(&crit_);
     88   stats_.decoder_implementation_name = implementation_name;
     89 }
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    180 void ReceiveStatisticsProxy::OnReceiveRatesUpdated(uint32_t bitRate,
    181                                                    uint32_t frameRate) {
    182 }
    183 
    184 void ReceiveStatisticsProxy::OnFrameCountsUpdated(
    185     const FrameCounts& frame_counts) {
    186   rtc::CritScope lock(&crit_);
    187   stats_.frame_counts = frame_counts;
    188 }
    189 
    190 void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) {
    191   rtc::CritScope lock(&crit_);
    192   stats_.discarded_packets = discarded_packets;
    193 }
    194 
    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 
    206 void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
    207   sum += sample;
    208   ++num_samples;
    209 }
    210 
    211 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