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

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