OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/host/video_frame_pump.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "base/run_loop.h" | |
10 #include "base/single_thread_task_runner.h" | |
11 #include "remoting/base/auto_thread.h" | |
12 #include "remoting/base/auto_thread_task_runner.h" | |
13 #include "remoting/codec/video_encoder.h" | |
14 #include "remoting/codec/video_encoder_verbatim.h" | |
15 #include "remoting/host/desktop_capturer_proxy.h" | |
16 #include "remoting/host/fake_desktop_capturer.h" | |
17 #include "remoting/host/host_mock_objects.h" | |
18 #include "remoting/proto/control.pb.h" | |
19 #include "remoting/proto/video.pb.h" | |
20 #include "remoting/protocol/protocol_mock_objects.h" | |
21 #include "testing/gmock/include/gmock/gmock.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
24 #include "third_party/webrtc/modules/desktop_capture/screen_capturer_mock_object
s.h" | |
25 | |
26 using ::remoting::protocol::MockVideoStub; | |
27 | |
28 using ::testing::_; | |
29 using ::testing::AtLeast; | |
30 using ::testing::DoAll; | |
31 using ::testing::Expectation; | |
32 using ::testing::InvokeWithoutArgs; | |
33 using ::testing::Return; | |
34 | |
35 namespace remoting { | |
36 | |
37 namespace { | |
38 | |
39 ACTION(FinishSend) { | |
40 arg1.Run(); | |
41 } | |
42 | |
43 scoped_ptr<webrtc::DesktopFrame> CreateNullFrame( | |
44 webrtc::DesktopCapturer::Callback*) { | |
45 return nullptr; | |
46 } | |
47 | |
48 scoped_ptr<webrtc::DesktopFrame> CreateUnchangedFrame( | |
49 webrtc::DesktopCapturer::Callback*) { | |
50 const webrtc::DesktopSize kSize(800, 640); | |
51 // updated_region() is already empty by default in new BasicDesktopFrames. | |
52 return make_scoped_ptr(new webrtc::BasicDesktopFrame(kSize)); | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 static const int kWidth = 640; | |
58 static const int kHeight = 480; | |
59 | |
60 class ThreadCheckVideoEncoder : public VideoEncoderVerbatim { | |
61 public: | |
62 ThreadCheckVideoEncoder( | |
63 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | |
64 : task_runner_(task_runner) { | |
65 } | |
66 ~ThreadCheckVideoEncoder() override { | |
67 EXPECT_TRUE(task_runner_->BelongsToCurrentThread()); | |
68 } | |
69 | |
70 scoped_ptr<VideoPacket> Encode(const webrtc::DesktopFrame& frame) override { | |
71 return make_scoped_ptr(new VideoPacket()); | |
72 } | |
73 | |
74 private: | |
75 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
76 | |
77 DISALLOW_COPY_AND_ASSIGN(ThreadCheckVideoEncoder); | |
78 }; | |
79 | |
80 class ThreadCheckDesktopCapturer : public webrtc::DesktopCapturer { | |
81 public: | |
82 ThreadCheckDesktopCapturer( | |
83 scoped_refptr<base::SingleThreadTaskRunner> task_runner) | |
84 : task_runner_(task_runner), callback_(nullptr) {} | |
85 ~ThreadCheckDesktopCapturer() override { | |
86 EXPECT_TRUE(task_runner_->BelongsToCurrentThread()); | |
87 } | |
88 | |
89 void Start(Callback* callback) override { | |
90 EXPECT_TRUE(task_runner_->BelongsToCurrentThread()); | |
91 EXPECT_FALSE(callback_); | |
92 EXPECT_TRUE(callback); | |
93 | |
94 callback_ = callback; | |
95 } | |
96 | |
97 void Capture(const webrtc::DesktopRegion& rect) override { | |
98 EXPECT_TRUE(task_runner_->BelongsToCurrentThread()); | |
99 | |
100 scoped_ptr<webrtc::DesktopFrame> frame( | |
101 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); | |
102 frame->mutable_updated_region()->SetRect( | |
103 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10)); | |
104 callback_->OnCaptureCompleted(frame.release()); | |
105 } | |
106 | |
107 private: | |
108 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
109 webrtc::DesktopCapturer::Callback* callback_; | |
110 | |
111 DISALLOW_COPY_AND_ASSIGN(ThreadCheckDesktopCapturer); | |
112 }; | |
113 | |
114 class VideoFramePumpTest : public testing::Test { | |
115 public: | |
116 void SetUp() override; | |
117 void TearDown() override; | |
118 | |
119 void StartVideoFramePump( | |
120 scoped_ptr<webrtc::DesktopCapturer> capturer, | |
121 scoped_ptr<VideoEncoder> encoder); | |
122 | |
123 protected: | |
124 base::MessageLoop message_loop_; | |
125 base::RunLoop run_loop_; | |
126 scoped_refptr<AutoThreadTaskRunner> capture_task_runner_; | |
127 scoped_refptr<AutoThreadTaskRunner> encode_task_runner_; | |
128 scoped_refptr<AutoThreadTaskRunner> main_task_runner_; | |
129 scoped_ptr<VideoFramePump> pump_; | |
130 | |
131 MockVideoStub video_stub_; | |
132 }; | |
133 | |
134 void VideoFramePumpTest::SetUp() { | |
135 main_task_runner_ = new AutoThreadTaskRunner( | |
136 message_loop_.task_runner(), run_loop_.QuitClosure()); | |
137 capture_task_runner_ = AutoThread::Create("capture", main_task_runner_); | |
138 encode_task_runner_ = AutoThread::Create("encode", main_task_runner_); | |
139 } | |
140 | |
141 void VideoFramePumpTest::TearDown() { | |
142 pump_.reset(); | |
143 | |
144 // Release the task runners, so that the test can quit. | |
145 capture_task_runner_ = nullptr; | |
146 encode_task_runner_ = nullptr; | |
147 main_task_runner_ = nullptr; | |
148 | |
149 // Run the MessageLoop until everything has torn down. | |
150 run_loop_.Run(); | |
151 } | |
152 | |
153 // This test mocks capturer, encoder and network layer to simulate one capture | |
154 // cycle. | |
155 TEST_F(VideoFramePumpTest, StartAndStop) { | |
156 scoped_ptr<ThreadCheckDesktopCapturer> capturer( | |
157 new ThreadCheckDesktopCapturer(capture_task_runner_)); | |
158 scoped_ptr<ThreadCheckVideoEncoder> encoder( | |
159 new ThreadCheckVideoEncoder(encode_task_runner_)); | |
160 | |
161 base::RunLoop run_loop; | |
162 | |
163 // When the first ProcessVideoPacket is received we stop the VideoFramePump. | |
164 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) | |
165 .WillOnce(DoAll( | |
166 FinishSend(), | |
167 InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit))) | |
168 .RetiresOnSaturation(); | |
169 | |
170 // Start video frame capture. | |
171 pump_.reset(new VideoFramePump(encode_task_runner_, | |
172 make_scoped_ptr(new DesktopCapturerProxy( | |
173 capture_task_runner_, capturer.Pass())), | |
174 encoder.Pass(), &video_stub_)); | |
175 | |
176 // Run MessageLoop until the first frame is received. | |
177 run_loop.Run(); | |
178 } | |
179 | |
180 // Tests that the pump handles null frames returned by the capturer. | |
181 TEST_F(VideoFramePumpTest, NullFrame) { | |
182 scoped_ptr<FakeDesktopCapturer> capturer(new FakeDesktopCapturer); | |
183 scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder); | |
184 | |
185 base::RunLoop run_loop; | |
186 | |
187 // Set up the capturer to return null frames. | |
188 capturer->set_frame_generator(base::Bind(&CreateNullFrame)); | |
189 | |
190 // Expect that the VideoEncoder::Encode() method is never called. | |
191 EXPECT_CALL(*encoder, EncodePtr(_)).Times(0); | |
192 | |
193 // When the first ProcessVideoPacket is received we stop the VideoFramePump. | |
194 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) | |
195 .WillOnce(DoAll(FinishSend(), | |
196 InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit))) | |
197 .RetiresOnSaturation(); | |
198 | |
199 // Start video frame capture. | |
200 pump_.reset(new VideoFramePump(encode_task_runner_, | |
201 make_scoped_ptr(new DesktopCapturerProxy( | |
202 capture_task_runner_, capturer.Pass())), | |
203 encoder.Pass(), &video_stub_)); | |
204 | |
205 // Run MessageLoop until the first frame is received.. | |
206 run_loop.Run(); | |
207 } | |
208 | |
209 // Tests how the pump handles unchanged frames returned by the capturer. | |
210 TEST_F(VideoFramePumpTest, UnchangedFrame) { | |
211 scoped_ptr<FakeDesktopCapturer> capturer(new FakeDesktopCapturer); | |
212 scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder); | |
213 | |
214 base::RunLoop run_loop; | |
215 | |
216 // Set up the capturer to return unchanged frames. | |
217 capturer->set_frame_generator(base::Bind(&CreateUnchangedFrame)); | |
218 | |
219 // Expect that the VideoEncoder::Encode() method is called. | |
220 EXPECT_CALL(*encoder, EncodePtr(_)).WillRepeatedly(Return(nullptr)); | |
221 | |
222 // When the first ProcessVideoPacket is received we stop the VideoFramePump. | |
223 // TODO(wez): Verify that the generated packet has no content here. | |
224 EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)) | |
225 .WillOnce(DoAll(FinishSend(), | |
226 InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit))) | |
227 .RetiresOnSaturation(); | |
228 | |
229 // Start video frame capture. | |
230 pump_.reset(new VideoFramePump(encode_task_runner_, | |
231 make_scoped_ptr(new DesktopCapturerProxy( | |
232 capture_task_runner_, capturer.Pass())), | |
233 encoder.Pass(), &video_stub_)); | |
234 | |
235 // Run MessageLoop until the first frame is received.. | |
236 run_loop.Run(); | |
237 } | |
238 | |
239 } // namespace remoting | |
OLD | NEW |