| 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 |