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

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

Issue 2918143003: Set overuse detector max frame interval based on target frame rate. (Closed)
Patch Set: Addressed comments, fixed last adaptation fps, fixed unit tests Created 3 years, 6 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
« webrtc/video/vie_encoder.cc ('K') | « webrtc/video/vie_encoder.cc ('k') | no next file » | 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
(...skipping 30 matching lines...) Expand all
41 using DegredationPreference = VideoSendStream::DegradationPreference; 41 using DegredationPreference = VideoSendStream::DegradationPreference;
42 using ScaleReason = AdaptationObserverInterface::AdaptReason; 42 using ScaleReason = AdaptationObserverInterface::AdaptReason;
43 using ::testing::_; 43 using ::testing::_;
44 using ::testing::Return; 44 using ::testing::Return;
45 45
46 namespace { 46 namespace {
47 const size_t kMaxPayloadLength = 1440; 47 const size_t kMaxPayloadLength = 1440;
48 const int kTargetBitrateBps = 1000000; 48 const int kTargetBitrateBps = 1000000;
49 const int kLowTargetBitrateBps = kTargetBitrateBps / 10; 49 const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50 const int kMaxInitialFramedrop = 4; 50 const int kMaxInitialFramedrop = 4;
51 const int kDefaultFramerate = 30;
51 52
52 class TestBuffer : public webrtc::I420Buffer { 53 class TestBuffer : public webrtc::I420Buffer {
53 public: 54 public:
54 TestBuffer(rtc::Event* event, int width, int height) 55 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {} 56 : I420Buffer(width, height), event_(event) {}
56 57
57 private: 58 private:
58 friend class rtc::RefCountedObject<TestBuffer>; 59 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override { 60 ~TestBuffer() override {
60 if (event_) 61 if (event_)
61 event_->Set(); 62 event_->Set();
62 } 63 }
63 rtc::Event* const event_; 64 rtc::Event* const event_;
64 }; 65 };
65 66
67 class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
69 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
70 AdaptationObserverInterface* overuse_observer,
71 EncodedFrameObserver* encoder_timing_,
72 CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(options,
74 overuse_observer,
75 encoder_timing_,
76 metrics_observer),
77 last_target_framerate_fps_(-1) {}
78 virtual ~CpuOveruseDetectorProxy() {}
79
80 void OnTargetFramerateUpdated(int framerate_fps) override {
81 rtc::CritScope cs(&lock_);
82 last_target_framerate_fps_ = framerate_fps;
83 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
84 }
85
86 int GetLastTargetFramerate() {
87 rtc::CritScope cs(&lock_);
88 return last_target_framerate_fps_;
89 }
90
91 private:
92 rtc::CriticalSection lock_;
93 int last_target_framerate_fps_ GUARDED_BY(lock_);
94 };
95
66 class ViEEncoderUnderTest : public ViEEncoder { 96 class ViEEncoderUnderTest : public ViEEncoder {
67 public: 97 public:
68 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy, 98 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
69 const VideoSendStream::Config::EncoderSettings& settings) 99 const VideoSendStream::Config::EncoderSettings& settings)
70 : ViEEncoder(1 /* number_of_cores */, 100 : ViEEncoder(1 /* number_of_cores */,
71 stats_proxy, 101 stats_proxy,
72 settings, 102 settings,
73 nullptr /* pre_encode_callback */, 103 nullptr /* pre_encode_callback */,
74 nullptr /* encoder_timing */) {} 104 nullptr /* encoder_timing */,
105 std::unique_ptr<OveruseFrameDetector>(
106 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
107 GetCpuOveruseOptions(settings.full_overuse_time),
108 this,
109 nullptr,
110 stats_proxy))) {}
75 111
76 void PostTaskAndWait(bool down, AdaptReason reason) { 112 void PostTaskAndWait(bool down, AdaptReason reason) {
77 rtc::Event event(false, false); 113 rtc::Event event(false, false);
78 encoder_queue()->PostTask([this, &event, reason, down] { 114 encoder_queue()->PostTask([this, &event, reason, down] {
79 down ? AdaptDown(reason) : AdaptUp(reason); 115 down ? AdaptDown(reason) : AdaptUp(reason);
80 event.Set(); 116 event.Set();
81 }); 117 });
82 ASSERT_TRUE(event.Wait(5000)); 118 ASSERT_TRUE(event.Wait(5000));
83 } 119 }
84 120
85 // This is used as a synchronisation mechanism, to make sure that the 121 // This is used as a synchronisation mechanism, to make sure that the
86 // encoder queue is not blocked before we start sending it frames. 122 // encoder queue is not blocked before we start sending it frames.
87 void WaitUntilTaskQueueIsIdle() { 123 void WaitUntilTaskQueueIsIdle() {
88 rtc::Event event(false, false); 124 rtc::Event event(false, false);
89 encoder_queue()->PostTask([&event] { 125 encoder_queue()->PostTask([&event] {
90 event.Set(); 126 event.Set();
91 }); 127 });
92 ASSERT_TRUE(event.Wait(5000)); 128 ASSERT_TRUE(event.Wait(5000));
93 } 129 }
94 130
95 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); } 131 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
96 132
97 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); } 133 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
98 134
99 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); } 135 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
100 136
101 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); } 137 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
138
139 CpuOveruseDetectorProxy* overuse_detector_proxy_;
102 }; 140 };
103 141
104 class VideoStreamFactory 142 class VideoStreamFactory
105 : public VideoEncoderConfig::VideoStreamFactoryInterface { 143 : public VideoEncoderConfig::VideoStreamFactoryInterface {
106 public: 144 public:
107 explicit VideoStreamFactory(size_t num_temporal_layers) 145 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
108 : num_temporal_layers_(num_temporal_layers) { 146 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
109 EXPECT_GT(num_temporal_layers, 0u); 147 EXPECT_GT(num_temporal_layers, 0u);
148 EXPECT_GT(framerate, 0);
110 } 149 }
111 150
112 private: 151 private:
113 std::vector<VideoStream> CreateEncoderStreams( 152 std::vector<VideoStream> CreateEncoderStreams(
114 int width, 153 int width,
115 int height, 154 int height,
116 const VideoEncoderConfig& encoder_config) override { 155 const VideoEncoderConfig& encoder_config) override {
117 std::vector<VideoStream> streams = 156 std::vector<VideoStream> streams =
118 test::CreateVideoStreams(width, height, encoder_config); 157 test::CreateVideoStreams(width, height, encoder_config);
119 for (VideoStream& stream : streams) { 158 for (VideoStream& stream : streams) {
120 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1); 159 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
160 stream.max_framerate = framerate_;
121 } 161 }
122 return streams; 162 return streams;
123 } 163 }
164
124 const size_t num_temporal_layers_; 165 const size_t num_temporal_layers_;
166 const int framerate_;
125 }; 167 };
126 168
127 class AdaptingFrameForwarder : public test::FrameForwarder { 169 class AdaptingFrameForwarder : public test::FrameForwarder {
128 public: 170 public:
129 AdaptingFrameForwarder() : adaptation_enabled_(false) {} 171 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
130 ~AdaptingFrameForwarder() override {} 172 ~AdaptingFrameForwarder() override {}
131 173
132 void set_adaptation_enabled(bool enabled) { 174 void set_adaptation_enabled(bool enabled) {
133 rtc::CritScope cs(&crit_); 175 rtc::CritScope cs(&crit_);
134 adaptation_enabled_ = enabled; 176 adaptation_enabled_ = enabled;
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 void ResetEncoder(const std::string& payload_name, 299 void ResetEncoder(const std::string& payload_name,
258 size_t num_streams, 300 size_t num_streams,
259 size_t num_temporal_layers, 301 size_t num_temporal_layers,
260 bool nack_enabled) { 302 bool nack_enabled) {
261 video_send_config_.encoder_settings.payload_name = payload_name; 303 video_send_config_.encoder_settings.payload_name = payload_name;
262 304
263 VideoEncoderConfig video_encoder_config; 305 VideoEncoderConfig video_encoder_config;
264 video_encoder_config.number_of_streams = num_streams; 306 video_encoder_config.number_of_streams = num_streams;
265 video_encoder_config.max_bitrate_bps = kTargetBitrateBps; 307 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
266 video_encoder_config.video_stream_factory = 308 video_encoder_config.video_stream_factory =
267 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers); 309 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
310 kDefaultFramerate);
268 ConfigureEncoder(std::move(video_encoder_config), nack_enabled); 311 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
269 } 312 }
270 313
271 VideoFrame CreateFrame(int64_t ntp_time_ms, 314 VideoFrame CreateFrame(int64_t ntp_time_ms,
272 rtc::Event* destruction_event) const { 315 rtc::Event* destruction_event) const {
273 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>( 316 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
274 destruction_event, codec_width_, codec_height_), 317 destruction_event, codec_width_, codec_height_),
275 99, 99, kVideoRotation_0); 318 99, 99, kVideoRotation_0);
276 frame.set_ntp_time_ms(ntp_time_ms); 319 frame.set_ntp_time_ms(ntp_time_ms);
277 return frame; 320 return frame;
(...skipping 1532 matching lines...) Expand 10 before | Expand all | Expand 10 after
1810 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps); 1853 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1811 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate)) 1854 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1812 .Times(1); 1855 .Times(1);
1813 video_source_.IncomingCapturedFrame(CreateFrame( 1856 video_source_.IncomingCapturedFrame(CreateFrame(
1814 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_)); 1857 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1815 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs); 1858 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1816 1859
1817 vie_encoder_->Stop(); 1860 vie_encoder_->Stop();
1818 } 1861 }
1819 1862
1863 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
1864 const int kFrameWidth = 1280;
1865 const int kFrameHeight = 720;
1866 const int kFramerate = 24;
1867
1868 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1869 test::FrameForwarder source;
1870 vie_encoder_->SetSource(
1871 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1872
1873 // Insert a single frame, triggering initial configuration.
1874 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
1875 vie_encoder_->WaitUntilTaskQueueIsIdle();
1876
1877 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1878 kDefaultFramerate);
1879
1880 // Trigger reconfigure encoder (without resetting the entire instance).
1881 VideoEncoderConfig video_encoder_config;
1882 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
1883 video_encoder_config.number_of_streams = 1;
1884 video_encoder_config.video_stream_factory =
1885 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
1886 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1887 kMaxPayloadLength, false);
1888 vie_encoder_->WaitUntilTaskQueueIsIdle();
1889
1890 // Detector should be updated with fps limit from codec config.
1891 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1892 kFramerate);
1893
1894 // Trigger overuse, max framerate should be reduced.
1895 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1896 stats.input_frame_rate = kFramerate;
1897 stats_proxy_->SetMockStats(stats);
1898 vie_encoder_->TriggerCpuOveruse();
1899 vie_encoder_->WaitUntilTaskQueueIsIdle();
1900 int adapted_framerate =
1901 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
1902 EXPECT_LT(adapted_framerate, kFramerate);
1903
1904 // Trigger underuse, max framerate should go back to codec configured fps.
1905 // Set extra low fps, to make sure it's actually reset, not just incremented.
1906 stats = stats_proxy_->GetStats();
1907 stats.input_frame_rate = adapted_framerate / 2;
1908 stats_proxy_->SetMockStats(stats);
1909 vie_encoder_->TriggerCpuNormalUsage();
1910 vie_encoder_->WaitUntilTaskQueueIsIdle();
1911 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1912 kFramerate);
1913
1914 vie_encoder_->Stop();
1915 }
1916
1917 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
1918 const int kFrameWidth = 1280;
1919 const int kFrameHeight = 720;
1920 const int kLowFramerate = 15;
1921 const int kHighFramerate = 25;
1922
1923 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1924 test::FrameForwarder source;
1925 vie_encoder_->SetSource(
1926 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1927
1928 // Trigger initial configuration.
1929 VideoEncoderConfig video_encoder_config;
1930 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
1931 video_encoder_config.number_of_streams = 1;
1932 video_encoder_config.video_stream_factory =
1933 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
1934 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
1935 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1936 kMaxPayloadLength, false);
1937 vie_encoder_->WaitUntilTaskQueueIsIdle();
1938
1939 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1940 kLowFramerate);
1941
1942 // Trigger overuse, max framerate should be reduced.
1943 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1944 stats.input_frame_rate = kLowFramerate;
1945 stats_proxy_->SetMockStats(stats);
1946 vie_encoder_->TriggerCpuOveruse();
1947 vie_encoder_->WaitUntilTaskQueueIsIdle();
1948 int adapted_framerate =
1949 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
1950 EXPECT_LT(adapted_framerate, kLowFramerate);
1951
1952 // Reconfigure the encoder with a new (higher max framerate), max fps should
1953 // still respect the adaptation.
1954 video_encoder_config.video_stream_factory =
1955 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
1956 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
1957 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1958 kMaxPayloadLength, false);
1959 vie_encoder_->WaitUntilTaskQueueIsIdle();
1960
1961 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1962 adapted_framerate);
1963
1964 // Trigger underuse, max framerate should go back to codec configured fps.
1965 stats = stats_proxy_->GetStats();
1966 stats.input_frame_rate = adapted_framerate;
1967 stats_proxy_->SetMockStats(stats);
1968 vie_encoder_->TriggerCpuNormalUsage();
1969 vie_encoder_->WaitUntilTaskQueueIsIdle();
1970 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1971 kHighFramerate);
1972
1973 vie_encoder_->Stop();
1974 }
1975
1976 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnDegradationPreferenceChange) {
1977 const int kFrameWidth = 1280;
1978 const int kFrameHeight = 720;
1979 const int kFramerate = 24;
1980
1981 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1982 test::FrameForwarder source;
1983 vie_encoder_->SetSource(
1984 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1985
1986 // Trigger initial configuration.
1987 VideoEncoderConfig video_encoder_config;
1988 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
1989 video_encoder_config.number_of_streams = 1;
1990 video_encoder_config.video_stream_factory =
1991 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
1992 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
1993 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
1994 kMaxPayloadLength, false);
1995 vie_encoder_->WaitUntilTaskQueueIsIdle();
1996
1997 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
1998 kFramerate);
1999
2000 // Trigger overuse, max framerate should be reduced.
2001 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2002 stats.input_frame_rate = kFramerate;
2003 stats_proxy_->SetMockStats(stats);
2004 vie_encoder_->TriggerCpuOveruse();
2005 vie_encoder_->WaitUntilTaskQueueIsIdle();
2006 int adapted_framerate =
2007 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2008 EXPECT_LT(adapted_framerate, kFramerate);
2009
2010 // Change degradation preference to not enable framerate scaling. Target
2011 // framerate should be changed to codec defined limit.
2012 vie_encoder_->SetSource(
2013 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2014 vie_encoder_->WaitUntilTaskQueueIsIdle();
2015 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2016 kFramerate);
2017
2018 vie_encoder_->Stop();
2019 }
2020
1820 TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) { 2021 TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
1821 const int kTooLowBitrateForFrameSizeBps = 10000; 2022 const int kTooLowBitrateForFrameSizeBps = 10000;
1822 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0); 2023 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1823 const int kWidth = 640; 2024 const int kWidth = 640;
1824 const int kHeight = 360; 2025 const int kHeight = 360;
1825 2026
1826 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); 2027 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1827 2028
1828 // Expect to drop this frame, the wait should time out. 2029 // Expect to drop this frame, the wait should time out.
1829 sink_.ExpectDroppedFrame(); 2030 sink_.ExpectDroppedFrame();
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
2114 for (int i = 0; i < 10; ++i) { 2315 for (int i = 0; i < 10; ++i) {
2115 timestamp_ms += kMinFpsFrameInterval; 2316 timestamp_ms += kMinFpsFrameInterval;
2116 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000); 2317 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
2117 video_source_.IncomingCapturedFrame( 2318 video_source_.IncomingCapturedFrame(
2118 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight)); 2319 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2119 sink_.WaitForEncodedFrame(timestamp_ms); 2320 sink_.WaitForEncodedFrame(timestamp_ms);
2120 } 2321 }
2121 vie_encoder_->Stop(); 2322 vie_encoder_->Stop();
2122 } 2323 }
2123 } // namespace webrtc 2324 } // namespace webrtc
OLDNEW
« webrtc/video/vie_encoder.cc ('K') | « webrtc/video/vie_encoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698