Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: webrtc/video/vie_encoder_unittest.cc

Issue 2716643002: Add framerate to VideoSinkWants and ability to signal on overuse (Closed)
Patch Set: Added tests, fixed bugs, rebase, address comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/video/vie_encoder.cc ('k') | webrtc/video_send_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 roundign errors or stuff causing the
magjed_webrtc 2017/02/28 14:21:55 spelling nit: rounding Also, this comment is a lit
sprang_webrtc 2017/02/28 15:15:30 Done. And yes :(
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
OLDNEW
« no previous file with comments | « webrtc/video/vie_encoder.cc ('k') | webrtc/video_send_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698