|  | /* | 
|  | *  Copyright 2021 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 "common_video/framerate_controller.h" | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <cstdlib> | 
|  | #include <limits> | 
|  | #include <optional> | 
|  |  | 
|  | #include "rtc_base/time_utils.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  | constexpr double kMinFramerate = 0.5; | 
|  | }  // namespace | 
|  |  | 
|  | FramerateController::FramerateController() | 
|  | : FramerateController(std::numeric_limits<double>::max()) {} | 
|  |  | 
|  | FramerateController::FramerateController(double max_framerate) | 
|  | : max_framerate_(max_framerate) {} | 
|  |  | 
|  | FramerateController::~FramerateController() {} | 
|  |  | 
|  | void FramerateController::SetMaxFramerate(double max_framerate) { | 
|  | max_framerate_ = max_framerate; | 
|  | } | 
|  |  | 
|  | double FramerateController::GetMaxFramerate() const { | 
|  | return max_framerate_; | 
|  | } | 
|  |  | 
|  | bool FramerateController::ShouldDropFrame(int64_t in_timestamp_ns) { | 
|  | if (max_framerate_ < kMinFramerate) | 
|  | return true; | 
|  |  | 
|  | // If `max_framerate_` is not set (i.e. maxdouble), `frame_interval_ns` is | 
|  | // rounded to 0. | 
|  | int64_t frame_interval_ns = kNumNanosecsPerSec / max_framerate_; | 
|  | if (frame_interval_ns <= 0) { | 
|  | // Frame rate throttling not enabled. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (next_frame_timestamp_ns_) { | 
|  | // Time until next frame should be outputted. | 
|  | const int64_t time_until_next_frame_ns = | 
|  | (*next_frame_timestamp_ns_ - in_timestamp_ns); | 
|  | // Continue if timestamp is within expected range. | 
|  | if (std::abs(time_until_next_frame_ns) < 2 * frame_interval_ns) { | 
|  | // Drop if a frame shouldn't be outputted yet. | 
|  | if (time_until_next_frame_ns > 0) | 
|  | return true; | 
|  | // Time to output new frame. | 
|  | *next_frame_timestamp_ns_ += frame_interval_ns; | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // First timestamp received or timestamp is way outside expected range, so | 
|  | // reset. Set first timestamp target to just half the interval to prefer | 
|  | // keeping frames in case of jitter. | 
|  | next_frame_timestamp_ns_ = in_timestamp_ns + frame_interval_ns / 2; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void FramerateController::Reset() { | 
|  | max_framerate_ = std::numeric_limits<double>::max(); | 
|  | next_frame_timestamp_ns_ = std::nullopt; | 
|  | } | 
|  |  | 
|  | void FramerateController::KeepFrame(int64_t in_timestamp_ns) { | 
|  | if (ShouldDropFrame(in_timestamp_ns)) { | 
|  | if (max_framerate_ < kMinFramerate) | 
|  | return; | 
|  |  | 
|  | int64_t frame_interval_ns = kNumNanosecsPerSec / max_framerate_; | 
|  | if (next_frame_timestamp_ns_) | 
|  | *next_frame_timestamp_ns_ += frame_interval_ns; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |