910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_
#define MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_

#include <algorithm>
#include <memory>

#include "base/time/time.h"
#include "media/gpu/media_gpu_export.h"

namespace media {

// An Exponential Moving Average filter.
// It is an implementation of exponential moving average filter with a time
// constant. The effective window size equals to the time elapsed since the
// first sample was added, until the maximum window size is reached. This makes
// a difference to the standard exponential moving average filter
// implementation. Alpha, the time constant, is calculated as a ratio between
// the time period passed from the last added sample and the effective window
// size.
//     mean += alpha * (value - mean)
//     mean_square += alpha * (value^2 - mean_square)
//     std_dev = sqrt(mean_square - mean^2)
//     alpha = elapsed_time / curr_window_size
class MEDIA_GPU_EXPORT ExponentialMovingAverage {
 public:
  explicit ExponentialMovingAverage(base::TimeDelta max_window_size);
  ~ExponentialMovingAverage();

  ExponentialMovingAverage(const ExponentialMovingAverage& other) = delete;
  ExponentialMovingAverage& operator=(const ExponentialMovingAverage& other) =
      delete;

  base::TimeDelta curr_window_size() const { return curr_window_size_; }
  base::TimeDelta max_window_size() const { return max_window_size_; }

  float mean() const { return mean_; }

  void update_max_window_size(base::TimeDelta max_window_size) {
    max_window_size_ = max_window_size;
  }

  // Adds a new value to the filter. The T type is casted to the float value.
  // Elapsed time is the period between the current and previous sample.
  template <typename T>
  void AddValue(T value, base::TimeDelta elapsed_time) {
    float float_value = static_cast<float>(value);
    // The minimum window size is 1ms. This is to avoid division by zero.
    curr_window_size_ = std::clamp(curr_window_size_ + elapsed_time,
                                   base::Milliseconds(1), max_window_size_);
    float alpha = static_cast<float>(std::min(
        elapsed_time.InMillisecondsF() / curr_window_size_.InMillisecondsF(),
        1.0));
    mean_ += alpha * (float_value - mean_);
    mean_square_ += alpha * (float_value * float_value - mean_square_);
  }

  float GetStdDeviation() const;

 private:
  // Mean of values.
  float mean_ = 0.0f;
  // Mean of squared values.
  float mean_square_ = 0.0f;

  // Effective window size.
  base::TimeDelta curr_window_size_;
  // Max window size.
  base::TimeDelta max_window_size_;
};

}  // namespace media

#endif  // MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_