• WebRTC源码之视频质量统计数据中基础数据结构分析


    WebRTC源码之视频质量统计数据的数据结构分析


    WebRTC专题开嗨鸭 !!!

    一、 WebRTC 线程模型

    1、WebRTC中线程模型和常见线程模型介绍

    2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用

    二、 WebRTC媒体协商

    三、 WebRTC 音频数据采集

    四、 WebRTC 音频引擎(编解码和3A算法)

    五、 WebRTC 视频数据采集

    六、 WebRTC 视频引擎( 编解码)

    七、 WebRTC 网络传输

    1、WebRTC的ICE之STUN协议

    2、WebRTC的ICE之Dtls/SSL/TLSv1.x协议详解

    八、 WebRTC服务质量(Qos)

    1、WebRTC中RTCP协议详解

    2、WebRTC中RTP协议详解

    3、WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传

    4、WebRTC源码之视频质量统计数据的数据结构分析

    九、 NetEQ

    十、 Simulcast与SVC

    前言

    分析视频数据

    video/send_statistics_proxy.h中进行数据统计 中基础数据结构支撑的

    视频质量统计数据的数据结构分析

    目录位置

    src/video/stats_counter.h
    src/video/stats_counter.cc
    
    • 1
    • 2
    1. 平均计数器
    2. 最大计数器
    3. 百分比计数器
    4. 千分比计数器
    5. 速率计数器
    6. 速率Acc计数器

    一、 工具类介绍 (定期计算的指标的最小值、平均值和最大值)

    • AggregatedStats 定期计算的指标的最小值、平均值和最大值
    • AggregatedCounter 定期计算的指标的最小值、平均值和最大值
    • Samples 间隔内保存收集的样本

    1、AggregatedStats

    //聚合统计
    struct AggregatedStats 
    {
      std::string ToString() const;
      std::string ToStringWithMultiplier(int multiplier) const;
    
      int64_t num_samples = 0; // 次数叠加值
      int min = -1;
      int max = -1;
      int average = -1;
      // TODO(asapersson): Consider adding median/percentiles.
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、AggregatedCounter

    //持有定期计算的指标
    //
    class AggregatedCounter {
     public:
      AggregatedCounter() : last_sample_(0), sum_samples_(0) {}
      ~AggregatedCounter() {}
    
      void Add(int sample) {
        last_sample_ = sample;
        sum_samples_ += sample;
        ++stats_.num_samples;
        if (stats_.num_samples == 1) {
          stats_.min = sample;
          stats_.max = sample;
        }
        stats_.min = std::min(sample, stats_.min);
        stats_.max = std::max(sample, stats_.max);
      }
    
      AggregatedStats ComputeStats() {
        Compute();
        return stats_;
      }
    
      bool Empty() const { return stats_.num_samples == 0; }
    
      int last_sample() const { return last_sample_; }
    
     private:
      void Compute() {
        if (stats_.num_samples == 0) {
          return;
        }
        // 平均值  公式 = ( 每个数据的叠加值  + 次数的平均数)/ 次数
        stats_.average =
            (sum_samples_ + stats_.num_samples / 2) / stats_.num_samples;
      }
      int last_sample_;        //记录上一次的数据值
      int64_t sum_samples_;    // 每个数据的叠加值
      AggregatedStats stats_;  // 记录次数 和 min、avg、max
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3、 Samples 间隔内保存收集的样本

    // 类在进程间隔内保存收集的样本
    class Samples {
     public:
      Samples() : total_count_(0) {}
      ~Samples() {}
    
      void Add(int sample, uint32_t stream_id) 
      {
        samples_[stream_id].Add(sample);
        ++total_count_;
      }
    
      void Set(int64_t sample, uint32_t stream_id) 
      {
        samples_[stream_id].Set(sample);
    	//改变总数据的后 为什么还要修改 总次数呢???
    	++total_count_;
      }
      void SetLast(int64_t sample, uint32_t stream_id) 
      {
        samples_[stream_id].SetLast(sample);
      }
      int64_t GetLast(uint32_t stream_id) { return samples_[stream_id].GetLast(); }
    
      int64_t Count() const { return total_count_; }
      bool Empty() const { return total_count_ == 0; }
    
      int64_t Sum() const 
      {
        int64_t sum = 0;
        for (const auto& it : samples_)
        {
           sum += it.second.sum_;
    	}
        return sum;
      }
    
      int Max() const 
      {
        int max = std::numeric_limits<int>::min();
        for (const auto& it : samples_)
        {
          max = std::max(it.second.max_, max);
    	}
        return max;
      }
    
      void Reset() {
        for (auto& it : samples_) 
    	{
          it.second.Reset();
        }
        total_count_ = 0;
      }
    
      // 这个接口意义是什么???
      int64_t Diff() const 
      {
        int64_t sum_diff = 0;
        int count = 0;
        for (const auto& it : samples_) 
    	{
          if (it.second.count_ > 0) 
    	  {
            int64_t diff = it.second.sum_ - it.second.last_sum_;
            if (diff >= 0) 
    		{
              sum_diff += diff;
              ++count;
            }
          }
        }
        return (count > 0) ? sum_diff : -1;
      }
    
     private:
      struct Stats {
        void Add(int sample)
    	{
          sum_ += sample;
          ++count_;
          max_ = std::max(sample, max_);
        }
        void Set(int64_t sample)
    	{
          sum_ = sample;
          ++count_;
        }
        void SetLast(int64_t sample) { last_sum_ = sample; }
        int64_t GetLast() const { return last_sum_; }
        void Reset() {
          if (count_ > 0) {
            last_sum_ = sum_;
          }
          sum_ = 0;
          count_ = 0;
          max_ = std::numeric_limits<int>::min();
        }
    
        int max_ = std::numeric_limits<int>::min();
        int64_t count_ = 0;
        int64_t sum_ = 0;
        int64_t last_sum_ = 0;
      };
    
      int64_t total_count_;
      std::map<uint32_t, Stats> samples_;  //key : 视频流的id 和统计的数据 Gathered samples mapped by stream id.
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    二、 视频数据统计信息

    1、StatsCounter 视频统计中基类

    // Classes which periodically computes a metric.
    //
    // During a period, |kProcessIntervalMs|, different metrics can be computed e.g:
    // - |AvgCounter|: average of samples
    // - |PercentCounter|: percentage of samples
    // - |PermilleCounter|: permille of samples
    //
    // Each periodic metric can be either:
    // - reported to an |observer| each period
    // - aggregated during the call (e.g. min, max, average)
    //
    //                 periodically computed
    //                    GetMetric()            GetMetric()   => AggregatedStats
    //                        ^                      ^            (e.g. min/max/avg)
    //                        |                      |
    // |   *    *  *       *  |  **    *   * *     * | ...
    // |<- process interval ->|
    //
    // (*) - samples
    //
    //
    // Example usage:
    //
    // AvgCounter counter(&clock, nullptr);
    // counter.Add(5);
    // counter.Add(1);
    // counter.Add(6);   // process interval passed -> GetMetric() avg:4
    // counter.Add(7);
    // counter.Add(3);   // process interval passed -> GetMetric() avg:5
    // counter.Add(10);
    // counter.Add(20);  // process interval passed -> GetMetric() avg:15
    // AggregatedStats stats = counter.GetStats();
    // stats: {min:4, max:15, avg:8}
    //
    
    // Note: StatsCounter takes ownership of |observer|.
    
    class StatsCounter {
     public:
      virtual ~StatsCounter();
    
      // Gets metric within an interval. Returns true on success false otherwise.
      // 1. 获取间隔内的度量。成功时返回true,否则返回false。
      virtual bool GetMetric(int* metric) const = 0;
    
      // Gets the value to use for an interval without samples.
      // 2. 获取用于不带样本的间隔的值
      virtual int GetValueForEmptyInterval() const = 0;
    
      // Gets aggregated stats (i.e. aggregate of periodically computed metrics).
      // 3. 获取聚合的统计信息(即定期计算的指标的聚合) [min、avg、max]
      AggregatedStats GetStats();
    
      // Reports metrics for elapsed intervals to AggregatedCounter and GetStats.
      // 4. 向AggregatedCounter和GetStats报告已用时间间隔的指标
      AggregatedStats ProcessAndGetStats();
    
      // Reports metrics for elapsed intervals to AggregatedCounter and pauses stats
      // (i.e. empty intervals will be discarded until next sample is added).
      // 5. 向AggregatedCounter报告已用时间间隔的指标,并暂停统计数据
      // (即,在添加下一个样本之前,将丢弃空间隔)。
      void ProcessAndPause();
    
      // As above with a minimum pause time. Added samples within this interval will
      // not resume the stats (i.e. stop the pause).
      // 6. 如上所述,暂停时间最短。在此间隔内添加的样本将
      // 不恢复统计(即停止暂停)。   暂停毫秒数
      void ProcessAndPauseForDuration(int64_t min_pause_time_ms);
    
      // Reports metrics for elapsed intervals to AggregatedCounter and stops pause.
      // 7. 向AggregatedCounter报告已用时间间隔的指标,并停止暂停。
      void ProcessAndStopPause();
    
      // Checks if a sample has been added (i.e. Add or Set called).
      // 8. 检查是否已添加样本(即添加或设置调用
      bool HasSample() const;
    
     protected:
      StatsCounter(Clock* clock,
                   int64_t process_intervals_ms,
                   bool include_empty_intervals,
                   StatsCounterObserver* observer);
    
      void Add(int sample);
      void Set(int64_t sample, uint32_t stream_id);
      void SetLast(int64_t sample, uint32_t stream_id);
    
      const bool include_empty_intervals_;
      const int64_t process_intervals_ms_;
      const std::unique_ptr<AggregatedCounter> aggregated_counter_;
      const std::unique_ptr<Samples> samples_;
    
     private:
      bool TimeToProcess(int* num_elapsed_intervals);
      void TryProcess();
      void ReportMetricToAggregatedCounter(int value, int num_values_to_add) const;
      bool IncludeEmptyIntervals() const;
      void Resume();
      void ResumeIfMinTimePassed();
    
      Clock* const clock_;
      const std::unique_ptr<StatsCounterObserver> observer_;
      int64_t last_process_time_ms_; // 记录数据 - 毫秒数
      bool paused_;
      int64_t pause_time_ms_;
      int64_t min_pause_time_ms_;
    };
    
    // StatsCounter class.
    StatsCounter::StatsCounter(Clock* clock,
                               int64_t process_intervals_ms,
                               bool include_empty_intervals,
                               StatsCounterObserver* observer)
        : include_empty_intervals_(include_empty_intervals),
          process_intervals_ms_(process_intervals_ms),
          aggregated_counter_(new AggregatedCounter()),
          samples_(new Samples()),
          clock_(clock),
          observer_(observer),
          last_process_time_ms_(-1),
          paused_(false),
          pause_time_ms_(-1),
          min_pause_time_ms_(0) {
      RTC_DCHECK_GT(process_intervals_ms_, 0);
    }
    
    StatsCounter::~StatsCounter() {}
    
    AggregatedStats StatsCounter::GetStats() {
      return aggregated_counter_->ComputeStats();
    }
    
    AggregatedStats StatsCounter::ProcessAndGetStats() {
      if (HasSample()) {
        TryProcess();
      }
      return aggregated_counter_->ComputeStats();
    }
    
    void StatsCounter::ProcessAndPauseForDuration(int64_t min_pause_time_ms) {
      ProcessAndPause();
      min_pause_time_ms_ = min_pause_time_ms;
    }
    
    void StatsCounter::ProcessAndPause() {
      if (HasSample()) 
      {
        TryProcess();
      }
      paused_ = true;
      pause_time_ms_ = clock_->TimeInMilliseconds();
    }
    
    void StatsCounter::ProcessAndStopPause() 
    {
      if (HasSample()) 
      {
        TryProcess();
      }
      Resume();
    }
    
    bool StatsCounter::HasSample() const 
    {
      return last_process_time_ms_ != -1;
    }
    
    bool StatsCounter::TimeToProcess(int* elapsed_intervals) 
    {
      int64_t now = clock_->TimeInMilliseconds();
      if (last_process_time_ms_ == -1) 
      {
        last_process_time_ms_ = now;
      }
    
      int64_t diff_ms = now - last_process_time_ms_;
      if (diff_ms < process_intervals_ms_) 
      {
        return false;
      }
    
      // Advance number of complete |process_intervals_ms_| that have passed.
      // 时间间隔中毫秒数 调整差值 [多减去的毫秒数 添加上]
      int64_t num_intervals = diff_ms / process_intervals_ms_;
      last_process_time_ms_ += num_intervals * process_intervals_ms_;
    
      *elapsed_intervals = num_intervals;
      return true;
    }
    
    void StatsCounter::Add(int sample) 
    {
      TryProcess();
      samples_->Add(sample, kStreamId0);
      ResumeIfMinTimePassed();
    }
    
    void StatsCounter::Set(int64_t sample, uint32_t stream_id) 
    {
      if (paused_ && sample == samples_->GetLast(stream_id)) 
      {
        // Do not add same sample while paused (will reset pause).
        return;
      }
      TryProcess();
      samples_->Set(sample, stream_id);
      ResumeIfMinTimePassed();
    }
    
    void StatsCounter::SetLast(int64_t sample, uint32_t stream_id) {
      RTC_DCHECK(!HasSample()) << "Should be set before first sample is added.";
      samples_->SetLast(sample, stream_id);
    }
    
    // Reports periodically computed metric.
    void StatsCounter::ReportMetricToAggregatedCounter(
        int value,
        int num_values_to_add) const 
    {
      for (int i = 0; i < num_values_to_add; ++i) 
      {
        aggregated_counter_->Add(value);
        if (observer_) 
    	{
          observer_->OnMetricUpdated(value);
        }
      }
    }
    
    void StatsCounter::TryProcess() 
    {
      int elapsed_intervals;
      if (!TimeToProcess(&elapsed_intervals)) 
      {
        return;
      }
    
      // Get and report periodically computed metric.
      int metric;
      if (GetMetric(&metric)) {
        ReportMetricToAggregatedCounter(metric, 1);
      }
    
      // Report value for elapsed intervals without samples.
      if (IncludeEmptyIntervals()) {
        // If there are no samples, all elapsed intervals are empty (otherwise one
        // interval contains sample(s), discard this interval).
        int empty_intervals =
            samples_->Empty() ? elapsed_intervals : (elapsed_intervals - 1);
        ReportMetricToAggregatedCounter(GetValueForEmptyInterval(),
                                        empty_intervals);
      }
    
      // Reset samples for elapsed interval.
      samples_->Reset();
    }
    
    bool StatsCounter::IncludeEmptyIntervals() const {
      return include_empty_intervals_ && !paused_ && !aggregated_counter_->Empty();
    }
    void StatsCounter::ResumeIfMinTimePassed() {
      if (paused_ && (clock_->TimeInMilliseconds() - pause_time_ms_) >= min_pause_time_ms_) 
      {
        Resume();
      }
    }
    
    void StatsCounter::Resume() {
      paused_ = false;
      min_pause_time_ms_ = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271

    2、AvgCounter 平均计数器

    
    // AvgCounter: average of samples
    //
    //           | *      *      *      | *           *       | ...
    //           | Add(5) Add(1) Add(6) | Add(5)      Add(5)  |
    // GetMetric | (5 + 1 + 6) / 3      | (5 + 5) / 2         |
    //
    // |include_empty_intervals|: If set, intervals without samples will be included
    //                            in the stats. The value for an interval is
    //                            determined by GetValueForEmptyInterval().
    //
    class AvgCounter : public StatsCounter {
     public:
      AvgCounter(Clock* clock,
                 StatsCounterObserver* observer,
                 bool include_empty_intervals);
      ~AvgCounter() override {}
    
      void Add(int sample);
    
     private:
      bool GetMetric(int* metric) const override;
    
      // Returns the last computed metric (i.e. from GetMetric).
      int GetValueForEmptyInterval() const override;
    
      RTC_DISALLOW_COPY_AND_ASSIGN(AvgCounter);
    };
    
    // StatsCounter sub-classes.
    AvgCounter::AvgCounter(Clock* clock,
                           StatsCounterObserver* observer,
                           bool include_empty_intervals)
        : StatsCounter(clock,
                       kDefaultProcessIntervalMs,
                       include_empty_intervals,
                       observer) {}
    
    void AvgCounter::Add(int sample) {
      StatsCounter::Add(sample);
    }
    
    bool AvgCounter::GetMetric(int* metric) const {
      int64_t count = samples_->Count();
      if (count == 0) {
        return false;
      }
      //  [count / 2] : 次数的平均值
      *metric = (samples_->Sum() + count / 2) / count;
      return true;
    }
    
    int AvgCounter::GetValueForEmptyInterval() const {
      return aggregated_counter_->last_sample();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    3、MaxCounter

    // MaxCounter: maximum of samples
    //
    //           | *      *      *      | *           *       | ...
    //           | Add(5) Add(1) Add(6) | Add(5)      Add(5)  |
    // GetMetric | max: (5, 1, 6)       | max: (5, 5)         |
    //
    class MaxCounter : public StatsCounter {
     public:
      MaxCounter(Clock* clock,
                 StatsCounterObserver* observer,
                 int64_t process_intervals_ms);
      ~MaxCounter() override {}
    
      void Add(int sample);
    
     private:
      bool GetMetric(int* metric) const override;
      int GetValueForEmptyInterval() const override;
    
      RTC_DISALLOW_COPY_AND_ASSIGN(MaxCounter);
    };
    
    
    MaxCounter::MaxCounter(Clock* clock,
                           StatsCounterObserver* observer,
                           int64_t process_intervals_ms)
        : StatsCounter(clock,
                       process_intervals_ms,
                       false,  // |include_empty_intervals|
                       observer) {}
    
    void MaxCounter::Add(int sample) {
      StatsCounter::Add(sample);
    }
    
    bool MaxCounter::GetMetric(int* metric) const {
      if (samples_->Empty())
        return false;
    
      *metric = samples_->Max();
      return true;
    }
    
    int MaxCounter::GetValueForEmptyInterval() const {
      RTC_NOTREACHED();
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4、PercentCounter 百分比计数器

    // PercentCounter: percentage of samples
    //
    //           | *      *      *      | *           *       | ...
    //           | Add(T) Add(F) Add(T) | Add(F)      Add(T)  |
    // GetMetric | 100 * 2 / 3          | 100 * 1 / 2         |
    //  百分比
    class PercentCounter : public StatsCounter {
     public:
      PercentCounter(Clock* clock, StatsCounterObserver* observer);
      ~PercentCounter() override {}
    
      void Add(bool sample);
    
     private:
      bool GetMetric(int* metric) const override;
      int GetValueForEmptyInterval() const override;
    
      RTC_DISALLOW_COPY_AND_ASSIGN(PercentCounter);
    };
    
    PercentCounter::PercentCounter(Clock* clock, StatsCounterObserver* observer)
        : StatsCounter(clock,
                       kDefaultProcessIntervalMs,
                       false,  // |include_empty_intervals|
                       observer) {}
    
    void PercentCounter::Add(bool sample) {
      StatsCounter::Add(sample ? 1 : 0);
    }
    
    bool PercentCounter::GetMetric(int* metric) const {
      int64_t count = samples_->Count();
      if (count == 0)
        return false;
    
      *metric = (samples_->Sum() * 100 + count / 2) / count;
      return true;
    }
    
    int PercentCounter::GetValueForEmptyInterval() const {
      RTC_NOTREACHED();
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    5、PermilleCounter 千分比计数器

    // PermilleCounter: permille of samples
    //
    //           | *      *      *      | *         *         | ...
    //           | Add(T) Add(F) Add(T) | Add(F)    Add(T)    |
    // GetMetric | 1000 *  2 / 3        | 1000 * 1 / 2        |
    //
    class PermilleCounter : public StatsCounter {
     public:
      PermilleCounter(Clock* clock, StatsCounterObserver* observer);
      ~PermilleCounter() override {}
    
      void Add(bool sample);
    
     private:
      bool GetMetric(int* metric) const override;
      int GetValueForEmptyInterval() const override;
    
      RTC_DISALLOW_COPY_AND_ASSIGN(PermilleCounter);
    };
    
    
    PermilleCounter::PermilleCounter(Clock* clock, StatsCounterObserver* observer)
        : StatsCounter(clock,
                       kDefaultProcessIntervalMs,
                       false,  // |include_empty_intervals|
                       observer) {}
    
    void PermilleCounter::Add(bool sample) {
      StatsCounter::Add(sample ? 1 : 0);
    }
    
    bool PermilleCounter::GetMetric(int* metric) const {
      int64_t count = samples_->Count();
      if (count == 0)
        return false;
    
      *metric = (samples_->Sum() * 1000 + count / 2) / count;
      return true;
    }
    
    int PermilleCounter::GetValueForEmptyInterval() const {
      RTC_NOTREACHED();
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    6、RateCounter 速率计数器

    // RateCounter: units per second
    //
    //           | *      *      *      | *           *       | ...
    //           | Add(5) Add(1) Add(6) | Add(5)      Add(5)  |
    //           |<------ 2 sec ------->|                     |
    // GetMetric | (5 + 1 + 6) / 2      | (5 + 5) / 2         |
    //
    // |include_empty_intervals|: If set, intervals without samples will be included
    //                            in the stats. The value for an interval is
    //                            determined by GetValueForEmptyInterval().
    //include_empty_intervals: 如果设置,将包括没有样本的间隔
    //在统计中。间隔的值为
    //由GetValueForEmptyInterval()确定。
    //
    class RateCounter : public StatsCounter {
     public:
      RateCounter(Clock* clock,
                  StatsCounterObserver* observer,
                  bool include_empty_intervals);
      ~RateCounter() override {}
    
      void Add(int sample);
    
     private:
      bool GetMetric(int* metric) const override;
      int GetValueForEmptyInterval() const override;  // Returns zero.
    
      RTC_DISALLOW_COPY_AND_ASSIGN(RateCounter);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    7、RateAccCounter 速率Acc计数器

    
    // RateAccCounter: units per second (used for counters)
    //
    //           | *      *      *      | *         *         | ...
    //           | Set(5) Set(6) Set(8) | Set(11)   Set(13)   |
    //           |<------ 2 sec ------->|                     |
    // GetMetric | (8 - 0) / 2          | (13 - 8) / 2        |
    //
    // |include_empty_intervals|: If set, intervals without samples will be included
    //                            in the stats. The value for an interval is
    //                            determined by GetValueForEmptyInterval().
    //
    class RateAccCounter : public StatsCounter {
     public:
      RateAccCounter(Clock* clock,
                     StatsCounterObserver* observer,
                     bool include_empty_intervals);
      ~RateAccCounter() override {}
    
      void Set(int64_t sample, uint32_t stream_id);
    
      // Sets the value for previous interval.
      // To be used if a value other than zero is initially required.
      void SetLast(int64_t sample, uint32_t stream_id);
    
     private:
      bool GetMetric(int* metric) const override;
      int GetValueForEmptyInterval() const override;  // Returns zero.
    
      RTC_DISALLOW_COPY_AND_ASSIGN(RateAccCounter);
    };
    RateCounter::RateCounter(Clock* clock,
                             StatsCounterObserver* observer,
                             bool include_empty_intervals)
        : StatsCounter(clock,
                       kDefaultProcessIntervalMs /*2000*/,
                       include_empty_intervals,
                       observer) {}
    
    void RateCounter::Add(int sample) {
      StatsCounter::Add(sample);
    }
    
    bool RateCounter::GetMetric(int* metric) const {
      if (samples_->Empty())
        return false;
    
      *metric = (samples_->Sum() * 1000 + process_intervals_ms_ / 2) /
                process_intervals_ms_;
      return true;
    }
    
    int RateCounter::GetValueForEmptyInterval() const {
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    总结:

    WebRTC源码分析地址:https://github.com/chensongpoixs/cwebrtc

  • 相关阅读:
    查找算法-二分查找法(Binary Search)
    复习Day01:数组part01:701. 二分查找、35. 搜索插入位置、367. 有效的完全平方数、69. x的平方根、74. 搜索二维矩阵
    ImageJ软件使用教程(三):目标计数
    Unity游戏开发基础之数据结构部分
    【光流估计】——gmflow中self attention,cross attention的比较
    TK爆品剖析 水晶首饰降临节日历持续火爆TikTok,独立站卖到断货
    景联文科技:一文读懂火爆全网的AIGC和背后的数据标注技术!
    Adobe 推出 Photoshop Elements 2024 新版
    golang同步原语——sync.Mutex
    五金机电行业智能渠道商管理平台搭建,构建数字化渠道管理新模式
  • 原文地址:https://blog.csdn.net/Poisx/article/details/126005484