/* * 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 #include "rtc_base/time_utils.h" #include "test/gtest.h" namespace webrtc { namespace { constexpr int kInputFps = 30; constexpr int kNumFrames = 60; } // namespace class FramerateControllerTest : public ::testing::Test { protected: int64_t GetNextTimestampNs() { int64_t interval_us = rtc::kNumMicrosecsPerSec / kInputFps; next_timestamp_us_ += interval_us; return next_timestamp_us_ * rtc::kNumNanosecsPerMicrosec; } int64_t next_timestamp_us_ = rtc::TimeMicros(); FramerateController controller_; }; TEST_F(FramerateControllerTest, NoFramesDroppedIfNothingRequested) { // Default max framerate is maxdouble. for (int i = 1; i < kNumFrames; ++i) EXPECT_FALSE(controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, AllFramesDroppedIfZeroRequested) { controller_.SetMaxFramerate(0); for (int i = 1; i < kNumFrames; ++i) EXPECT_TRUE(controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, AllFramesDroppedIfNegativeRequested) { controller_.SetMaxFramerate(-1); for (int i = 1; i < kNumFrames; ++i) EXPECT_TRUE(controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, EverySecondFrameDroppedIfHalfRequested) { controller_.SetMaxFramerate(kInputFps / 2); // The first frame should not be dropped. for (int i = 1; i < kNumFrames; ++i) EXPECT_EQ(i % 2 == 0, controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, EveryThirdFrameDroppedIfTwoThirdsRequested) { controller_.SetMaxFramerate(kInputFps * 2 / 3); // The first frame should not be dropped. for (int i = 1; i < kNumFrames; ++i) EXPECT_EQ(i % 3 == 0, controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, NoFrameDroppedIfTwiceRequested) { controller_.SetMaxFramerate(kInputFps * 2); for (int i = 1; i < kNumFrames; ++i) EXPECT_FALSE(controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, TestAverageFramerate) { const double kMaxFps = 18.2; controller_.SetMaxFramerate(kMaxFps); const int kNumSec = 10; int frames_kept = 0; for (int i = 0; i < kInputFps * kNumSec; ++i) { if (!controller_.ShouldDropFrame(GetNextTimestampNs())) ++frames_kept; } double average_fps = static_cast(frames_kept) / kNumSec; EXPECT_NEAR(kMaxFps, average_fps, 0.01); } TEST_F(FramerateControllerTest, NoFrameDroppedForLargeTimestampOffset) { controller_.SetMaxFramerate(kInputFps); EXPECT_FALSE(controller_.ShouldDropFrame(0)); const int64_t kLargeOffsetNs = -987654321LL * 1000; EXPECT_FALSE(controller_.ShouldDropFrame(kLargeOffsetNs)); int64_t input_interval_ns = rtc::kNumNanosecsPerSec / kInputFps; EXPECT_FALSE(controller_.ShouldDropFrame(kLargeOffsetNs + input_interval_ns)); } TEST_F(FramerateControllerTest, NoFrameDroppedIfInputWithJitterRequested) { controller_.SetMaxFramerate(kInputFps); // Input fps with jitter. int64_t input_interval_ns = rtc::kNumNanosecsPerSec / kInputFps; EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 0 / 10)); EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 10 / 10 - 1)); EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 25 / 10)); EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 30 / 10)); EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 35 / 10)); EXPECT_FALSE(controller_.ShouldDropFrame(input_interval_ns * 50 / 10)); } TEST_F(FramerateControllerTest, FrameDroppedWhenReductionRequested) { controller_.SetMaxFramerate(kInputFps); // Expect no frame drop. for (int i = 1; i < kNumFrames; ++i) EXPECT_FALSE(controller_.ShouldDropFrame(GetNextTimestampNs())); // Reduce max frame rate. controller_.SetMaxFramerate(kInputFps / 2); // Verify that every other frame is dropped. for (int i = 1; i < kNumFrames; ++i) EXPECT_EQ(i % 2 == 0, controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, NoFramesDroppedAfterReset) { controller_.SetMaxFramerate(0); // All frames dropped. for (int i = 1; i < kNumFrames; ++i) EXPECT_TRUE(controller_.ShouldDropFrame(GetNextTimestampNs())); controller_.Reset(); // Expect no frame drop after reset. for (int i = 1; i < kNumFrames; ++i) EXPECT_FALSE(controller_.ShouldDropFrame(GetNextTimestampNs())); } TEST_F(FramerateControllerTest, TestKeepFrame) { FramerateController controller(kInputFps / 2); EXPECT_FALSE(controller.ShouldDropFrame(GetNextTimestampNs())); EXPECT_TRUE(controller.ShouldDropFrame(GetNextTimestampNs())); EXPECT_FALSE(controller.ShouldDropFrame(GetNextTimestampNs())); EXPECT_TRUE(controller.ShouldDropFrame(GetNextTimestampNs())); EXPECT_FALSE(controller.ShouldDropFrame(GetNextTimestampNs())); // Next frame should be dropped. // Keep this frame (e.g. in case of a key frame). controller.KeepFrame(GetNextTimestampNs()); // Expect next frame to be dropped instead. EXPECT_TRUE(controller.ShouldDropFrame(GetNextTimestampNs())); } } // namespace webrtc