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

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: Rebase 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
« no previous file with comments | « 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 1742 matching lines...) Expand 10 before | Expand all | Expand 10 after
2020 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps); 2063 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
2021 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate)) 2064 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2022 .Times(1); 2065 .Times(1);
2023 video_source_.IncomingCapturedFrame(CreateFrame( 2066 video_source_.IncomingCapturedFrame(CreateFrame(
2024 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_)); 2067 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
2025 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs); 2068 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
2026 2069
2027 vie_encoder_->Stop(); 2070 vie_encoder_->Stop();
2028 } 2071 }
2029 2072
2073 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2074 const int kFrameWidth = 1280;
2075 const int kFrameHeight = 720;
2076 const int kFramerate = 24;
2077
2078 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2079 test::FrameForwarder source;
2080 vie_encoder_->SetSource(
2081 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2082
2083 // Insert a single frame, triggering initial configuration.
2084 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2085 vie_encoder_->WaitUntilTaskQueueIsIdle();
2086
2087 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2088 kDefaultFramerate);
2089
2090 // Trigger reconfigure encoder (without resetting the entire instance).
2091 VideoEncoderConfig video_encoder_config;
2092 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2093 video_encoder_config.number_of_streams = 1;
2094 video_encoder_config.video_stream_factory =
2095 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2096 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2097 kMaxPayloadLength, false);
2098 vie_encoder_->WaitUntilTaskQueueIsIdle();
2099
2100 // Detector should be updated with fps limit from codec config.
2101 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2102 kFramerate);
2103
2104 // Trigger overuse, max framerate should be reduced.
2105 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2106 stats.input_frame_rate = kFramerate;
2107 stats_proxy_->SetMockStats(stats);
2108 vie_encoder_->TriggerCpuOveruse();
2109 vie_encoder_->WaitUntilTaskQueueIsIdle();
2110 int adapted_framerate =
2111 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2112 EXPECT_LT(adapted_framerate, kFramerate);
2113
2114 // Trigger underuse, max framerate should go back to codec configured fps.
2115 // Set extra low fps, to make sure it's actually reset, not just incremented.
2116 stats = stats_proxy_->GetStats();
2117 stats.input_frame_rate = adapted_framerate / 2;
2118 stats_proxy_->SetMockStats(stats);
2119 vie_encoder_->TriggerCpuNormalUsage();
2120 vie_encoder_->WaitUntilTaskQueueIsIdle();
2121 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2122 kFramerate);
2123
2124 vie_encoder_->Stop();
2125 }
2126
2127 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2128 const int kFrameWidth = 1280;
2129 const int kFrameHeight = 720;
2130 const int kLowFramerate = 15;
2131 const int kHighFramerate = 25;
2132
2133 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2134 test::FrameForwarder source;
2135 vie_encoder_->SetSource(
2136 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2137
2138 // Trigger initial configuration.
2139 VideoEncoderConfig video_encoder_config;
2140 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2141 video_encoder_config.number_of_streams = 1;
2142 video_encoder_config.video_stream_factory =
2143 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2144 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2145 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2146 kMaxPayloadLength, false);
2147 vie_encoder_->WaitUntilTaskQueueIsIdle();
2148
2149 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2150 kLowFramerate);
2151
2152 // Trigger overuse, max framerate should be reduced.
2153 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2154 stats.input_frame_rate = kLowFramerate;
2155 stats_proxy_->SetMockStats(stats);
2156 vie_encoder_->TriggerCpuOveruse();
2157 vie_encoder_->WaitUntilTaskQueueIsIdle();
2158 int adapted_framerate =
2159 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2160 EXPECT_LT(adapted_framerate, kLowFramerate);
2161
2162 // Reconfigure the encoder with a new (higher max framerate), max fps should
2163 // still respect the adaptation.
2164 video_encoder_config.video_stream_factory =
2165 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2166 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2167 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2168 kMaxPayloadLength, false);
2169 vie_encoder_->WaitUntilTaskQueueIsIdle();
2170
2171 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2172 adapted_framerate);
2173
2174 // Trigger underuse, max framerate should go back to codec configured fps.
2175 stats = stats_proxy_->GetStats();
2176 stats.input_frame_rate = adapted_framerate;
2177 stats_proxy_->SetMockStats(stats);
2178 vie_encoder_->TriggerCpuNormalUsage();
2179 vie_encoder_->WaitUntilTaskQueueIsIdle();
2180 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2181 kHighFramerate);
2182
2183 vie_encoder_->Stop();
2184 }
2185
2186 TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnDegradationPreferenceChange) {
2187 const int kFrameWidth = 1280;
2188 const int kFrameHeight = 720;
2189 const int kFramerate = 24;
2190
2191 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2192 test::FrameForwarder source;
2193 vie_encoder_->SetSource(
2194 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2195
2196 // Trigger initial configuration.
2197 VideoEncoderConfig video_encoder_config;
2198 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2199 video_encoder_config.number_of_streams = 1;
2200 video_encoder_config.video_stream_factory =
2201 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2202 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2203 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2204 kMaxPayloadLength, false);
2205 vie_encoder_->WaitUntilTaskQueueIsIdle();
2206
2207 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2208 kFramerate);
2209
2210 // Trigger overuse, max framerate should be reduced.
2211 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2212 stats.input_frame_rate = kFramerate;
2213 stats_proxy_->SetMockStats(stats);
2214 vie_encoder_->TriggerCpuOveruse();
2215 vie_encoder_->WaitUntilTaskQueueIsIdle();
2216 int adapted_framerate =
2217 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2218 EXPECT_LT(adapted_framerate, kFramerate);
2219
2220 // Change degradation preference to not enable framerate scaling. Target
2221 // framerate should be changed to codec defined limit.
2222 vie_encoder_->SetSource(
2223 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2224 vie_encoder_->WaitUntilTaskQueueIsIdle();
2225 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2226 kFramerate);
2227
2228 vie_encoder_->Stop();
2229 }
2230
2030 TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) { 2231 TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
2031 const int kTooLowBitrateForFrameSizeBps = 10000; 2232 const int kTooLowBitrateForFrameSizeBps = 10000;
2032 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0); 2233 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2033 const int kWidth = 640; 2234 const int kWidth = 640;
2034 const int kHeight = 360; 2235 const int kHeight = 360;
2035 2236
2036 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); 2237 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2037 2238
2038 // Expect to drop this frame, the wait should time out. 2239 // Expect to drop this frame, the wait should time out.
2039 sink_.ExpectDroppedFrame(); 2240 sink_.ExpectDroppedFrame();
(...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after
2737 // Trigger adapt up, expect no change. 2938 // Trigger adapt up, expect no change.
2738 vie_encoder_->TriggerQualityHigh(); 2939 vie_encoder_->TriggerQualityHigh();
2739 VerifyNoLimitation(source.sink_wants()); 2940 VerifyNoLimitation(source.sink_wants());
2740 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes); 2941 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2741 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes); 2942 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2742 2943
2743 vie_encoder_->Stop(); 2944 vie_encoder_->Stop();
2744 } 2945 }
2745 2946
2746 } // namespace webrtc 2947 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/video/vie_encoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698