/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/video_coding/media_optimization.h"

#include <string.h>
#include <algorithm>
#include <limits>

#include "modules/video_coding/utility/frame_dropper.h"
#include "system_wrappers/include/clock.h"

namespace webrtc {
namespace media_optimization {
namespace {
const int64_t kFrameHistoryWinMs = 2000;
}  // namespace

MediaOptimization::MediaOptimization(Clock* clock)
    : clock_(clock),
      max_bit_rate_(0),
      max_frame_rate_(0),
      frame_dropper_(),
      incoming_frame_rate_(0) {
  memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
  frame_dropper_.SetRates(0, 0);
}

MediaOptimization::~MediaOptimization() = default;

void MediaOptimization::SetEncodingData(int32_t max_bit_rate,
                                        uint32_t target_bitrate,
                                        uint32_t max_frame_rate) {
  rtc::CritScope lock(&crit_sect_);
  // Everything codec specific should be reset here since the codec has changed.
  max_bit_rate_ = max_bit_rate;
  max_frame_rate_ = static_cast<float>(max_frame_rate);
  float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f;
  frame_dropper_.Reset();
  frame_dropper_.SetRates(target_bitrate_kbps, max_frame_rate_);
}

uint32_t MediaOptimization::SetTargetRates(uint32_t target_bitrate) {
  rtc::CritScope lock(&crit_sect_);

  // Cap target video bitrate to codec maximum.
  int video_target_bitrate = target_bitrate;
  if (max_bit_rate_ > 0 && video_target_bitrate > max_bit_rate_) {
    video_target_bitrate = max_bit_rate_;
  }
  float target_video_bitrate_kbps =
      static_cast<float>(video_target_bitrate) / 1000.0f;

  float framerate = incoming_frame_rate_;
  if (framerate == 0.0) {
    // No framerate estimate available, use configured max framerate instead.
    framerate = max_frame_rate_;
  }

  frame_dropper_.SetRates(target_video_bitrate_kbps, framerate);

  return video_target_bitrate;
}

uint32_t MediaOptimization::InputFrameRate() {
  rtc::CritScope lock(&crit_sect_);
  return InputFrameRateInternal();
}

uint32_t MediaOptimization::InputFrameRateInternal() {
  ProcessIncomingFrameRate(clock_->TimeInMilliseconds());
  uint32_t framerate = static_cast<uint32_t>(std::min<float>(
      std::numeric_limits<uint32_t>::max(), incoming_frame_rate_ + 0.5f));
  return framerate;
}

void MediaOptimization::UpdateWithEncodedData(
    const size_t encoded_image_length,
    const FrameType encoded_image_frametype) {
  size_t encoded_length = encoded_image_length;
  rtc::CritScope lock(&crit_sect_);
  if (encoded_length > 0) {
    const bool delta_frame = encoded_image_frametype != kVideoFrameKey;
    frame_dropper_.Fill(encoded_length, delta_frame);
  }
}

void MediaOptimization::EnableFrameDropper(bool enable) {
  rtc::CritScope lock(&crit_sect_);
  frame_dropper_.Enable(enable);
}

bool MediaOptimization::DropFrame() {
  rtc::CritScope lock(&crit_sect_);
  UpdateIncomingFrameRate();
  // Leak appropriate number of bytes.
  frame_dropper_.Leak(static_cast<uint32_t>(InputFrameRateInternal() + 0.5f));
  return frame_dropper_.DropFrame();
}

void MediaOptimization::UpdateIncomingFrameRate() {
  int64_t now = clock_->TimeInMilliseconds();
  if (incoming_frame_times_[0] == 0) {
    // No shifting if this is the first time.
  } else {
    // Shift all times one step.
    for (int32_t i = (kFrameCountHistorySize - 2); i >= 0; i--) {
      incoming_frame_times_[i + 1] = incoming_frame_times_[i];
    }
  }
  incoming_frame_times_[0] = now;
  ProcessIncomingFrameRate(now);
}

// Allowing VCM to keep track of incoming frame rate.
void MediaOptimization::ProcessIncomingFrameRate(int64_t now) {
  int32_t num = 0;
  int32_t nr_of_frames = 0;
  for (num = 1; num < (kFrameCountHistorySize - 1); ++num) {
    if (incoming_frame_times_[num] <= 0 ||
        // Don't use data older than 2 s.
        now - incoming_frame_times_[num] > kFrameHistoryWinMs) {
      break;
    } else {
      nr_of_frames++;
    }
  }
  if (num > 1) {
    const int64_t diff =
        incoming_frame_times_[0] - incoming_frame_times_[num - 1];
    incoming_frame_rate_ = 0.0;  // No frame rate estimate available.
    if (diff > 0) {
      incoming_frame_rate_ = nr_of_frames * 1000.0f / static_cast<float>(diff);
    }
  }
}
}  // namespace media_optimization
}  // namespace webrtc
