Index: webrtc/video/vie_encoder_unittest.cc |
diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc |
index dae172dea353e5d198584f8a01921fbb86103c69..427796ed5eb41afefe9202c0d442a22ae90e7b5c 100644 |
--- a/webrtc/video/vie_encoder_unittest.cc |
+++ b/webrtc/video/vie_encoder_unittest.cc |
@@ -13,6 +13,7 @@ |
#include "webrtc/api/video/i420_buffer.h" |
#include "webrtc/base/logging.h" |
+#include "webrtc/media/base/videoadapter.h" |
#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" |
#include "webrtc/system_wrappers/include/metrics_default.h" |
#include "webrtc/system_wrappers/include/sleep.h" |
@@ -37,7 +38,7 @@ const int kMinPixelsPerFrame = 120 * 90; |
namespace webrtc { |
using DegredationPreference = VideoSendStream::DegradationPreference; |
-using ScaleReason = ScalingObserverInterface::ScaleReason; |
+using ScaleReason = AdaptationObserverInterface::AdaptReason; |
using ::testing::_; |
using ::testing::Return; |
@@ -69,22 +70,22 @@ class ViEEncoderUnderTest : public ViEEncoder { |
nullptr /* pre_encode_callback */, |
nullptr /* encoder_timing */) {} |
- void PostTaskAndWait(bool down, ScaleReason reason) { |
+ void PostTaskAndWait(bool down, AdaptReason reason) { |
rtc::Event event(false, false); |
encoder_queue()->PostTask([this, &event, reason, down] { |
- down ? ScaleDown(reason) : ScaleUp(reason); |
+ down ? AdaptDown(reason) : AdaptUp(reason); |
event.Set(); |
}); |
RTC_DCHECK(event.Wait(5000)); |
} |
- void TriggerCpuOveruse() { PostTaskAndWait(true, ScaleReason::kCpu); } |
+ void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); } |
- void TriggerCpuNormalUsage() { PostTaskAndWait(false, ScaleReason::kCpu); } |
+ void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); } |
- void TriggerQualityLow() { PostTaskAndWait(true, ScaleReason::kQuality); } |
+ void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); } |
- void TriggerQualityHigh() { PostTaskAndWait(false, ScaleReason::kQuality); } |
+ void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); } |
}; |
class VideoStreamFactory |
@@ -110,6 +111,52 @@ class VideoStreamFactory |
const size_t num_temporal_layers_; |
}; |
+class AdaptingFrameForwarder : public test::FrameForwarder { |
+ public: |
+ AdaptingFrameForwarder() : adaptation_enabled_(false) {} |
+ virtual ~AdaptingFrameForwarder() {} |
+ |
+ void set_adaptation_enabled(bool enabled) { |
+ rtc::CritScope cs(&crit_); |
+ adaptation_enabled_ = enabled; |
+ } |
+ |
+ bool adaption_enabled() { |
+ rtc::CritScope cs(&crit_); |
+ return adaptation_enabled_; |
+ } |
+ |
+ void IncomingCapturedFrame(const VideoFrame& video_frame) override { |
+ int cropped_width = 0; |
+ int cropped_height = 0; |
+ int out_width = 0; |
+ int out_height = 0; |
+ if (adaption_enabled() && |
+ adapter_.AdaptFrameResolution(video_frame.width(), video_frame.height(), |
+ video_frame.timestamp_us() * 1000, |
+ &cropped_width, &cropped_height, |
+ &out_width, &out_height)) { |
+ VideoFrame adapted_frame( |
+ new rtc::RefCountedObject<TestBuffer>(nullptr, out_width, out_height), |
+ 99, 99, kVideoRotation_0); |
+ adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms()); |
+ test::FrameForwarder::IncomingCapturedFrame(adapted_frame); |
+ } else { |
+ test::FrameForwarder::IncomingCapturedFrame(video_frame); |
+ } |
+ } |
+ |
+ void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, |
+ const rtc::VideoSinkWants& wants) override { |
+ rtc::CritScope cs(&crit_); |
+ adapter_.OnResolutionRequest(wants.max_pixel_count, |
+ wants.max_pixel_count_step_up); |
+ test::FrameForwarder::AddOrUpdateSink(sink, wants); |
+ } |
+ |
+ cricket::VideoAdapter adapter_; |
+ bool adaptation_enabled_ GUARDED_BY(crit_); |
+}; |
} // namespace |
class ViEEncoderTest : public ::testing::Test { |
@@ -258,11 +305,25 @@ class ViEEncoderTest : public ::testing::Test { |
EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
{ |
rtc::CritScope lock(&crit_); |
- timestamp = timestamp_; |
+ timestamp = last_timestamp_; |
} |
test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp); |
} |
+ void WaitForEncodedFrame(uint32_t expected_width, |
+ uint32_t expected_height) { |
+ uint32_t width = 0; |
+ uint32_t height = 0; |
+ EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); |
+ { |
+ rtc::CritScope lock(&crit_); |
+ width = last_width_; |
+ height = last_height_; |
+ } |
+ EXPECT_EQ(expected_height, height); |
+ EXPECT_EQ(expected_width, width); |
+ } |
+ |
void SetExpectNoFrames() { |
rtc::CritScope lock(&crit_); |
expect_frames_ = false; |
@@ -285,9 +346,11 @@ class ViEEncoderTest : public ::testing::Test { |
const RTPFragmentationHeader* fragmentation) override { |
rtc::CritScope lock(&crit_); |
EXPECT_TRUE(expect_frames_); |
- timestamp_ = encoded_image._timeStamp; |
+ last_timestamp_ = encoded_image._timeStamp; |
+ last_width_ = encoded_image._encodedWidth; |
+ last_height_ = encoded_image._encodedHeight; |
encoded_frame_event_.Set(); |
- return Result(Result::OK, timestamp_); |
+ return Result(Result::OK, last_timestamp_); |
} |
void OnEncoderConfigurationChanged(std::vector<VideoStream> streams, |
@@ -300,7 +363,9 @@ class ViEEncoderTest : public ::testing::Test { |
rtc::CriticalSection crit_; |
TestEncoder* test_encoder_; |
rtc::Event encoded_frame_event_; |
- uint32_t timestamp_ = 0; |
+ uint32_t last_timestamp_ = 0; |
+ uint32_t last_height_ = 0; |
+ uint32_t last_width_ = 0; |
bool expect_frames_ = true; |
int number_of_reconfigurations_ = 0; |
int min_transmit_bitrate_bps_ = 0; |
@@ -313,7 +378,7 @@ class ViEEncoderTest : public ::testing::Test { |
TestEncoder fake_encoder_; |
std::unique_ptr<SendStatisticsProxy> stats_proxy_; |
TestSink sink_; |
- test::FrameForwarder video_source_; |
+ AdaptingFrameForwarder video_source_; |
std::unique_ptr<ViEEncoderUnderTest> vie_encoder_; |
}; |
@@ -1029,4 +1094,32 @@ TEST_F(ViEEncoderTest, CallsBitrateObserver) { |
vie_encoder_->Stop(); |
} |
+// TODO(sprang): Extend this with fps throttling and any "balanced" extensions. |
+TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) { |
+ vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); |
+ |
+ const int kFrameWidth = 1280; |
+ const int kFrameHeight = 720; |
+ // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as |
+ // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan(). |
+ video_source_.set_adaptation_enabled(true); |
+ |
+ video_source_.IncomingCapturedFrame( |
+ CreateFrame(1, kFrameWidth, kFrameHeight)); |
+ sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
+ |
+ // Trigger CPU overuse, downscale by 3/4. |
+ vie_encoder_->TriggerCpuOveruse(); |
+ video_source_.IncomingCapturedFrame( |
+ CreateFrame(2, kFrameWidth, kFrameHeight)); |
+ sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4); |
+ |
+ // Trigger CPU normal use, return to original resoluton; |
+ vie_encoder_->TriggerCpuNormalUsage(); |
+ video_source_.IncomingCapturedFrame( |
+ CreateFrame(3, kFrameWidth, kFrameHeight)); |
+ sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight); |
+ |
+ vie_encoder_->Stop(); |
+} |
} // namespace webrtc |