videocodec_test_mediacodec.cc (11127B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <algorithm> 12 #include <cstddef> 13 #include <memory> 14 #include <string> 15 #include <tuple> 16 #include <utility> 17 #include <vector> 18 19 #include "api/test/create_videocodec_test_fixture.h" 20 #include "api/test/videocodec_test_fixture.h" 21 #include "api/video_codecs/h264_profile_level_id.h" 22 #include "media/base/media_constants.h" 23 #include "modules/video_coding/codecs/test/android_codec_factory_helper.h" 24 #include "modules/video_coding/codecs/test/videocodec_test_fixture_impl.h" 25 #include "rtc_base/strings/string_builder.h" 26 #include "test/gtest.h" 27 #include "test/testsupport/file_utils.h" 28 29 namespace webrtc { 30 namespace test { 31 32 namespace { 33 const int kForemanNumFrames = 300; 34 const int kForemanFramerateFps = 30; 35 36 struct RateProfileData { 37 std::string name; 38 std::vector<webrtc::test::RateProfile> rate_profile; 39 }; 40 41 const size_t kConstRateIntervalSec = 10; 42 43 const RateProfileData kBitRateHighLowHigh = { 44 /*name=*/"BitRateHighLowHigh", 45 /*rate_profile=*/{ 46 {/*target_kbps=*/3000, /*input_fps=*/30, /*frame_num=*/0}, 47 {/*target_kbps=*/1500, /*input_fps=*/30, /*frame_num=*/300}, 48 {/*target_kbps=*/750, /*input_fps=*/30, /*frame_num=*/600}, 49 {/*target_kbps=*/1500, /*input_fps=*/30, /*frame_num=*/900}, 50 {/*target_kbps=*/3000, /*input_fps=*/30, /*frame_num=*/1200}}}; 51 52 const RateProfileData kBitRateLowHighLow = { 53 /*name=*/"BitRateLowHighLow", 54 /*rate_profile=*/{ 55 {/*target_kbps=*/750, /*input_fps=*/30, /*frame_num=*/0}, 56 {/*target_kbps=*/1500, /*input_fps=*/30, /*frame_num=*/300}, 57 {/*target_kbps=*/3000, /*input_fps=*/30, /*frame_num=*/600}, 58 {/*target_kbps=*/1500, /*input_fps=*/30, /*frame_num=*/900}, 59 {/*target_kbps=*/750, /*input_fps=*/30, /*frame_num=*/1200}}}; 60 61 const RateProfileData kFrameRateHighLowHigh = { 62 /*name=*/"FrameRateHighLowHigh", 63 /*rate_profile=*/{ 64 {/*target_kbps=*/2000, /*input_fps=*/30, /*frame_num=*/0}, 65 {/*target_kbps=*/2000, /*input_fps=*/15, /*frame_num=*/300}, 66 {/*target_kbps=*/2000, /*input_fps=*/7.5, /*frame_num=*/450}, 67 {/*target_kbps=*/2000, /*input_fps=*/15, /*frame_num=*/525}, 68 {/*target_kbps=*/2000, /*input_fps=*/30, /*frame_num=*/675}}}; 69 70 const RateProfileData kFrameRateLowHighLow = { 71 /*name=*/"FrameRateLowHighLow", 72 /*rate_profile=*/{ 73 {/*target_kbps=*/2000, /*input_fps=*/7.5, /*frame_num=*/0}, 74 {/*target_kbps=*/2000, /*input_fps=*/15, /*frame_num=*/75}, 75 {/*target_kbps=*/2000, /*input_fps=*/30, /*frame_num=*/225}, 76 {/*target_kbps=*/2000, /*input_fps=*/15, /*frame_num=*/525}, 77 {/*target_kbps=*/2000, /*input_fps=*/7.5, /*frame_num=*/775}}}; 78 79 VideoCodecTestFixture::Config CreateConfig() { 80 VideoCodecTestFixture::Config config; 81 config.filename = "foreman_cif"; 82 config.filepath = ResourcePath(config.filename, "yuv"); 83 config.num_frames = kForemanNumFrames; 84 // In order to not overwhelm the OpenMAX buffers in the Android MediaCodec. 85 config.encode_in_real_time = true; 86 return config; 87 } 88 89 std::unique_ptr<VideoCodecTestFixture> CreateTestFixtureWithConfig( 90 VideoCodecTestFixture::Config config) { 91 InitializeAndroidObjects(); // Idempotent. 92 auto encoder_factory = CreateAndroidEncoderFactory(); 93 auto decoder_factory = CreateAndroidDecoderFactory(); 94 return CreateVideoCodecTestFixture(config, std::move(decoder_factory), 95 std::move(encoder_factory)); 96 } 97 } // namespace 98 99 TEST(VideoCodecTestMediaCodec, ForemanCif500kbpsVp8) { 100 auto config = CreateConfig(); 101 config.SetCodecSettings(webrtc::kVp8CodecName, 1, 1, 1, false, false, false, 102 352, 288); 103 auto fixture = CreateTestFixtureWithConfig(config); 104 105 std::vector<RateProfile> rate_profiles = {{500, kForemanFramerateFps, 0}}; 106 107 // The thresholds below may have to be tweaked to let even poor MediaCodec 108 // implementations pass. If this test fails on the bots, disable it and 109 // ping brandtr@. 110 std::vector<RateControlThresholds> rc_thresholds = { 111 {10, 1, 1, 0.1, 0.2, 0.1, 0, 1}}; 112 113 std::vector<QualityThresholds> quality_thresholds = {{36, 31, 0.92, 0.86}}; 114 115 fixture->RunTest(rate_profiles, &rc_thresholds, &quality_thresholds, nullptr); 116 } 117 118 TEST(VideoCodecTestMediaCodec, ForemanCif500kbpsH264CBP) { 119 auto config = CreateConfig(); 120 const auto frame_checker = 121 std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>(); 122 config.encoded_frame_checker = frame_checker.get(); 123 config.SetCodecSettings(webrtc::kH264CodecName, 1, 1, 1, false, false, false, 124 352, 288); 125 auto fixture = CreateTestFixtureWithConfig(config); 126 127 std::vector<RateProfile> rate_profiles = {{500, kForemanFramerateFps, 0}}; 128 129 // The thresholds below may have to be tweaked to let even poor MediaCodec 130 // implementations pass. If this test fails on the bots, disable it and 131 // ping brandtr@. 132 std::vector<RateControlThresholds> rc_thresholds = { 133 {10, 1, 1, 0.1, 0.2, 0.1, 0, 1}}; 134 135 std::vector<QualityThresholds> quality_thresholds = {{36, 31, 0.92, 0.86}}; 136 137 fixture->RunTest(rate_profiles, &rc_thresholds, &quality_thresholds, nullptr); 138 } 139 140 // TODO(brandtr): Enable this test when we have trybots/buildbots with 141 // HW encoders that support CHP. 142 TEST(VideoCodecTestMediaCodec, DISABLED_ForemanCif500kbpsH264CHP) { 143 auto config = CreateConfig(); 144 const auto frame_checker = 145 std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>(); 146 147 config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh; 148 config.encoded_frame_checker = frame_checker.get(); 149 config.SetCodecSettings(webrtc::kH264CodecName, 1, 1, 1, false, false, false, 150 352, 288); 151 auto fixture = CreateTestFixtureWithConfig(config); 152 153 std::vector<RateProfile> rate_profiles = {{500, kForemanFramerateFps, 0}}; 154 155 // The thresholds below may have to be tweaked to let even poor MediaCodec 156 // implementations pass. If this test fails on the bots, disable it and 157 // ping brandtr@. 158 std::vector<RateControlThresholds> rc_thresholds = { 159 {5, 1, 0, 0.1, 0.2, 0.1, 0, 1}}; 160 161 std::vector<QualityThresholds> quality_thresholds = {{37, 35, 0.93, 0.91}}; 162 163 fixture->RunTest(rate_profiles, &rc_thresholds, &quality_thresholds, nullptr); 164 } 165 166 TEST(VideoCodecTestMediaCodec, ForemanMixedRes100kbpsVp8H264) { 167 auto config = CreateConfig(); 168 const int kNumFrames = 30; 169 const std::vector<std::string> codecs = {webrtc::kVp8CodecName, 170 webrtc::kH264CodecName}; 171 const std::vector<std::tuple<int, int>> resolutions = { 172 {128, 96}, {176, 144}, {320, 240}, {480, 272}}; 173 const std::vector<RateProfile> rate_profiles = { 174 {100, kForemanFramerateFps, 0}}; 175 const std::vector<QualityThresholds> quality_thresholds = { 176 {29, 26, 0.8, 0.75}}; 177 178 for (const auto& codec : codecs) { 179 for (const auto& resolution : resolutions) { 180 const int width = std::get<0>(resolution); 181 const int height = std::get<1>(resolution); 182 config.filename = std::string("foreman_") + std::to_string(width) + "x" + 183 std::to_string(height); 184 config.filepath = ResourcePath(config.filename, "yuv"); 185 config.num_frames = kNumFrames; 186 config.SetCodecSettings(codec, 1, 1, 1, false, false, false, width, 187 height); 188 189 auto fixture = CreateTestFixtureWithConfig(config); 190 fixture->RunTest(rate_profiles, nullptr /* rc_thresholds */, 191 &quality_thresholds, nullptr /* bs_thresholds */); 192 } 193 } 194 } 195 196 class VideoCodecTestMediaCodecRateAdaptation 197 : public ::testing::TestWithParam< 198 std::tuple<RateProfileData, std::string>> { 199 public: 200 static std::string ParamInfoToStr( 201 const ::testing::TestParamInfo< 202 VideoCodecTestMediaCodecRateAdaptation::ParamType>& info) { 203 char buf[512]; 204 webrtc::SimpleStringBuilder ss(buf); 205 ss << std::get<0>(info.param).name << "_" << std::get<1>(info.param); 206 return ss.str(); 207 } 208 }; 209 210 TEST_P(VideoCodecTestMediaCodecRateAdaptation, DISABLED_RateAdaptation) { 211 const std::vector<webrtc::test::RateProfile> rate_profile = 212 std::get<0>(GetParam()).rate_profile; 213 const std::string codec_name = std::get<1>(GetParam()); 214 215 VideoCodecTestFixture::Config config; 216 config.filename = "FourPeople_1280x720_30"; 217 config.filepath = ResourcePath(config.filename, "yuv"); 218 config.num_frames = rate_profile.back().frame_num + 219 static_cast<size_t>(kConstRateIntervalSec * 220 rate_profile.back().input_fps); 221 config.encode_in_real_time = true; 222 config.SetCodecSettings(codec_name, 1, 1, 1, false, false, false, 1280, 720); 223 224 auto fixture = CreateTestFixtureWithConfig(config); 225 fixture->RunTest(rate_profile, nullptr, nullptr, nullptr); 226 227 for (size_t i = 0; i < rate_profile.size(); ++i) { 228 const size_t num_frames = 229 static_cast<size_t>(rate_profile[i].input_fps * kConstRateIntervalSec); 230 231 auto stats = fixture->GetStats().SliceAndCalcLayerVideoStatistic( 232 rate_profile[i].frame_num, rate_profile[i].frame_num + num_frames - 1); 233 ASSERT_EQ(stats.size(), 1u); 234 235 // Bitrate mismatch is <= 10%. 236 EXPECT_LE(stats[0].avg_bitrate_mismatch_pct, 10); 237 EXPECT_GE(stats[0].avg_bitrate_mismatch_pct, -10); 238 239 // Avg frame transmission delay and processing latency is <=100..250ms 240 // depending on frame rate. 241 const double expected_delay_sec = 242 std::min(std::max(1 / rate_profile[i].input_fps, 0.1), 0.25); 243 EXPECT_LE(stats[0].avg_delay_sec, expected_delay_sec); 244 EXPECT_LE(stats[0].avg_encode_latency_sec, expected_delay_sec); 245 EXPECT_LE(stats[0].avg_decode_latency_sec, expected_delay_sec); 246 247 // Frame drops are not expected. 248 EXPECT_EQ(stats[0].num_encoded_frames, num_frames); 249 EXPECT_EQ(stats[0].num_decoded_frames, num_frames); 250 251 // Periodic keyframes are not expected. 252 EXPECT_EQ(stats[0].num_key_frames, i == 0 ? 1u : 0); 253 254 // Ensure codec delivers a reasonable spatial quality. 255 EXPECT_GE(stats[0].avg_psnr_y, 35); 256 } 257 } 258 259 INSTANTIATE_TEST_SUITE_P( 260 RateAdaptation, 261 VideoCodecTestMediaCodecRateAdaptation, 262 ::testing::Combine(::testing::Values(kBitRateLowHighLow, 263 kBitRateHighLowHigh, 264 kFrameRateLowHighLow, 265 kFrameRateHighLowHigh), 266 ::testing::Values(webrtc::kVp8CodecName, 267 webrtc::kVp9CodecName, 268 webrtc::kH264CodecName)), 269 VideoCodecTestMediaCodecRateAdaptation::ParamInfoToStr); 270 271 } // namespace test 272 } // namespace webrtc