OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <limits> | 11 #include <limits> |
12 #include <utility> | 12 #include <utility> |
13 | 13 |
14 #include "webrtc/api/video/i420_buffer.h" | 14 #include "webrtc/api/video/i420_buffer.h" |
| 15 #include "webrtc/base/fakeclock.h" |
15 #include "webrtc/base/logging.h" | 16 #include "webrtc/base/logging.h" |
16 #include "webrtc/media/base/videoadapter.h" | 17 #include "webrtc/media/base/videoadapter.h" |
17 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" | 18 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" |
18 #include "webrtc/system_wrappers/include/metrics_default.h" | 19 #include "webrtc/system_wrappers/include/metrics_default.h" |
19 #include "webrtc/system_wrappers/include/sleep.h" | 20 #include "webrtc/system_wrappers/include/sleep.h" |
20 #include "webrtc/test/encoder_settings.h" | 21 #include "webrtc/test/encoder_settings.h" |
21 #include "webrtc/test/fake_encoder.h" | 22 #include "webrtc/test/fake_encoder.h" |
22 #include "webrtc/test/frame_generator.h" | 23 #include "webrtc/test/frame_generator.h" |
23 #include "webrtc/test/gmock.h" | 24 #include "webrtc/test/gmock.h" |
24 #include "webrtc/test/gtest.h" | 25 #include "webrtc/test/gtest.h" |
25 #include "webrtc/video/send_statistics_proxy.h" | 26 #include "webrtc/video/send_statistics_proxy.h" |
26 #include "webrtc/video/vie_encoder.h" | 27 #include "webrtc/video/vie_encoder.h" |
27 | 28 |
28 namespace { | 29 namespace { |
29 #if defined(WEBRTC_ANDROID) | 30 #if defined(WEBRTC_ANDROID) |
30 // TODO(kthelgason): Lower this limit when better testing | 31 // TODO(kthelgason): Lower this limit when better testing |
31 // on MediaCodec and fallback implementations are in place. | 32 // on MediaCodec and fallback implementations are in place. |
32 const int kMinPixelsPerFrame = 320 * 180; | 33 const int kMinPixelsPerFrame = 320 * 180; |
33 #else | 34 #else |
34 const int kMinPixelsPerFrame = 120 * 90; | 35 const int kMinPixelsPerFrame = 120 * 90; |
35 #endif | 36 #endif |
36 } | 37 const int kMinFramerateFps = 2; |
| 38 const int64_t kFrameTimeoutMs = 100; |
| 39 } // namespace |
37 | 40 |
38 namespace webrtc { | 41 namespace webrtc { |
39 | 42 |
40 using DegredationPreference = VideoSendStream::DegradationPreference; | 43 using DegredationPreference = VideoSendStream::DegradationPreference; |
41 using ScaleReason = AdaptationObserverInterface::AdaptReason; | 44 using ScaleReason = AdaptationObserverInterface::AdaptReason; |
42 using ::testing::_; | 45 using ::testing::_; |
43 using ::testing::Return; | 46 using ::testing::Return; |
44 | 47 |
45 namespace { | 48 namespace { |
46 const size_t kMaxPayloadLength = 1440; | 49 const size_t kMaxPayloadLength = 1440; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 bool adaption_enabled() { | 129 bool adaption_enabled() { |
127 rtc::CritScope cs(&crit_); | 130 rtc::CritScope cs(&crit_); |
128 return adaptation_enabled_; | 131 return adaptation_enabled_; |
129 } | 132 } |
130 | 133 |
131 void IncomingCapturedFrame(const VideoFrame& video_frame) override { | 134 void IncomingCapturedFrame(const VideoFrame& video_frame) override { |
132 int cropped_width = 0; | 135 int cropped_width = 0; |
133 int cropped_height = 0; | 136 int cropped_height = 0; |
134 int out_width = 0; | 137 int out_width = 0; |
135 int out_height = 0; | 138 int out_height = 0; |
136 if (adaption_enabled() && | 139 if (adaption_enabled()) { |
137 adapter_.AdaptFrameResolution(video_frame.width(), video_frame.height(), | 140 if (adapter_.AdaptFrameResolution( |
138 video_frame.timestamp_us() * 1000, | 141 video_frame.width(), video_frame.height(), |
139 &cropped_width, &cropped_height, | 142 video_frame.timestamp_us() * 1000, &cropped_width, |
140 &out_width, &out_height)) { | 143 &cropped_height, &out_width, &out_height)) { |
141 VideoFrame adapted_frame( | 144 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>( |
142 new rtc::RefCountedObject<TestBuffer>(nullptr, out_width, out_height), | 145 nullptr, out_width, out_height), |
143 99, 99, kVideoRotation_0); | 146 99, 99, kVideoRotation_0); |
144 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms()); | 147 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms()); |
145 test::FrameForwarder::IncomingCapturedFrame(adapted_frame); | 148 test::FrameForwarder::IncomingCapturedFrame(adapted_frame); |
| 149 } |
146 } else { | 150 } else { |
147 test::FrameForwarder::IncomingCapturedFrame(video_frame); | 151 test::FrameForwarder::IncomingCapturedFrame(video_frame); |
148 } | 152 } |
149 } | 153 } |
150 | 154 |
151 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, | 155 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, |
152 const rtc::VideoSinkWants& wants) override { | 156 const rtc::VideoSinkWants& wants) override { |
153 rtc::CritScope cs(&crit_); | 157 rtc::CritScope cs(&crit_); |
154 adapter_.OnResolutionRequest(wants.target_pixel_count, | 158 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count, |
155 wants.max_pixel_count); | 159 wants.max_pixel_count, |
| 160 wants.max_framerate_fps_); |
156 test::FrameForwarder::AddOrUpdateSink(sink, wants); | 161 test::FrameForwarder::AddOrUpdateSink(sink, wants); |
157 } | 162 } |
158 | 163 |
159 cricket::VideoAdapter adapter_; | 164 cricket::VideoAdapter adapter_; |
160 bool adaptation_enabled_ GUARDED_BY(crit_); | 165 bool adaptation_enabled_ GUARDED_BY(crit_); |
161 }; | 166 }; |
162 } // namespace | 167 } // namespace |
163 | 168 |
164 class ViEEncoderTest : public ::testing::Test { | 169 class ViEEncoderTest : public ::testing::Test { |
165 public: | 170 public: |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 99, 99, kVideoRotation_0); | 229 99, 99, kVideoRotation_0); |
225 frame.set_ntp_time_ms(ntp_time_ms); | 230 frame.set_ntp_time_ms(ntp_time_ms); |
226 return frame; | 231 return frame; |
227 } | 232 } |
228 | 233 |
229 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const { | 234 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const { |
230 VideoFrame frame( | 235 VideoFrame frame( |
231 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99, | 236 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99, |
232 kVideoRotation_0); | 237 kVideoRotation_0); |
233 frame.set_ntp_time_ms(ntp_time_ms); | 238 frame.set_ntp_time_ms(ntp_time_ms); |
| 239 frame.set_timestamp_us(ntp_time_ms * 1000); |
234 return frame; | 240 return frame; |
235 } | 241 } |
236 | 242 |
237 class TestEncoder : public test::FakeEncoder { | 243 class TestEncoder : public test::FakeEncoder { |
238 public: | 244 public: |
239 TestEncoder() | 245 TestEncoder() |
240 : FakeEncoder(Clock::GetRealTimeClock()), | 246 : FakeEncoder(Clock::GetRealTimeClock()), |
241 continue_encode_event_(false, false) {} | 247 continue_encode_event_(false, false) {} |
242 | 248 |
243 VideoCodec codec_config() { | 249 VideoCodec codec_config() { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); | 318 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
313 { | 319 { |
314 rtc::CritScope lock(&crit_); | 320 rtc::CritScope lock(&crit_); |
315 timestamp = last_timestamp_; | 321 timestamp = last_timestamp_; |
316 } | 322 } |
317 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp); | 323 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp); |
318 } | 324 } |
319 | 325 |
320 void WaitForEncodedFrame(uint32_t expected_width, | 326 void WaitForEncodedFrame(uint32_t expected_width, |
321 uint32_t expected_height) { | 327 uint32_t expected_height) { |
| 328 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
| 329 CheckLastFrameSizeMathces(expected_width, expected_height); |
| 330 } |
| 331 |
| 332 void CheckLastFrameSizeMathces(uint32_t expected_width, |
| 333 uint32_t expected_height) { |
322 uint32_t width = 0; | 334 uint32_t width = 0; |
323 uint32_t height = 0; | 335 uint32_t height = 0; |
324 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); | |
325 { | 336 { |
326 rtc::CritScope lock(&crit_); | 337 rtc::CritScope lock(&crit_); |
327 width = last_width_; | 338 width = last_width_; |
328 height = last_height_; | 339 height = last_height_; |
329 } | 340 } |
330 EXPECT_EQ(expected_height, height); | 341 EXPECT_EQ(expected_height, height); |
331 EXPECT_EQ(expected_width, width); | 342 EXPECT_EQ(expected_width, width); |
332 } | 343 } |
333 | 344 |
334 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(20)); } | 345 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(20)); } |
335 | 346 |
| 347 bool WaitForFrame(int64_t timeout_ms) { |
| 348 return encoded_frame_event_.Wait(timeout_ms); |
| 349 } |
| 350 |
336 void SetExpectNoFrames() { | 351 void SetExpectNoFrames() { |
337 rtc::CritScope lock(&crit_); | 352 rtc::CritScope lock(&crit_); |
338 expect_frames_ = false; | 353 expect_frames_ = false; |
339 } | 354 } |
340 | 355 |
341 int number_of_reconfigurations() { | 356 int number_of_reconfigurations() { |
342 rtc::CritScope lock(&crit_); | 357 rtc::CritScope lock(&crit_); |
343 return number_of_reconfigurations_; | 358 return number_of_reconfigurations_; |
344 } | 359 } |
345 | 360 |
(...skipping 872 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1218 video_source_.IncomingCapturedFrame( | 1233 video_source_.IncomingCapturedFrame( |
1219 CreateFrame(1, kFrameWidth, kFrameHeight)); | 1234 CreateFrame(1, kFrameWidth, kFrameHeight)); |
1220 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); | 1235 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
1221 | 1236 |
1222 // Trigger CPU overuse, downscale by 3/4. | 1237 // Trigger CPU overuse, downscale by 3/4. |
1223 vie_encoder_->TriggerCpuOveruse(); | 1238 vie_encoder_->TriggerCpuOveruse(); |
1224 video_source_.IncomingCapturedFrame( | 1239 video_source_.IncomingCapturedFrame( |
1225 CreateFrame(2, kFrameWidth, kFrameHeight)); | 1240 CreateFrame(2, kFrameWidth, kFrameHeight)); |
1226 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4); | 1241 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4); |
1227 | 1242 |
1228 // Trigger CPU normal use, return to original resoluton; | 1243 // Trigger CPU normal use, return to original resolution; |
1229 vie_encoder_->TriggerCpuNormalUsage(); | 1244 vie_encoder_->TriggerCpuNormalUsage(); |
1230 video_source_.IncomingCapturedFrame( | 1245 video_source_.IncomingCapturedFrame( |
1231 CreateFrame(3, kFrameWidth, kFrameHeight)); | 1246 CreateFrame(3, kFrameWidth, kFrameHeight)); |
1232 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); | 1247 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
1233 | 1248 |
1234 vie_encoder_->Stop(); | 1249 vie_encoder_->Stop(); |
1235 } | 1250 } |
| 1251 |
| 1252 TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) { |
| 1253 const int kDefaultFramerateFps = 30; |
| 1254 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps; |
| 1255 const int kFrameWidth = 1280; |
| 1256 const int kFrameHeight = 720; |
| 1257 rtc::ScopedFakeClock fake_clock; |
| 1258 |
| 1259 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
| 1260 vie_encoder_->SetSource( |
| 1261 &video_source_, |
| 1262 VideoSendStream::DegradationPreference::kMaintainResolution); |
| 1263 video_source_.set_adaptation_enabled(true); |
| 1264 |
| 1265 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000); |
| 1266 int64_t timestamp_ms = kFrameIntervalMs; |
| 1267 |
| 1268 video_source_.IncomingCapturedFrame( |
| 1269 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1270 sink_.WaitForEncodedFrame(timestamp_ms); |
| 1271 |
| 1272 // Try to trigger overuse. No fps estimate available => no effect. |
| 1273 vie_encoder_->TriggerCpuOveruse(); |
| 1274 |
| 1275 // Insert frames for one second to get a stable estimate. |
| 1276 for (int i = 0; i < kDefaultFramerateFps; ++i) { |
| 1277 timestamp_ms += kFrameIntervalMs; |
| 1278 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1279 video_source_.IncomingCapturedFrame( |
| 1280 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1281 sink_.WaitForEncodedFrame(timestamp_ms); |
| 1282 } |
| 1283 |
| 1284 // Trigger CPU overuse, reduce framerate by 2/3. |
| 1285 vie_encoder_->TriggerCpuOveruse(); |
| 1286 int num_frames_dropped = 0; |
| 1287 for (int i = 0; i < kDefaultFramerateFps; ++i) { |
| 1288 timestamp_ms += kFrameIntervalMs; |
| 1289 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1290 video_source_.IncomingCapturedFrame( |
| 1291 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1292 if (!sink_.WaitForFrame(kFrameTimeoutMs)) { |
| 1293 ++num_frames_dropped; |
| 1294 } else { |
| 1295 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight); |
| 1296 } |
| 1297 } |
| 1298 |
| 1299 // TODO(sprang): Find where there's rounding errors or stuff causing the |
| 1300 // margin here to be a little larger than we'd like (input fps estimate is |
| 1301 // off) and the frame dropping is a little too aggressive. |
| 1302 const int kErrorMargin = 5; |
| 1303 EXPECT_NEAR(num_frames_dropped, |
| 1304 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3), |
| 1305 kErrorMargin); |
| 1306 |
| 1307 // Trigger CPU overuse, reduce framerate by 2/3 again. |
| 1308 vie_encoder_->TriggerCpuOveruse(); |
| 1309 num_frames_dropped = 0; |
| 1310 for (int i = 0; i < kDefaultFramerateFps; ++i) { |
| 1311 timestamp_ms += kFrameIntervalMs; |
| 1312 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1313 video_source_.IncomingCapturedFrame( |
| 1314 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1315 if (!sink_.WaitForFrame(kFrameTimeoutMs)) { |
| 1316 ++num_frames_dropped; |
| 1317 } else { |
| 1318 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight); |
| 1319 } |
| 1320 } |
| 1321 EXPECT_NEAR(num_frames_dropped, |
| 1322 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9), |
| 1323 kErrorMargin); |
| 1324 |
| 1325 // Go back up one step. |
| 1326 vie_encoder_->TriggerCpuNormalUsage(); |
| 1327 num_frames_dropped = 0; |
| 1328 for (int i = 0; i < kDefaultFramerateFps; ++i) { |
| 1329 timestamp_ms += kFrameIntervalMs; |
| 1330 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1331 video_source_.IncomingCapturedFrame( |
| 1332 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1333 if (!sink_.WaitForFrame(kFrameTimeoutMs)) { |
| 1334 ++num_frames_dropped; |
| 1335 } else { |
| 1336 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight); |
| 1337 } |
| 1338 } |
| 1339 EXPECT_NEAR(num_frames_dropped, |
| 1340 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3), |
| 1341 kErrorMargin); |
| 1342 |
| 1343 // Go back up to original mode. |
| 1344 vie_encoder_->TriggerCpuNormalUsage(); |
| 1345 num_frames_dropped = 0; |
| 1346 for (int i = 0; i < kDefaultFramerateFps; ++i) { |
| 1347 timestamp_ms += kFrameIntervalMs; |
| 1348 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1349 video_source_.IncomingCapturedFrame( |
| 1350 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1351 if (!sink_.WaitForFrame(kFrameTimeoutMs)) { |
| 1352 ++num_frames_dropped; |
| 1353 } else { |
| 1354 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight); |
| 1355 } |
| 1356 } |
| 1357 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin); |
| 1358 |
| 1359 vie_encoder_->Stop(); |
| 1360 } |
| 1361 |
| 1362 TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) { |
| 1363 const int kFramerateFps = 5; |
| 1364 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps; |
| 1365 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps; |
| 1366 const int kFrameWidth = 1280; |
| 1367 const int kFrameHeight = 720; |
| 1368 |
| 1369 rtc::ScopedFakeClock fake_clock; |
| 1370 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
| 1371 vie_encoder_->SetSource( |
| 1372 &video_source_, |
| 1373 VideoSendStream::DegradationPreference::kMaintainResolution); |
| 1374 video_source_.set_adaptation_enabled(true); |
| 1375 |
| 1376 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000); |
| 1377 int64_t timestamp_ms = kFrameIntervalMs; |
| 1378 |
| 1379 // Trigger overuse as much as we can. |
| 1380 for (int i = 0; i < ViEEncoder::kMaxCpuDowngrades; ++i) { |
| 1381 // Insert frames to get a new fps estimate... |
| 1382 for (int j = 0; j < kFramerateFps; ++j) { |
| 1383 video_source_.IncomingCapturedFrame( |
| 1384 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1385 timestamp_ms += kFrameIntervalMs; |
| 1386 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000); |
| 1387 } |
| 1388 // ...and then try to adapt again. |
| 1389 vie_encoder_->TriggerCpuOveruse(); |
| 1390 } |
| 1391 |
| 1392 // Drain any frame in the pipeline. |
| 1393 sink_.WaitForFrame(kDefaultTimeoutMs); |
| 1394 |
| 1395 // Insert frames at min fps, all should go through. |
| 1396 for (int i = 0; i < 10; ++i) { |
| 1397 timestamp_ms += kMinFpsFrameInterval; |
| 1398 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000); |
| 1399 video_source_.IncomingCapturedFrame( |
| 1400 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); |
| 1401 sink_.WaitForEncodedFrame(timestamp_ms); |
| 1402 } |
| 1403 |
| 1404 vie_encoder_->Stop(); |
| 1405 } |
1236 } // namespace webrtc | 1406 } // namespace webrtc |
OLD | NEW |