diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 0e4805d94c..ff1e202ad9 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -425,6 +425,7 @@ rtc_static_library("webrtc_vp8") { "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_numerics", + "../../rtc_base/experiments:cpu_speed_experiment", "../../system_wrappers", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index b199f65748..e4be823cef 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -142,6 +142,7 @@ LibvpxVp8Encoder::LibvpxVp8Encoder() LibvpxVp8Encoder::LibvpxVp8Encoder(std::unique_ptr interface) : libvpx_(std::move(interface)), + experimental_cpu_speed_config_arm_(CpuSpeedExperiment::GetConfigs()), encoded_complete_callback_(nullptr), inited_(false), timestamp_(0), @@ -432,10 +433,10 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, } cpu_speed_default_ = cpu_speed_[0]; // Set encoding complexity (cpu_speed) based on resolution and/or platform. - cpu_speed_[0] = SetCpuSpeed(inst->width, inst->height); + cpu_speed_[0] = GetCpuSpeed(inst->width, inst->height); for (int i = 1; i < number_of_streams; ++i) { cpu_speed_[i] = - SetCpuSpeed(inst->simulcastStream[number_of_streams - 1 - i].width, + GetCpuSpeed(inst->simulcastStream[number_of_streams - 1 - i].width, inst->simulcastStream[number_of_streams - 1 - i].height); } configurations_[0].g_w = inst->width; @@ -507,7 +508,7 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, return InitAndSetControlSettings(); } -int LibvpxVp8Encoder::SetCpuSpeed(int width, int height) { +int LibvpxVp8Encoder::GetCpuSpeed(int width, int height) { #if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64) || \ defined(WEBRTC_ANDROID) // On mobile platform, use a lower speed setting for lower resolutions for @@ -516,6 +517,11 @@ int LibvpxVp8Encoder::SetCpuSpeed(int width, int height) { if (number_of_cores_ <= 3) return -12; + if (experimental_cpu_speed_config_arm_) { + return CpuSpeedExperiment::GetValue(width * height, + *experimental_cpu_speed_config_arm_); + } + if (width * height <= 352 * 288) return -8; else if (width * height <= 640 * 480) diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h index 7fffbab767..362a07979d 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h @@ -22,6 +22,7 @@ #include "modules/video_coding/codecs/vp8/include/vp8.h" #include "modules/video_coding/codecs/vp8/libvpx_interface.h" #include "modules/video_coding/include/video_codec_interface.h" +#include "rtc_base/experiments/cpu_speed_experiment.h" #include "vpx/vp8cx.h" #include "vpx/vpx_encoder.h" @@ -61,8 +62,8 @@ class LibvpxVp8Encoder : public VideoEncoder { private: void SetupTemporalLayers(const VideoCodec& codec); - // Set the cpu_speed setting for encoder based on resolution and/or platform. - int SetCpuSpeed(int width, int height); + // Get the cpu_speed setting for encoder based on resolution and/or platform. + int GetCpuSpeed(int width, int height); // Determine number of encoder threads to use. int NumberOfThreads(int width, int height, int number_of_cores); @@ -87,6 +88,9 @@ class LibvpxVp8Encoder : public VideoEncoder { const std::unique_ptr libvpx_; + const absl::optional> + experimental_cpu_speed_config_arm_; + EncodedImageCallback* encoded_complete_callback_; VideoCodec codec_; bool inited_; diff --git a/rtc_base/experiments/BUILD.gn b/rtc_base/experiments/BUILD.gn index 924b490eb6..b2e1302edc 100644 --- a/rtc_base/experiments/BUILD.gn +++ b/rtc_base/experiments/BUILD.gn @@ -75,6 +75,18 @@ rtc_static_library("normalize_simulcast_size_experiment") { ] } +rtc_static_library("cpu_speed_experiment") { + sources = [ + "cpu_speed_experiment.cc", + "cpu_speed_experiment.h", + ] + deps = [ + "../:rtc_base_approved", + "../../system_wrappers:field_trial", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + rtc_static_library("rtt_mult_experiment") { sources = [ "rtt_mult_experiment.cc", @@ -104,6 +116,7 @@ if (rtc_include_tests) { sources = [ "congestion_controller_experiment_unittest.cc", + "cpu_speed_experiment_unittest.cc", "field_trial_parser_unittest.cc", "field_trial_units_unittest.cc", "normalize_simulcast_size_experiment_unittest.cc", @@ -112,6 +125,7 @@ if (rtc_include_tests) { ] deps = [ ":congestion_controller_experiment", + ":cpu_speed_experiment", ":field_trial_parser", ":normalize_simulcast_size_experiment", ":quality_scaling_experiment", @@ -120,6 +134,7 @@ if (rtc_include_tests) { "../:rtc_base_tests_utils", "../../system_wrappers:field_trial", "../../test:field_trial", + "../../test:test_support", ] } } diff --git a/rtc_base/experiments/cpu_speed_experiment.cc b/rtc_base/experiments/cpu_speed_experiment.cc new file mode 100644 index 0000000000..f39540cf03 --- /dev/null +++ b/rtc_base/experiments/cpu_speed_experiment.cc @@ -0,0 +1,70 @@ +/* + * Copyright 2018 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 "rtc_base/experiments/cpu_speed_experiment.h" + +#include + +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { +constexpr char kFieldTrial[] = "WebRTC-VP8-CpuSpeed-Arm"; +constexpr int kMinSetting = -16; +constexpr int kMaxSetting = -1; +} // namespace + +absl::optional> +CpuSpeedExperiment::GetConfigs() { + if (!webrtc::field_trial::IsEnabled(kFieldTrial)) + return absl::nullopt; + + const std::string group = webrtc::field_trial::FindFullName(kFieldTrial); + if (group.empty()) + return absl::nullopt; + + std::vector configs(3); + if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d,%d,%d", &(configs[0].pixels), + &(configs[0].cpu_speed), &(configs[1].pixels), + &(configs[1].cpu_speed), &(configs[2].pixels), + &(configs[2].cpu_speed)) != 6) { + RTC_LOG(LS_WARNING) << "Too few parameters provided."; + return absl::nullopt; + } + + for (const auto& config : configs) { + if (config.cpu_speed < kMinSetting || config.cpu_speed > kMaxSetting) { + RTC_LOG(LS_WARNING) << "Unsupported cpu speed setting, value ignored."; + return absl::nullopt; + } + } + + for (size_t i = 1; i < configs.size(); ++i) { + if (configs[i].pixels < configs[i - 1].pixels || + configs[i].cpu_speed > configs[i - 1].cpu_speed) { + RTC_LOG(LS_WARNING) << "Invalid parameter value provided."; + return absl::nullopt; + } + } + + return absl::optional>(configs); +} + +int CpuSpeedExperiment::GetValue(int pixels, + const std::vector& configs) { + for (const auto& config : configs) { + if (pixels <= config.pixels) + return config.cpu_speed; + } + return kMinSetting; +} + +} // namespace webrtc diff --git a/rtc_base/experiments/cpu_speed_experiment.h b/rtc_base/experiments/cpu_speed_experiment.h new file mode 100644 index 0000000000..e6c8340943 --- /dev/null +++ b/rtc_base/experiments/cpu_speed_experiment.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 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. + */ + +#ifndef RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ +#define RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ + +#include + +#include "absl/types/optional.h" + +namespace webrtc { + +class CpuSpeedExperiment { + public: + struct Config { + bool operator==(const Config& o) const { + return pixels == o.pixels && cpu_speed == o.cpu_speed; + } + + int pixels; // The video frame size. + int cpu_speed; // The |cpu_speed| to be used if the frame size is less + // than or equal to |pixels|. + }; + + // Returns the configurations from field trial on success. + static absl::optional> GetConfigs(); + + // Gets the cpu speed from the |configs| based on |pixels|. + static int GetValue(int pixels, const std::vector& configs); +}; + +} // namespace webrtc + +#endif // RTC_BASE_EXPERIMENTS_CPU_SPEED_EXPERIMENT_H_ diff --git a/rtc_base/experiments/cpu_speed_experiment_unittest.cc b/rtc_base/experiments/cpu_speed_experiment_unittest.cc new file mode 100644 index 0000000000..edc782c0ad --- /dev/null +++ b/rtc_base/experiments/cpu_speed_experiment_unittest.cc @@ -0,0 +1,85 @@ +/* + * Copyright 2018 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 "rtc_base/experiments/cpu_speed_experiment.h" + +#include "rtc_base/gunit.h" +#include "test/field_trial.h" +#include "test/gmock.h" + +namespace webrtc { + +TEST(CpuSpeedExperimentTest, GetConfigsFailsIfNotEnabled) { + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +TEST(CpuSpeedExperimentTest, GetConfigsFailsForTooFewParameters) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-1,2000,-10,3000/"); + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +TEST(CpuSpeedExperimentTest, GetConfigs) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-1,2000,-10,3000,-16/"); + + const absl::optional> kConfigs = + CpuSpeedExperiment::GetConfigs(); + ASSERT_TRUE(kConfigs); + EXPECT_THAT(*kConfigs, + ::testing::ElementsAre(CpuSpeedExperiment::Config{1000, -1}, + CpuSpeedExperiment::Config{2000, -10}, + CpuSpeedExperiment::Config{3000, -16})); +} + +TEST(CpuSpeedExperimentTest, GetValue) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-5,2000,-10,3000,-12/"); + + const absl::optional> kConfigs = + CpuSpeedExperiment::GetConfigs(); + ASSERT_TRUE(kConfigs); + ASSERT_EQ(3u, (*kConfigs).size()); + EXPECT_EQ(-5, CpuSpeedExperiment::GetValue(1, *kConfigs)); + EXPECT_EQ(-5, CpuSpeedExperiment::GetValue(1000, *kConfigs)); + EXPECT_EQ(-10, CpuSpeedExperiment::GetValue(1000 + 1, *kConfigs)); + EXPECT_EQ(-10, CpuSpeedExperiment::GetValue(2000, *kConfigs)); + EXPECT_EQ(-12, CpuSpeedExperiment::GetValue(2000 + 1, *kConfigs)); + EXPECT_EQ(-12, CpuSpeedExperiment::GetValue(3000, *kConfigs)); + EXPECT_EQ(-16, CpuSpeedExperiment::GetValue(3000 + 1, *kConfigs)); +} + +TEST(CpuSpeedExperimentTest, GetConfigsFailsForTooSmallValue) { + // Supported range: [-16, -1]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-1,2000,-10,3000,-17/"); + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +TEST(CpuSpeedExperimentTest, GetConfigsFailsForTooLargeValue) { + // Supported range: [-16, -1]. + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,0,2000,-10,3000,-16/"); + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +TEST(CpuSpeedExperimentTest, GetConfigsFailsIfPixelsDecreasing) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-5,999,-10,3000,-16/"); + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +TEST(CpuSpeedExperimentTest, GetConfigsFailsIfCpuSpeedIncreasing) { + webrtc::test::ScopedFieldTrials field_trials( + "WebRTC-VP8-CpuSpeed-Arm/Enabled-1000,-5,2000,-4,3000,-16/"); + EXPECT_FALSE(CpuSpeedExperiment::GetConfigs()); +} + +} // namespace webrtc