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/logging.h" | 15 #include "webrtc/base/logging.h" |
| 16 #include "webrtc/media/base/videoadapter.h" |
16 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" | 17 #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" |
17 #include "webrtc/system_wrappers/include/metrics_default.h" | 18 #include "webrtc/system_wrappers/include/metrics_default.h" |
18 #include "webrtc/system_wrappers/include/sleep.h" | 19 #include "webrtc/system_wrappers/include/sleep.h" |
19 #include "webrtc/test/encoder_settings.h" | 20 #include "webrtc/test/encoder_settings.h" |
20 #include "webrtc/test/fake_encoder.h" | 21 #include "webrtc/test/fake_encoder.h" |
21 #include "webrtc/test/frame_generator.h" | 22 #include "webrtc/test/frame_generator.h" |
22 #include "webrtc/test/gmock.h" | 23 #include "webrtc/test/gmock.h" |
23 #include "webrtc/test/gtest.h" | 24 #include "webrtc/test/gtest.h" |
24 #include "webrtc/video/send_statistics_proxy.h" | 25 #include "webrtc/video/send_statistics_proxy.h" |
25 #include "webrtc/video/vie_encoder.h" | 26 #include "webrtc/video/vie_encoder.h" |
26 | 27 |
27 namespace { | 28 namespace { |
28 #if defined(WEBRTC_ANDROID) | 29 #if defined(WEBRTC_ANDROID) |
29 // TODO(kthelgason): Lower this limit when better testing | 30 // TODO(kthelgason): Lower this limit when better testing |
30 // on MediaCodec and fallback implementations are in place. | 31 // on MediaCodec and fallback implementations are in place. |
31 const int kMinPixelsPerFrame = 320 * 180; | 32 const int kMinPixelsPerFrame = 320 * 180; |
32 #else | 33 #else |
33 const int kMinPixelsPerFrame = 120 * 90; | 34 const int kMinPixelsPerFrame = 120 * 90; |
34 #endif | 35 #endif |
35 } | 36 } |
36 | 37 |
37 namespace webrtc { | 38 namespace webrtc { |
38 | 39 |
39 using DegredationPreference = VideoSendStream::DegradationPreference; | 40 using DegredationPreference = VideoSendStream::DegradationPreference; |
40 using ScaleReason = ScalingObserverInterface::ScaleReason; | 41 using ScaleReason = AdaptationObserverInterface::AdaptReason; |
41 using ::testing::_; | 42 using ::testing::_; |
42 using ::testing::Return; | 43 using ::testing::Return; |
43 | 44 |
44 namespace { | 45 namespace { |
45 const size_t kMaxPayloadLength = 1440; | 46 const size_t kMaxPayloadLength = 1440; |
46 const int kTargetBitrateBps = 100000; | 47 const int kTargetBitrateBps = 100000; |
47 | 48 |
48 class TestBuffer : public webrtc::I420Buffer { | 49 class TestBuffer : public webrtc::I420Buffer { |
49 public: | 50 public: |
50 TestBuffer(rtc::Event* event, int width, int height) | 51 TestBuffer(rtc::Event* event, int width, int height) |
(...skipping 11 matching lines...) Expand all Loading... |
62 class ViEEncoderUnderTest : public ViEEncoder { | 63 class ViEEncoderUnderTest : public ViEEncoder { |
63 public: | 64 public: |
64 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy, | 65 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy, |
65 const VideoSendStream::Config::EncoderSettings& settings) | 66 const VideoSendStream::Config::EncoderSettings& settings) |
66 : ViEEncoder(1 /* number_of_cores */, | 67 : ViEEncoder(1 /* number_of_cores */, |
67 stats_proxy, | 68 stats_proxy, |
68 settings, | 69 settings, |
69 nullptr /* pre_encode_callback */, | 70 nullptr /* pre_encode_callback */, |
70 nullptr /* encoder_timing */) {} | 71 nullptr /* encoder_timing */) {} |
71 | 72 |
72 void PostTaskAndWait(bool down, ScaleReason reason) { | 73 void PostTaskAndWait(bool down, AdaptReason reason) { |
73 rtc::Event event(false, false); | 74 rtc::Event event(false, false); |
74 encoder_queue()->PostTask([this, &event, reason, down] { | 75 encoder_queue()->PostTask([this, &event, reason, down] { |
75 down ? ScaleDown(reason) : ScaleUp(reason); | 76 down ? AdaptDown(reason) : AdaptUp(reason); |
76 event.Set(); | 77 event.Set(); |
77 }); | 78 }); |
78 RTC_DCHECK(event.Wait(5000)); | 79 RTC_DCHECK(event.Wait(5000)); |
79 } | 80 } |
80 | 81 |
81 void TriggerCpuOveruse() { PostTaskAndWait(true, ScaleReason::kCpu); } | 82 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); } |
82 | 83 |
83 void TriggerCpuNormalUsage() { PostTaskAndWait(false, ScaleReason::kCpu); } | 84 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); } |
84 | 85 |
85 void TriggerQualityLow() { PostTaskAndWait(true, ScaleReason::kQuality); } | 86 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); } |
86 | 87 |
87 void TriggerQualityHigh() { PostTaskAndWait(false, ScaleReason::kQuality); } | 88 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); } |
88 }; | 89 }; |
89 | 90 |
90 class VideoStreamFactory | 91 class VideoStreamFactory |
91 : public VideoEncoderConfig::VideoStreamFactoryInterface { | 92 : public VideoEncoderConfig::VideoStreamFactoryInterface { |
92 public: | 93 public: |
93 explicit VideoStreamFactory(size_t num_temporal_layers) | 94 explicit VideoStreamFactory(size_t num_temporal_layers) |
94 : num_temporal_layers_(num_temporal_layers) { | 95 : num_temporal_layers_(num_temporal_layers) { |
95 EXPECT_GT(num_temporal_layers, 0u); | 96 EXPECT_GT(num_temporal_layers, 0u); |
96 } | 97 } |
97 | 98 |
98 private: | 99 private: |
99 std::vector<VideoStream> CreateEncoderStreams( | 100 std::vector<VideoStream> CreateEncoderStreams( |
100 int width, | 101 int width, |
101 int height, | 102 int height, |
102 const VideoEncoderConfig& encoder_config) override { | 103 const VideoEncoderConfig& encoder_config) override { |
103 std::vector<VideoStream> streams = | 104 std::vector<VideoStream> streams = |
104 test::CreateVideoStreams(width, height, encoder_config); | 105 test::CreateVideoStreams(width, height, encoder_config); |
105 for (VideoStream& stream : streams) { | 106 for (VideoStream& stream : streams) { |
106 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1); | 107 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1); |
107 } | 108 } |
108 return streams; | 109 return streams; |
109 } | 110 } |
110 const size_t num_temporal_layers_; | 111 const size_t num_temporal_layers_; |
111 }; | 112 }; |
112 | 113 |
| 114 class AdaptingFrameForwarder : public test::FrameForwarder { |
| 115 public: |
| 116 AdaptingFrameForwarder() : adaptation_enabled_(false) {} |
| 117 virtual ~AdaptingFrameForwarder() {} |
| 118 |
| 119 void set_adaptation_enabled(bool enabled) { |
| 120 rtc::CritScope cs(&crit_); |
| 121 adaptation_enabled_ = enabled; |
| 122 } |
| 123 |
| 124 bool adaption_enabled() { |
| 125 rtc::CritScope cs(&crit_); |
| 126 return adaptation_enabled_; |
| 127 } |
| 128 |
| 129 void IncomingCapturedFrame(const VideoFrame& video_frame) override { |
| 130 int cropped_width = 0; |
| 131 int cropped_height = 0; |
| 132 int out_width = 0; |
| 133 int out_height = 0; |
| 134 if (adaption_enabled() && |
| 135 adapter_.AdaptFrameResolution(video_frame.width(), video_frame.height(), |
| 136 video_frame.timestamp_us() * 1000, |
| 137 &cropped_width, &cropped_height, |
| 138 &out_width, &out_height)) { |
| 139 VideoFrame adapted_frame( |
| 140 new rtc::RefCountedObject<TestBuffer>(nullptr, out_width, out_height), |
| 141 99, 99, kVideoRotation_0); |
| 142 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms()); |
| 143 test::FrameForwarder::IncomingCapturedFrame(adapted_frame); |
| 144 } else { |
| 145 test::FrameForwarder::IncomingCapturedFrame(video_frame); |
| 146 } |
| 147 } |
| 148 |
| 149 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, |
| 150 const rtc::VideoSinkWants& wants) override { |
| 151 rtc::CritScope cs(&crit_); |
| 152 adapter_.OnResolutionRequest(wants.max_pixel_count, |
| 153 wants.max_pixel_count_step_up); |
| 154 test::FrameForwarder::AddOrUpdateSink(sink, wants); |
| 155 } |
| 156 |
| 157 cricket::VideoAdapter adapter_; |
| 158 bool adaptation_enabled_ GUARDED_BY(crit_); |
| 159 }; |
113 } // namespace | 160 } // namespace |
114 | 161 |
115 class ViEEncoderTest : public ::testing::Test { | 162 class ViEEncoderTest : public ::testing::Test { |
116 public: | 163 public: |
117 static const int kDefaultTimeoutMs = 30 * 1000; | 164 static const int kDefaultTimeoutMs = 30 * 1000; |
118 | 165 |
119 ViEEncoderTest() | 166 ViEEncoderTest() |
120 : video_send_config_(VideoSendStream::Config(nullptr)), | 167 : video_send_config_(VideoSendStream::Config(nullptr)), |
121 codec_width_(320), | 168 codec_width_(320), |
122 codec_height_(240), | 169 codec_height_(240), |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 class TestSink : public ViEEncoder::EncoderSink { | 298 class TestSink : public ViEEncoder::EncoderSink { |
252 public: | 299 public: |
253 explicit TestSink(TestEncoder* test_encoder) | 300 explicit TestSink(TestEncoder* test_encoder) |
254 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {} | 301 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {} |
255 | 302 |
256 void WaitForEncodedFrame(int64_t expected_ntp_time) { | 303 void WaitForEncodedFrame(int64_t expected_ntp_time) { |
257 uint32_t timestamp = 0; | 304 uint32_t timestamp = 0; |
258 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); | 305 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
259 { | 306 { |
260 rtc::CritScope lock(&crit_); | 307 rtc::CritScope lock(&crit_); |
261 timestamp = timestamp_; | 308 timestamp = last_timestamp_; |
262 } | 309 } |
263 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp); | 310 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp); |
264 } | 311 } |
265 | 312 |
| 313 void WaitForEncodedFrame(uint32_t expected_width, |
| 314 uint32_t expected_height) { |
| 315 uint32_t width = 0; |
| 316 uint32_t height = 0; |
| 317 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
| 318 { |
| 319 rtc::CritScope lock(&crit_); |
| 320 width = last_width_; |
| 321 height = last_height_; |
| 322 } |
| 323 EXPECT_EQ(expected_height, height); |
| 324 EXPECT_EQ(expected_width, width); |
| 325 } |
| 326 |
266 void SetExpectNoFrames() { | 327 void SetExpectNoFrames() { |
267 rtc::CritScope lock(&crit_); | 328 rtc::CritScope lock(&crit_); |
268 expect_frames_ = false; | 329 expect_frames_ = false; |
269 } | 330 } |
270 | 331 |
271 int number_of_reconfigurations() { | 332 int number_of_reconfigurations() { |
272 rtc::CritScope lock(&crit_); | 333 rtc::CritScope lock(&crit_); |
273 return number_of_reconfigurations_; | 334 return number_of_reconfigurations_; |
274 } | 335 } |
275 | 336 |
276 int last_min_transmit_bitrate() { | 337 int last_min_transmit_bitrate() { |
277 rtc::CritScope lock(&crit_); | 338 rtc::CritScope lock(&crit_); |
278 return min_transmit_bitrate_bps_; | 339 return min_transmit_bitrate_bps_; |
279 } | 340 } |
280 | 341 |
281 private: | 342 private: |
282 Result OnEncodedImage( | 343 Result OnEncodedImage( |
283 const EncodedImage& encoded_image, | 344 const EncodedImage& encoded_image, |
284 const CodecSpecificInfo* codec_specific_info, | 345 const CodecSpecificInfo* codec_specific_info, |
285 const RTPFragmentationHeader* fragmentation) override { | 346 const RTPFragmentationHeader* fragmentation) override { |
286 rtc::CritScope lock(&crit_); | 347 rtc::CritScope lock(&crit_); |
287 EXPECT_TRUE(expect_frames_); | 348 EXPECT_TRUE(expect_frames_); |
288 timestamp_ = encoded_image._timeStamp; | 349 last_timestamp_ = encoded_image._timeStamp; |
| 350 last_width_ = encoded_image._encodedWidth; |
| 351 last_height_ = encoded_image._encodedHeight; |
289 encoded_frame_event_.Set(); | 352 encoded_frame_event_.Set(); |
290 return Result(Result::OK, timestamp_); | 353 return Result(Result::OK, last_timestamp_); |
291 } | 354 } |
292 | 355 |
293 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams, | 356 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams, |
294 int min_transmit_bitrate_bps) override { | 357 int min_transmit_bitrate_bps) override { |
295 rtc::CriticalSection crit_; | 358 rtc::CriticalSection crit_; |
296 ++number_of_reconfigurations_; | 359 ++number_of_reconfigurations_; |
297 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps; | 360 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps; |
298 } | 361 } |
299 | 362 |
300 rtc::CriticalSection crit_; | 363 rtc::CriticalSection crit_; |
301 TestEncoder* test_encoder_; | 364 TestEncoder* test_encoder_; |
302 rtc::Event encoded_frame_event_; | 365 rtc::Event encoded_frame_event_; |
303 uint32_t timestamp_ = 0; | 366 uint32_t last_timestamp_ = 0; |
| 367 uint32_t last_height_ = 0; |
| 368 uint32_t last_width_ = 0; |
304 bool expect_frames_ = true; | 369 bool expect_frames_ = true; |
305 int number_of_reconfigurations_ = 0; | 370 int number_of_reconfigurations_ = 0; |
306 int min_transmit_bitrate_bps_ = 0; | 371 int min_transmit_bitrate_bps_ = 0; |
307 }; | 372 }; |
308 | 373 |
309 VideoSendStream::Config video_send_config_; | 374 VideoSendStream::Config video_send_config_; |
310 VideoEncoderConfig video_encoder_config_; | 375 VideoEncoderConfig video_encoder_config_; |
311 int codec_width_; | 376 int codec_width_; |
312 int codec_height_; | 377 int codec_height_; |
313 TestEncoder fake_encoder_; | 378 TestEncoder fake_encoder_; |
314 std::unique_ptr<SendStatisticsProxy> stats_proxy_; | 379 std::unique_ptr<SendStatisticsProxy> stats_proxy_; |
315 TestSink sink_; | 380 TestSink sink_; |
316 test::FrameForwarder video_source_; | 381 AdaptingFrameForwarder video_source_; |
317 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_; | 382 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_; |
318 }; | 383 }; |
319 | 384 |
320 TEST_F(ViEEncoderTest, EncodeOneFrame) { | 385 TEST_F(ViEEncoderTest, EncodeOneFrame) { |
321 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); | 386 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
322 rtc::Event frame_destroyed_event(false, false); | 387 rtc::Event frame_destroyed_event(false, false); |
323 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event)); | 388 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event)); |
324 sink_.WaitForEncodedFrame(1); | 389 sink_.WaitForEncodedFrame(1); |
325 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs)); | 390 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs)); |
326 vie_encoder_->Stop(); | 391 vie_encoder_->Stop(); |
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1022 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps); | 1087 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps); |
1023 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate)) | 1088 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate)) |
1024 .Times(1); | 1089 .Times(1); |
1025 video_source_.IncomingCapturedFrame(CreateFrame( | 1090 video_source_.IncomingCapturedFrame(CreateFrame( |
1026 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_)); | 1091 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_)); |
1027 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs); | 1092 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs); |
1028 | 1093 |
1029 vie_encoder_->Stop(); | 1094 vie_encoder_->Stop(); |
1030 } | 1095 } |
1031 | 1096 |
| 1097 // TODO(sprang): Extend this with fps throttling and any "balanced" extensions. |
| 1098 TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) { |
| 1099 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
| 1100 |
| 1101 const int kFrameWidth = 1280; |
| 1102 const int kFrameHeight = 720; |
| 1103 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as |
| 1104 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan(). |
| 1105 video_source_.set_adaptation_enabled(true); |
| 1106 |
| 1107 video_source_.IncomingCapturedFrame( |
| 1108 CreateFrame(1, kFrameWidth, kFrameHeight)); |
| 1109 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
| 1110 |
| 1111 // Trigger CPU overuse, downscale by 3/4. |
| 1112 vie_encoder_->TriggerCpuOveruse(); |
| 1113 video_source_.IncomingCapturedFrame( |
| 1114 CreateFrame(2, kFrameWidth, kFrameHeight)); |
| 1115 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4); |
| 1116 |
| 1117 // Trigger CPU normal use, return to original resoluton; |
| 1118 vie_encoder_->TriggerCpuNormalUsage(); |
| 1119 video_source_.IncomingCapturedFrame( |
| 1120 CreateFrame(3, kFrameWidth, kFrameHeight)); |
| 1121 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
| 1122 |
| 1123 vie_encoder_->Stop(); |
| 1124 } |
| 1125 |
1032 } // namespace webrtc | 1126 } // namespace webrtc |
OLD | NEW |