| // 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. |
| |
| |
| #include "media/gpu/frame_size_estimator.h" |
| |
| #include <array> |
| |
| #include "media/gpu/h264_rate_control_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media { |
| namespace { |
| constexpr int kCommonFps = 30; |
| constexpr uint32_t kCommonAvgBitrate = 1000000; // bits per second |
| |
| // Test FrameSizeEstimatorTest updates the estimator running the test frame |
| // sequence and checks whether the expected output from the component is |
| // generated. |
| class FrameSizeEstimatorTest : public testing::Test { |
| public: |
| FrameSizeEstimatorTest() = default; |
| |
| void SetUp() override { |
| float bytes_per_frame_avg = kCommonAvgBitrate / 8 / kCommonFps; |
| float qp_size_init = |
| h264_rate_control_util::QP2QStepSize(24) * bytes_per_frame_avg; |
| float size_correction_init = 0.3f * bytes_per_frame_avg; |
| |
| frame_size_estimator_ = std::make_unique<FrameSizeEstimator>( |
| base::Milliseconds(300), qp_size_init, size_correction_init); |
| EXPECT_EQ(41660.0f, frame_size_estimator_->qp_size_mean()); |
| EXPECT_EQ(1249.800049f, frame_size_estimator_->size_correction_mean()); |
| } |
| |
| protected: |
| // Runs a loop of P encoded frames in the sequence. |
| // Returns the index of the last frame. QP is circularly taken from the |
| // set { 22, 24, 26, 28, 26, 24 }. |
| int RunTestSequence(uint32_t avg_bitrate, |
| int fps, |
| int frame_count, |
| int start_frame_index) { |
| constexpr auto kQpValues = |
| std::to_array<uint32_t>({22, 24, 26, 28, 26, 24}); |
| size_t common_frame_size = avg_bitrate / 8 / fps; |
| |
| base::TimeDelta timestamp = base::Microseconds( |
| start_frame_index * base::Time::kMicrosecondsPerSecond / fps); |
| for (int i = 0; i < frame_count; ++i) { |
| uint32_t qp = |
| kQpValues[(i + 1) % ((kQpValues.size() * |
| sizeof(decltype(kQpValues)::value_type)) / |
| sizeof(uint32_t))]; |
| uint32_t qp_prev = |
| kQpValues[i % ((kQpValues.size() * |
| sizeof(decltype(kQpValues)::value_type)) / |
| sizeof(uint32_t))]; |
| size_t encoded_size = 0.625 * 16 * common_frame_size / |
| h264_rate_control_util::QP2QStepSize(qp); |
| |
| frame_size_estimator_->Update(encoded_size, qp, qp_prev, timestamp); |
| |
| timestamp += base::Microseconds(base::Time::kMicrosecondsPerSecond / fps); |
| } |
| |
| return start_frame_index + frame_count; |
| } |
| |
| std::unique_ptr<FrameSizeEstimator> frame_size_estimator_; |
| }; |
| |
| // Test Cases |
| |
| // The test runs a predefined sequence of frame sizes two times and checks |
| // the stats after running each sequence. Different window size is used in |
| // each run. |
| TEST_F(FrameSizeEstimatorTest, RunBasicFrameSizeEstimatorTest) { |
| constexpr float kExpectedQpSizeMeanMin1 = 33060.32f; |
| constexpr float kExpectedQpSizeMeanMax1 = 33060.34f; |
| constexpr float kExpectedSizeCorrectionMeanMin1 = -0.01f; |
| constexpr float kExpectedSizeCorrectionMeanMax1 = 0.01f; |
| constexpr float kExpectedQpSizeMeanMin2 = 52165.11f; |
| constexpr float kExpectedQpSizeMeanMax2 = 52165.13f; |
| constexpr float kExpectedSizeCorrectionMeanMin2 = 38.68f; |
| constexpr float kExpectedSizeCorrectionMeanMax2 = 38.70f; |
| |
| int start_frame_index = 0; |
| int last_frame_index = |
| RunTestSequence(kCommonAvgBitrate, kCommonFps, 30, start_frame_index); |
| |
| EXPECT_LT(kExpectedQpSizeMeanMin1, frame_size_estimator_->qp_size_mean()); |
| EXPECT_GT(kExpectedQpSizeMeanMax1, frame_size_estimator_->qp_size_mean()); |
| EXPECT_LT(kExpectedSizeCorrectionMeanMin1, |
| frame_size_estimator_->size_correction_mean()); |
| EXPECT_GT(kExpectedSizeCorrectionMeanMax1, |
| frame_size_estimator_->size_correction_mean()); |
| |
| start_frame_index = last_frame_index; |
| frame_size_estimator_->UpdateMaxWindowSize(base::Milliseconds(3000)); |
| RunTestSequence(kCommonAvgBitrate, kCommonFps, 50, start_frame_index); |
| |
| EXPECT_LT(kExpectedQpSizeMeanMin2, frame_size_estimator_->qp_size_mean()); |
| EXPECT_GT(kExpectedQpSizeMeanMax2, frame_size_estimator_->qp_size_mean()); |
| EXPECT_LT(kExpectedSizeCorrectionMeanMin2, |
| frame_size_estimator_->size_correction_mean()); |
| EXPECT_GT(kExpectedSizeCorrectionMeanMax2, |
| frame_size_estimator_->size_correction_mean()); |
| } |
| |
| // The test updates the buffer with predefined sample sequence and checks the |
| // estimated frame size values. |
| TEST_F(FrameSizeEstimatorTest, CheckEstimatorStates) { |
| constexpr auto kEstimatedFrameSizeValues = std::to_array<size_t>({ |
| 4556, |
| 3874, |
| 2663, |
| 5259, |
| 4916, |
| 5540, |
| 2352, |
| 3095, |
| 2655, |
| 5250, |
| }); |
| constexpr auto kQpValues = std::to_array<uint32_t>({22, 24, 26, 28, 26, 24}); |
| |
| size_t common_frame_size = kCommonAvgBitrate / 8 / kCommonFps; |
| base::TimeDelta timestamp = base::Microseconds(0); |
| for (int i = 0; i < 10; ++i) { |
| uint32_t qp = |
| kQpValues[(i + 1) % ((kQpValues.size() * |
| sizeof(decltype(kQpValues)::value_type)) / |
| sizeof(uint32_t))]; |
| uint32_t qp_prev = |
| kQpValues[i % ((kQpValues.size() * |
| sizeof(decltype(kQpValues)::value_type)) / |
| sizeof(uint32_t))]; |
| size_t encoded_size = 0.625 * 16 * common_frame_size / |
| h264_rate_control_util::QP2QStepSize(qp); |
| |
| size_t estimated_size = frame_size_estimator_->Estimate(qp, qp_prev); |
| |
| frame_size_estimator_->Update(encoded_size, qp, qp_prev, timestamp); |
| |
| EXPECT_EQ(kEstimatedFrameSizeValues[i], estimated_size); |
| |
| timestamp += |
| base::Microseconds(base::Time::kMicrosecondsPerSecond / kCommonFps); |
| } |
| } |
| |
| } // namespace |
| |
| } // namespace media |