diff options
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/client_session_unittest.cc | 2 | ||||
-rw-r--r-- | remoting/host/host_mock_objects.cc | 13 | ||||
-rw-r--r-- | remoting/host/host_mock_objects.h | 34 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer.h | 47 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_fake.cc | 8 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_fake.h | 8 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_linux.cc | 32 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_mac.mm | 32 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_mac_unittest.cc | 84 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_unittest.cc | 26 | ||||
-rw-r--r-- | remoting/host/video_frame_capturer_win.cc | 42 | ||||
-rw-r--r-- | remoting/host/video_scheduler.cc | 70 | ||||
-rw-r--r-- | remoting/host/video_scheduler.h | 17 | ||||
-rw-r--r-- | remoting/host/video_scheduler_unittest.cc | 34 |
14 files changed, 211 insertions, 238 deletions
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 0a7cf48..1d32056 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -101,7 +101,7 @@ class ClientSessionTest : public testing::Test { EXPECT_CALL(*capturer, Start(_)); EXPECT_CALL(*capturer, Stop()); EXPECT_CALL(*capturer, InvalidateRegion(_)).Times(AnyNumber()); - EXPECT_CALL(*capturer, CaptureInvalidRegion(_)).Times(AnyNumber()); + EXPECT_CALL(*capturer, CaptureInvalidRegion()).Times(AnyNumber()); EXPECT_CALL(*capturer, size_most_recent()) .WillRepeatedly(ReturnRef(screen_size_)); diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index 3f5cfee..952699b 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -17,13 +17,16 @@ MockVideoFrameCapturer::MockVideoFrameCapturer() {} MockVideoFrameCapturer::~MockVideoFrameCapturer() {} -MockCaptureCompletedCallback::MockCaptureCompletedCallback() {} +MockVideoFrameCapturerDelegate::MockVideoFrameCapturerDelegate() { +} -MockCaptureCompletedCallback::~MockCaptureCompletedCallback() {} +MockVideoFrameCapturerDelegate::~MockVideoFrameCapturerDelegate() { +} -void MockCaptureCompletedCallback::CaptureCompleted( - scoped_refptr<CaptureData> capture_data) { - CaptureCompletedPtr(capture_data.get()); +void MockVideoFrameCapturerDelegate::OnCursorShapeChanged( + scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { + // Notify the mock method. + OnCursorShapeChangedPtr(cursor_shape.get()); } MockDesktopEnvironmentFactory::MockDesktopEnvironmentFactory() diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index d5ebcdb..4eaee55 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h @@ -6,6 +6,7 @@ #define REMOTING_HOST_HOST_MOCK_OBJECTS_H_ #include "net/base/ip_endpoint.h" +#include "remoting/base/capture_data.h" #include "remoting/host/video_frame_capturer.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/client_session.h" @@ -17,39 +18,42 @@ #include "remoting/host/host_status_observer.h" #include "remoting/host/local_input_monitor.h" #include "remoting/host/user_authenticator.h" +#include "remoting/proto/control.pb.h" #include "testing/gmock/include/gmock/gmock.h" namespace remoting { -class MockCaptureCompletedCallback { - public: - MockCaptureCompletedCallback(); - virtual ~MockCaptureCompletedCallback(); - - MOCK_METHOD1(CaptureCompletedPtr, void(CaptureData* capture_data)); - void CaptureCompleted(scoped_refptr<CaptureData> capture_data); - - private: - DISALLOW_COPY_AND_ASSIGN(MockCaptureCompletedCallback); -}; - class MockVideoFrameCapturer : public VideoFrameCapturer { public: MockVideoFrameCapturer(); virtual ~MockVideoFrameCapturer(); - MOCK_METHOD1(Start, void(const CursorShapeChangedCallback& callback)); + MOCK_METHOD1(Start, void(Delegate* delegate)); MOCK_METHOD0(Stop, void()); MOCK_CONST_METHOD0(pixel_format, media::VideoFrame::Format()); MOCK_METHOD1(InvalidateRegion, void(const SkRegion& invalid_region)); - MOCK_METHOD1(CaptureInvalidRegion, - void(const CaptureCompletedCallback& callback)); + MOCK_METHOD0(CaptureInvalidRegion, void()); MOCK_CONST_METHOD0(size_most_recent, const SkISize&()); private: DISALLOW_COPY_AND_ASSIGN(MockVideoFrameCapturer); }; +class MockVideoFrameCapturerDelegate : public VideoFrameCapturer::Delegate { + public: + MockVideoFrameCapturerDelegate(); + virtual ~MockVideoFrameCapturerDelegate(); + + virtual void OnCursorShapeChanged( + scoped_ptr<protocol::CursorShapeInfo> cursor_shape) OVERRIDE; + + MOCK_METHOD1(OnCaptureCompleted, void(scoped_refptr<CaptureData>)); + MOCK_METHOD1(OnCursorShapeChangedPtr, void(protocol::CursorShapeInfo*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockVideoFrameCapturerDelegate); +}; + class MockDisconnectWindow : public DisconnectWindow { public: MockDisconnectWindow(); diff --git a/remoting/host/video_frame_capturer.h b/remoting/host/video_frame_capturer.h index e2db2b9..7cc863e 100644 --- a/remoting/host/video_frame_capturer.h +++ b/remoting/host/video_frame_capturer.h @@ -50,13 +50,21 @@ class CaptureData; // Since data can be read while another capture action is happening. class VideoFrameCapturer { public: - // CaptureCompletedCallback is called when the capturer has completed. - typedef base::Callback<void(scoped_refptr<CaptureData>)> - CaptureCompletedCallback; - - // CursorShapeChangedCallback is called when the cursor shape has changed. - typedef base::Callback<void(scoped_ptr<protocol::CursorShapeInfo>)> - CursorShapeChangedCallback; + // Provides callbacks used by the capturer to pass captured video frames and + // mouse cursor shapes to the processing pipeline. + class Delegate { + public: + virtual ~Delegate() {} + + // Called when the capturer has completed. |capture_data| describes + // a captured frame. + virtual void OnCaptureCompleted( + scoped_refptr<CaptureData> capture_data) = 0; + + // Called when the cursor shape has changed. + virtual void OnCursorShapeChanged( + scoped_ptr<protocol::CursorShapeInfo> cursor_shape) = 0; + }; virtual ~VideoFrameCapturer() {} @@ -78,30 +86,27 @@ class VideoFrameCapturer { static void EnableXDamage(bool enable); #endif // defined(OS_LINUX) - // Called at the beginning of a capturing session. - virtual void Start( - const CursorShapeChangedCallback& callback) = 0; + // Called at the beginning of a capturing session. |delegate| must remain + // valid until Stop() is called. + virtual void Start(Delegate* delegate) = 0; // Called at the end of a capturing session. virtual void Stop() = 0; - // Return the pixel format of the screen. + // Returns the pixel format of the screen. virtual media::VideoFrame::Format pixel_format() const = 0; - // Invalidate the specified region. + // Invalidates the specified region. virtual void InvalidateRegion(const SkRegion& invalid_region) = 0; - // Capture the screen data associated with each of the accumulated - // dirty region. - // When the capture is complete, |callback| is called even if the dirty region - // is empty. + // Captures the screen data associated with each of the accumulated + // dirty region. When the capture is complete, the delegate is notified even + // if the dirty region is empty. // // It is OK to call this method while another thread is reading - // data of the previous capture. - // There can be at most one concurrent read going on when this - // method is called. - virtual void CaptureInvalidRegion( - const CaptureCompletedCallback& callback) = 0; + // data of the previous capture. There can be at most one concurrent read + // going on when this method is called. + virtual void CaptureInvalidRegion() = 0; // Get the size of the most recently captured screen. virtual const SkISize& size_most_recent() const = 0; diff --git a/remoting/host/video_frame_capturer_fake.cc b/remoting/host/video_frame_capturer_fake.cc index aff8f3e..6d34fa2 100644 --- a/remoting/host/video_frame_capturer_fake.cc +++ b/remoting/host/video_frame_capturer_fake.cc @@ -39,7 +39,8 @@ VideoFrameCapturerFake::VideoFrameCapturerFake() VideoFrameCapturerFake::~VideoFrameCapturerFake() { } -void VideoFrameCapturerFake::Start(const CursorShapeChangedCallback& callback) { +void VideoFrameCapturerFake::Start(Delegate* delegate) { + delegate_ = delegate; } void VideoFrameCapturerFake::Stop() { @@ -53,8 +54,7 @@ void VideoFrameCapturerFake::InvalidateRegion(const SkRegion& invalid_region) { helper_.InvalidateRegion(invalid_region); } -void VideoFrameCapturerFake::CaptureInvalidRegion( - const CaptureCompletedCallback& callback) { +void VideoFrameCapturerFake::CaptureInvalidRegion() { GenerateImage(); helper_.InvalidateScreen(size_); @@ -73,7 +73,7 @@ void VideoFrameCapturerFake::CaptureInvalidRegion( helper_.set_size_most_recent(capture_data->size()); - callback.Run(capture_data); + delegate_->OnCaptureCompleted(capture_data); } const SkISize& VideoFrameCapturerFake::size_most_recent() const { diff --git a/remoting/host/video_frame_capturer_fake.h b/remoting/host/video_frame_capturer_fake.h index ac4b19a..5cb7d53 100644 --- a/remoting/host/video_frame_capturer_fake.h +++ b/remoting/host/video_frame_capturer_fake.h @@ -21,13 +21,11 @@ class VideoFrameCapturerFake : public VideoFrameCapturer { virtual ~VideoFrameCapturerFake(); // Overridden from VideoFrameCapturer: - virtual void Start( - const CursorShapeChangedCallback& callback) OVERRIDE; + virtual void Start(Delegate* delegate) OVERRIDE; virtual void Stop() OVERRIDE; virtual media::VideoFrame::Format pixel_format() const OVERRIDE; virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; - virtual void CaptureInvalidRegion( - const CaptureCompletedCallback& callback) OVERRIDE; + virtual void CaptureInvalidRegion() OVERRIDE; virtual const SkISize& size_most_recent() const OVERRIDE; private: @@ -37,6 +35,8 @@ class VideoFrameCapturerFake : public VideoFrameCapturer { // Called when the screen configuration is changed. void ScreenConfigurationChanged(); + Delegate* delegate_; + SkISize size_; int bytes_per_row_; int box_pos_x_; diff --git a/remoting/host/video_frame_capturer_linux.cc b/remoting/host/video_frame_capturer_linux.cc index c472f49..522eac7 100644 --- a/remoting/host/video_frame_capturer_linux.cc +++ b/remoting/host/video_frame_capturer_linux.cc @@ -83,12 +83,11 @@ class VideoFrameCapturerLinux : public VideoFrameCapturer { bool Init(); // TODO(ajwong): Do we really want this to be synchronous? // Capturer interface. - virtual void Start(const CursorShapeChangedCallback& callback) OVERRIDE; + virtual void Start(Delegate* delegate) OVERRIDE; virtual void Stop() OVERRIDE; virtual media::VideoFrame::Format pixel_format() const OVERRIDE; virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; - virtual void CaptureInvalidRegion( - const CaptureCompletedCallback& callback) OVERRIDE; + virtual void CaptureInvalidRegion() OVERRIDE; virtual const SkISize& size_most_recent() const OVERRIDE; private: @@ -110,8 +109,7 @@ class VideoFrameCapturerLinux : public VideoFrameCapturer { // previous capture. CaptureData* CaptureFrame(); - // Capture the cursor image and call the CursorShapeChangedCallback if it - // has been set (using SetCursorShapeChangedCallback). + // Capture the cursor image and notify the delegate if it was captured. void CaptureCursor(); // Called when the screen configuration is changed. @@ -135,6 +133,8 @@ class VideoFrameCapturerLinux : public VideoFrameCapturer { void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); + Delegate* delegate_; + // X11 graphics context. Display* display_; GC gc_; @@ -159,9 +159,6 @@ class VideoFrameCapturerLinux : public VideoFrameCapturer { // recently captured screen. VideoFrameCapturerHelper helper_; - // Callback notified whenever the cursor shape is changed. - CursorShapeChangedCallback cursor_shape_changed_callback_; - // Capture state. static const int kNumBuffers = 2; VideoFrameBuffer buffers_[kNumBuffers]; @@ -184,7 +181,8 @@ class VideoFrameCapturerLinux : public VideoFrameCapturer { }; VideoFrameCapturerLinux::VideoFrameCapturerLinux() - : display_(NULL), + : delegate_(NULL), + display_(NULL), gc_(NULL), root_window_(BadValue), has_xfixes_(false), @@ -293,9 +291,10 @@ void VideoFrameCapturerLinux::InitXDamage() { LOG(INFO) << "Using XDamage extension."; } -void VideoFrameCapturerLinux::Start( - const CursorShapeChangedCallback& callback) { - cursor_shape_changed_callback_ = callback; +void VideoFrameCapturerLinux::Start(Delegate* delegate) { + DCHECK(delegate_ == NULL); + + delegate_ = delegate; } void VideoFrameCapturerLinux::Stop() { @@ -309,8 +308,7 @@ void VideoFrameCapturerLinux::InvalidateRegion(const SkRegion& invalid_region) { helper_.InvalidateRegion(invalid_region); } -void VideoFrameCapturerLinux::CaptureInvalidRegion( - const CaptureCompletedCallback& callback) { +void VideoFrameCapturerLinux::CaptureInvalidRegion() { // Process XEvents for XDamage and cursor shape tracking. ProcessPendingXEvents(); @@ -337,7 +335,7 @@ void VideoFrameCapturerLinux::CaptureInvalidRegion( last_buffer_ = current_buffer_; current_buffer_ = (current_buffer_ + 1) % kNumBuffers; - callback.Run(capture_data); + delegate_->OnCaptureCompleted(capture_data); } void VideoFrameCapturerLinux::ProcessPendingXEvents() { @@ -368,8 +366,6 @@ void VideoFrameCapturerLinux::ProcessPendingXEvents() { void VideoFrameCapturerLinux::CaptureCursor() { DCHECK(has_xfixes_); - if (cursor_shape_changed_callback_.is_null()) - return; XFixesCursorImage* img = XFixesGetCursorImage(display_); if (!img) { @@ -400,7 +396,7 @@ void VideoFrameCapturerLinux::CaptureCursor() { } XFree(img); - cursor_shape_changed_callback_.Run(cursor_proto.Pass()); + delegate_->OnCursorShapeChanged(cursor_proto.Pass()); } CaptureData* VideoFrameCapturerLinux::CaptureFrame() { diff --git a/remoting/host/video_frame_capturer_mac.mm b/remoting/host/video_frame_capturer_mac.mm index ca85c0d..456b01f 100644 --- a/remoting/host/video_frame_capturer_mac.mm +++ b/remoting/host/video_frame_capturer_mac.mm @@ -113,12 +113,11 @@ class VideoFrameCapturerMac : public VideoFrameCapturer { bool Init(); // Overridden from VideoFrameCapturer: - virtual void Start(const CursorShapeChangedCallback& callback) OVERRIDE; + virtual void Start(Delegate* delegate) OVERRIDE; virtual void Stop() OVERRIDE; virtual media::VideoFrame::Format pixel_format() const OVERRIDE; virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; - virtual void CaptureInvalidRegion( - const CaptureCompletedCallback& callback) OVERRIDE; + virtual void CaptureInvalidRegion() OVERRIDE; virtual const SkISize& size_most_recent() const OVERRIDE; private: @@ -128,8 +127,6 @@ class VideoFrameCapturerMac : public VideoFrameCapturer { void GlBlitSlow(const VideoFrameBuffer& buffer); void CgBlitPreLion(const VideoFrameBuffer& buffer, const SkRegion& region); void CgBlitPostLion(const VideoFrameBuffer& buffer, const SkRegion& region); - void CaptureRegion(const SkRegion& region, - const CaptureCompletedCallback& callback); // Called when the screen configuration is changed. void ScreenConfigurationChanged(); @@ -153,6 +150,8 @@ class VideoFrameCapturerMac : public VideoFrameCapturer { void ReleaseBuffers(); + Delegate* delegate_; + CGLContextObj cgl_context_; static const int kNumBuffers = 2; ScopedPixelBufferObject pixel_buffer_object_; @@ -166,9 +165,6 @@ class VideoFrameCapturerMac : public VideoFrameCapturer { // recently captured screen. VideoFrameCapturerHelper helper_; - // Callback notified whenever the cursor shape is changed. - CursorShapeChangedCallback cursor_shape_changed_callback_; - // Image of the last cursor that we sent to the client. base::mac::ScopedCFTypeRef<CGImageRef> current_cursor_; @@ -207,7 +203,8 @@ class VideoFrameCapturerMac : public VideoFrameCapturer { }; VideoFrameCapturerMac::VideoFrameCapturerMac() - : cgl_context_(NULL), + : delegate_(NULL), + cgl_context_(NULL), current_buffer_(0), last_buffer_(NULL), pixel_format_(media::VideoFrame::RGB32), @@ -273,8 +270,10 @@ void VideoFrameCapturerMac::ReleaseBuffers() { } } -void VideoFrameCapturerMac::Start(const CursorShapeChangedCallback& callback) { - cursor_shape_changed_callback_ = callback; +void VideoFrameCapturerMac::Start(Delegate* delegate) { + DCHECK(delegate_ == NULL); + + delegate_ = delegate; // Create power management assertions to wake the display and prevent it from // going to sleep on user idle. @@ -311,8 +310,7 @@ void VideoFrameCapturerMac::InvalidateRegion(const SkRegion& invalid_region) { helper_.InvalidateRegion(invalid_region); } -void VideoFrameCapturerMac::CaptureInvalidRegion( - const CaptureCompletedCallback& callback) { +void VideoFrameCapturerMac::CaptureInvalidRegion() { // Only allow captures when the display configuration is not occurring. scoped_refptr<CaptureData> data; @@ -362,14 +360,10 @@ void VideoFrameCapturerMac::CaptureInvalidRegion( CaptureCursor(); - callback.Run(data); + delegate_->OnCaptureCompleted(data); } void VideoFrameCapturerMac::CaptureCursor() { - if (cursor_shape_changed_callback_.is_null()) { - return; - } - NSCursor* cursor = [NSCursor currentSystemCursor]; if (cursor == nil) { return; @@ -445,7 +439,7 @@ void VideoFrameCapturerMac::CaptureCursor() { cursor_proto->set_height(size.height); cursor_proto->set_hotspot_x(hotspot.x); cursor_proto->set_hotspot_y(hotspot.y); - cursor_shape_changed_callback_.Run(cursor_proto.Pass()); + delegate_->OnCursorShapeChanged(cursor_proto.Pass()); // Record the last cursor image that we sent. current_cursor_.reset(CGImageCreateCopy(image)); diff --git a/remoting/host/video_frame_capturer_mac_unittest.cc b/remoting/host/video_frame_capturer_mac_unittest.cc index 0bd3e11..ced13dc 100644 --- a/remoting/host/video_frame_capturer_mac_unittest.cc +++ b/remoting/host/video_frame_capturer_mac_unittest.cc @@ -12,9 +12,13 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" #include "remoting/base/capture_data.h" +#include "remoting/host/host_mock_objects.h" #include "remoting/proto/control.pb.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::_; +using ::testing::AnyNumber; + namespace remoting { // Verify that the OS is at least Snow Leopard (10.6). @@ -27,6 +31,14 @@ bool CheckSnowLeopard() { } class VideoFrameCapturerMacTest : public testing::Test { + public: + // Verifies that the whole screen is initially dirty. + void CaptureDoneCallback1(scoped_refptr<CaptureData> capture_data); + + // Verifies that a rectangle explicitly marked as dirty is propagated + // correctly. + void CaptureDoneCallback2(scoped_refptr<CaptureData> capture_data); + protected: virtual void SetUp() OVERRIDE { capturer_.reset(VideoFrameCapturer::Create()); @@ -38,21 +50,11 @@ class VideoFrameCapturerMacTest : public testing::Test { } scoped_ptr<VideoFrameCapturer> capturer_; + MockVideoFrameCapturerDelegate delegate_; SkRegion region_; }; -// CapturerCallback1 verifies that the whole screen is initially dirty. -class VideoFrameCapturerCallback1 { - public: - VideoFrameCapturerCallback1() {} - - void CaptureDoneCallback(scoped_refptr<CaptureData> capture_data); - - private: - DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerCallback1); -}; - -void VideoFrameCapturerCallback1::CaptureDoneCallback( +void VideoFrameCapturerMacTest::CaptureDoneCallback1( scoped_refptr<CaptureData> capture_data) { CGDirectDisplayID mainDevice = CGMainDisplayID(); int width = CGDisplayPixelsWide(mainDevice); @@ -61,29 +63,13 @@ void VideoFrameCapturerCallback1::CaptureDoneCallback( EXPECT_EQ(initial_region, capture_data->dirty_region()); } -// VideoFrameCapturerCallback2 verifies that a rectangle explicitly marked as -// dirty is propagated correctly. -class VideoFrameCapturerCallback2 { - public: - explicit VideoFrameCapturerCallback2(const SkRegion& expected_dirty_region) - : expected_dirty_region_(expected_dirty_region) {} - - void CaptureDoneCallback(scoped_refptr<CaptureData> capture_data); - - protected: - SkRegion expected_dirty_region_; - - private: - DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerCallback2); -}; - -void VideoFrameCapturerCallback2::CaptureDoneCallback( +void VideoFrameCapturerMacTest::CaptureDoneCallback2( scoped_refptr<CaptureData> capture_data) { CGDirectDisplayID mainDevice = CGMainDisplayID(); int width = CGDisplayPixelsWide(mainDevice); int height = CGDisplayPixelsHigh(mainDevice); - EXPECT_EQ(expected_dirty_region_, capture_data->dirty_region()); + EXPECT_EQ(region_, capture_data->dirty_region()); EXPECT_EQ(width, capture_data->size().width()); EXPECT_EQ(height, capture_data->size().height()); const DataPlanes &planes = capture_data->data_planes(); @@ -98,42 +84,28 @@ void VideoFrameCapturerCallback2::CaptureDoneCallback( EXPECT_EQ(0, planes.strides[2]); } -class CursorCallback { - public: - CursorCallback() {} - - void CursorShapeChangedCallback( - scoped_ptr<protocol::CursorShapeInfo> cursor_data); - - private: - DISALLOW_COPY_AND_ASSIGN(CursorCallback); -}; - -void CursorCallback::CursorShapeChangedCallback( - scoped_ptr<protocol::CursorShapeInfo> cursor_data) { -} - TEST_F(VideoFrameCapturerMacTest, Capture) { if (!CheckSnowLeopard()) { return; } + EXPECT_CALL(delegate_, OnCaptureCompleted(_)) + .Times(2) + .WillOnce(Invoke(this, &VideoFrameCapturerMacTest::CaptureDoneCallback1)) + .WillOnce(Invoke(this, &VideoFrameCapturerMacTest::CaptureDoneCallback2)); + EXPECT_CALL(delegate_, OnCursorShapeChangedPtr(_)) + .Times(AnyNumber()); + SCOPED_TRACE(""); - CursorCallback cursor_callback; - capturer_->Start(base::Bind(&CursorCallback::CursorShapeChangedCallback, - base::Unretained(&cursor_callback))); + capturer_->Start(&delegate_); + // Check that we get an initial full-screen updated. - VideoFrameCapturerCallback1 callback1; - capturer_->CaptureInvalidRegion(base::Bind( - &VideoFrameCapturerCallback1::CaptureDoneCallback, - base::Unretained(&callback1))); + capturer_->CaptureInvalidRegion(); + // Check that subsequent dirty rects are propagated correctly. AddDirtyRect(); - VideoFrameCapturerCallback2 callback2(region_); capturer_->InvalidateRegion(region_); - capturer_->CaptureInvalidRegion(base::Bind( - &VideoFrameCapturerCallback2::CaptureDoneCallback, - base::Unretained(&callback2))); + capturer_->CaptureInvalidRegion(); capturer_->Stop(); } diff --git a/remoting/host/video_frame_capturer_unittest.cc b/remoting/host/video_frame_capturer_unittest.cc index 4ad0a1b..0b10161 100644 --- a/remoting/host/video_frame_capturer_unittest.cc +++ b/remoting/host/video_frame_capturer_unittest.cc @@ -14,14 +14,10 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -namespace remoting { - -namespace { +using ::testing::_; +using ::testing::AnyNumber; -void IgnoreCursorShapeChanged(scoped_ptr<protocol::CursorShapeInfo> info) { -} - -} // namespace +namespace remoting { MATCHER(DirtyRegionIsNonEmptyRect, "") { const SkRegion& dirty_region = arg->dirty_region(); @@ -39,23 +35,23 @@ class VideoFrameCapturerTest : public testing::Test { } scoped_ptr<VideoFrameCapturer> capturer_; - MockCaptureCompletedCallback capture_completed_callback_; + MockVideoFrameCapturerDelegate delegate_; }; TEST_F(VideoFrameCapturerTest, StartCapturer) { - capturer_->Start(base::Bind(&IgnoreCursorShapeChanged)); + capturer_->Start(&delegate_); capturer_->Stop(); } TEST_F(VideoFrameCapturerTest, Capture) { // Assume that Start() treats the screen as invalid initially. - EXPECT_CALL(capture_completed_callback_, - CaptureCompletedPtr(DirtyRegionIsNonEmptyRect())); + EXPECT_CALL(delegate_, + OnCaptureCompleted(DirtyRegionIsNonEmptyRect())); + EXPECT_CALL(delegate_, OnCursorShapeChangedPtr(_)) + .Times(AnyNumber()); - capturer_->Start(base::Bind(&IgnoreCursorShapeChanged)); - capturer_->CaptureInvalidRegion(base::Bind( - &MockCaptureCompletedCallback::CaptureCompleted, - base::Unretained(&capture_completed_callback_))); + capturer_->Start(&delegate_); + capturer_->CaptureInvalidRegion(); capturer_->Stop(); } diff --git a/remoting/host/video_frame_capturer_win.cc b/remoting/host/video_frame_capturer_win.cc index 3f40592..8d33620 100644 --- a/remoting/host/video_frame_capturer_win.cc +++ b/remoting/host/video_frame_capturer_win.cc @@ -48,12 +48,11 @@ class VideoFrameCapturerWin : public VideoFrameCapturer { virtual ~VideoFrameCapturerWin(); // Overridden from VideoFrameCapturer: - virtual void Start(const CursorShapeChangedCallback& callback) OVERRIDE; + virtual void Start(Delegate* delegate) OVERRIDE; virtual void Stop() OVERRIDE; virtual media::VideoFrame::Format pixel_format() const OVERRIDE; virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; - virtual void CaptureInvalidRegion( - const CaptureCompletedCallback& callback) OVERRIDE; + virtual void CaptureInvalidRegion() OVERRIDE; virtual const SkISize& size_most_recent() const OVERRIDE; private: @@ -79,10 +78,9 @@ class VideoFrameCapturerWin : public VideoFrameCapturer { // contents reported to the caller, to determine the dirty region. void CalculateInvalidRegion(); - // Creates a CaptureData instance wrapping the current framebuffer and calls - // |callback| with it. - void CaptureRegion(const SkRegion& region, - const CaptureCompletedCallback& callback); + // Creates a CaptureData instance wrapping the current framebuffer and + // notifies |delegate_|. + void CaptureRegion(const SkRegion& region); // Captures the current screen contents into the next available framebuffer. void CaptureImage(); @@ -94,13 +92,12 @@ class VideoFrameCapturerWin : public VideoFrameCapturer { // Capture the current cursor shape. void CaptureCursor(); + Delegate* delegate_; + // A thread-safe list of invalid rectangles, and the size of the most // recently captured screen. VideoFrameCapturerHelper helper_; - // Callback notified whenever the cursor shape is changed. - CursorShapeChangedCallback cursor_shape_changed_callback_; - // Snapshot of the last cursor bitmap we sent to the client. This is used // to diff against the current cursor so we only send a cursor-change // message when the shape has changed. @@ -151,7 +148,8 @@ VideoFrameCapturerWin::VideoFrameBuffer::VideoFrameBuffer() } VideoFrameCapturerWin::VideoFrameCapturerWin() - : last_cursor_size_(SkISize::Make(0, 0)), + : delegate_(NULL), + last_cursor_size_(SkISize::Make(0, 0)), desktop_dc_rect_(SkIRect::MakeEmpty()), resource_generation_(0), current_buffer_(0), @@ -170,8 +168,7 @@ void VideoFrameCapturerWin::InvalidateRegion(const SkRegion& invalid_region) { helper_.InvalidateRegion(invalid_region); } -void VideoFrameCapturerWin::CaptureInvalidRegion( - const CaptureCompletedCallback& callback) { +void VideoFrameCapturerWin::CaptureInvalidRegion() { // Force the system to power-up display hardware, if it has been suspended. SetThreadExecutionState(ES_DISPLAY_REQUIRED); @@ -179,7 +176,7 @@ void VideoFrameCapturerWin::CaptureInvalidRegion( CalculateInvalidRegion(); SkRegion invalid_region; helper_.SwapInvalidRegion(&invalid_region); - CaptureRegion(invalid_region, callback); + CaptureRegion(invalid_region); // Check for cursor shape update. CaptureCursor(); @@ -189,9 +186,10 @@ const SkISize& VideoFrameCapturerWin::size_most_recent() const { return helper_.size_most_recent(); } -void VideoFrameCapturerWin::Start( - const CursorShapeChangedCallback& callback) { - cursor_shape_changed_callback_ = callback; +void VideoFrameCapturerWin::Start(Delegate* delegate) { + DCHECK(delegate_ == NULL); + + delegate_ = delegate; // Load dwmapi.dll dynamically since it is not available on XP. if (!dwmapi_library_.is_valid()) { @@ -217,6 +215,8 @@ void VideoFrameCapturerWin::Stop() { if (composition_func_ != NULL) { (*composition_func_)(DWM_EC_ENABLECOMPOSITION); } + + delegate_ = NULL; } void VideoFrameCapturerWin::PrepareCaptureResources() { @@ -347,9 +347,7 @@ void VideoFrameCapturerWin::CalculateInvalidRegion() { InvalidateRegion(region); } -void VideoFrameCapturerWin::CaptureRegion( - const SkRegion& region, - const CaptureCompletedCallback& callback) { +void VideoFrameCapturerWin::CaptureRegion(const SkRegion& region) { const VideoFrameBuffer& buffer = buffers_[current_buffer_]; current_buffer_ = (current_buffer_ + 1) % kNumBuffers; @@ -364,7 +362,7 @@ void VideoFrameCapturerWin::CaptureRegion( helper_.set_size_most_recent(data->size()); - callback.Run(data); + delegate_->OnCaptureCompleted(data); } void VideoFrameCapturerWin::CaptureImage() { @@ -561,7 +559,7 @@ void VideoFrameCapturerWin::CaptureCursor() { memcpy(last_cursor_.get(), cursor_dst_data, data_size); last_cursor_size_ = SkISize::Make(width, height); - cursor_shape_changed_callback_.Run(cursor_proto.Pass()); + delegate_->OnCursorShapeChanged(cursor_proto.Pass()); } } // namespace diff --git a/remoting/host/video_scheduler.cc b/remoting/host/video_scheduler.cc index ded48dc..6c1d30d 100644 --- a/remoting/host/video_scheduler.cc +++ b/remoting/host/video_scheduler.cc @@ -60,6 +60,38 @@ VideoScheduler::VideoScheduler( // Public methods -------------------------------------------------------------- +void VideoScheduler::OnCaptureCompleted( + scoped_refptr<CaptureData> capture_data) { + DCHECK(capture_task_runner_->BelongsToCurrentThread()); + + if (capture_data) { + base::TimeDelta capture_time = base::Time::Now() - capture_start_time_; + int capture_time_ms = + static_cast<int>(capture_time.InMilliseconds()); + capture_data->set_capture_time_ms(capture_time_ms); + scheduler_.RecordCaptureTime(capture_time); + + // The best way to get this value is by binding the sequence number to + // the callback when calling CaptureInvalidRects(). However the callback + // system doesn't allow this. Reading from the member variable is + // accurate as long as capture is synchronous as the following statement + // will obtain the most recent sequence number received. + capture_data->set_client_sequence_number(sequence_number_); + } + + encode_task_runner_->PostTask( + FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); +} + +void VideoScheduler::OnCursorShapeChanged( + scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { + DCHECK(capture_task_runner_->BelongsToCurrentThread()); + + network_task_runner_->PostTask( + FROM_HERE, base::Bind(&VideoScheduler::SendCursorShape, this, + base::Passed(&cursor_shape))); +} + void VideoScheduler::Stop(const base::Closure& done_task) { DCHECK(network_task_runner_->BelongsToCurrentThread()); DCHECK(!done_task.is_null()); @@ -112,8 +144,7 @@ void VideoScheduler::StartOnCaptureThread() { DCHECK(capture_task_runner_->BelongsToCurrentThread()); // Start the capturer and let it notify us of cursor shape changes. - capturer_->Start( - base::Bind(&VideoScheduler::CursorShapeChangedCallback, this)); + capturer_->Start(this); capture_timer_.reset(new base::OneShotTimer<VideoScheduler>()); @@ -171,40 +202,7 @@ void VideoScheduler::CaptureNextFrame() { // And finally perform one capture. capture_start_time_ = base::Time::Now(); - capturer_->CaptureInvalidRegion( - base::Bind(&VideoScheduler::CaptureDoneCallback, this)); -} - -void VideoScheduler::CaptureDoneCallback( - scoped_refptr<CaptureData> capture_data) { - DCHECK(capture_task_runner_->BelongsToCurrentThread()); - - if (capture_data) { - base::TimeDelta capture_time = base::Time::Now() - capture_start_time_; - int capture_time_ms = - static_cast<int>(capture_time.InMilliseconds()); - capture_data->set_capture_time_ms(capture_time_ms); - scheduler_.RecordCaptureTime(capture_time); - - // The best way to get this value is by binding the sequence number to - // the callback when calling CaptureInvalidRects(). However the callback - // system doesn't allow this. Reading from the member variable is - // accurate as long as capture is synchronous as the following statement - // will obtain the most recent sequence number received. - capture_data->set_client_sequence_number(sequence_number_); - } - - encode_task_runner_->PostTask( - FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data)); -} - -void VideoScheduler::CursorShapeChangedCallback( - scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { - DCHECK(capture_task_runner_->BelongsToCurrentThread()); - - network_task_runner_->PostTask( - FROM_HERE, base::Bind(&VideoScheduler::SendCursorShape, this, - base::Passed(&cursor_shape))); + capturer_->CaptureInvalidRegion(); } void VideoScheduler::FrameCaptureCompleted() { diff --git a/remoting/host/video_scheduler.h b/remoting/host/video_scheduler.h index 92cc1bd..98c4d41 100644 --- a/remoting/host/video_scheduler.h +++ b/remoting/host/video_scheduler.h @@ -15,6 +15,7 @@ #include "base/timer.h" #include "remoting/codec/video_encoder.h" #include "remoting/host/capture_scheduler.h" +#include "remoting/host/video_frame_capturer.h" #include "remoting/proto/video.pb.h" namespace base { @@ -68,7 +69,8 @@ class VideoStub; // rate-limit captures to avoid overloading the host system, either by consuming // too much CPU, or hogging the host's graphics subsystem. -class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler> { +class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>, + public VideoFrameCapturer::Delegate { public: // Creates a VideoScheduler running capture, encode and network tasks on the // supplied TaskRunners. Video and cursor shape updates will be pumped to @@ -84,6 +86,12 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler> { protocol::ClientStub* client_stub, protocol::VideoStub* video_stub); + // VideoFrameCapturer::Delegate implementation + virtual void OnCaptureCompleted( + scoped_refptr<CaptureData> capture_data) OVERRIDE; + virtual void OnCursorShapeChanged( + scoped_ptr<protocol::CursorShapeInfo> cursor_shape) OVERRIDE; + // Stop scheduling frame captures. |done_task| is executed on the network // thread when capturing has stopped. This object cannot be re-used once // it has been stopped. @@ -116,13 +124,6 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler> { // Starts the next frame capture, unless there are already too many pending. void CaptureNextFrame(); - // Called when a frame capture completes. - void CaptureDoneCallback(scoped_refptr<CaptureData> capture_data); - - // Called when the cursor shape changes. - void CursorShapeChangedCallback( - scoped_ptr<protocol::CursorShapeInfo> cursor_data); - // Called when a frame capture has been encoded & sent to the client. void FrameCaptureCompleted(); diff --git a/remoting/host/video_scheduler_unittest.cc b/remoting/host/video_scheduler_unittest.cc index 54b572c..8ca7d7a 100644 --- a/remoting/host/video_scheduler_unittest.cc +++ b/remoting/host/video_scheduler_unittest.cc @@ -34,12 +34,6 @@ namespace remoting { namespace { -ACTION_P2(RunCallback, region, data) { - SkRegion& dirty_region = data->mutable_dirty_region(); - dirty_region.op(region, SkRegion::kUnion_Op); - arg0.Run(data); -} - ACTION(FinishEncode) { scoped_ptr<VideoPacket> packet(new VideoPacket()); packet->set_flags(VideoPacket::LAST_PACKET | VideoPacket::LAST_PARTITION); @@ -82,7 +76,7 @@ MockVideoEncoder::~MockVideoEncoder() {} class VideoSchedulerTest : public testing::Test { public: - VideoSchedulerTest() { + VideoSchedulerTest() : size_(SkISize::Make(0, 0)) { } virtual void SetUp() OVERRIDE { @@ -100,6 +94,8 @@ class VideoSchedulerTest : public testing::Test { &video_stub_); } + void GenerateOnCaptureCompleted(); + protected: MessageLoop message_loop_; scoped_refptr<VideoScheduler> scheduler_; @@ -111,16 +107,25 @@ class VideoSchedulerTest : public testing::Test { // The following mock objects are owned by VideoScheduler. MockVideoEncoder* encoder_; + SkISize size_; + scoped_refptr<CaptureData> data_; + private: DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest); }; +void VideoSchedulerTest::GenerateOnCaptureCompleted() { + SkRegion update_region(SkIRect::MakeXYWH(0, 0, 10, 10)); + data_->mutable_dirty_region().op(update_region, SkRegion::kUnion_Op); + + scheduler_->OnCaptureCompleted(data_); +} + // This test mocks capturer, encoder and network layer to simulate one capture // cycle. When the first encoded packet is submitted to the network // VideoScheduler is instructed to come to a complete stop. We expect the stop // sequence to be executed successfully. TEST_F(VideoSchedulerTest, StartAndStop) { - SkRegion update_region(SkIRect::MakeXYWH(0, 0, 10, 10)); DataPlanes planes; for (int i = 0; i < DataPlanes::kPlaneCount; ++i) { planes.data[i] = reinterpret_cast<uint8*>(i); @@ -129,22 +134,23 @@ TEST_F(VideoSchedulerTest, StartAndStop) { Expectation capturer_start = EXPECT_CALL(capturer_, Start(_)); - SkISize size(SkISize::Make(kWidth, kHeight)); - scoped_refptr<CaptureData> data(new CaptureData(planes, size, kFormat)); + size_.set(kWidth, kHeight); + data_ = new CaptureData(planes, size_, kFormat); // Create a RunLoop through which to drive |message_loop_|. base::RunLoop run_loop; EXPECT_CALL(capturer_, size_most_recent()) - .WillRepeatedly(ReturnRef(size)); + .WillRepeatedly(ReturnRef(size_)); // First the capturer is called. - Expectation capturer_capture = EXPECT_CALL(capturer_, CaptureInvalidRegion(_)) + Expectation capturer_capture = EXPECT_CALL(capturer_, CaptureInvalidRegion()) .After(capturer_start) - .WillRepeatedly(RunCallback(update_region, data)); + .WillRepeatedly(InvokeWithoutArgs( + this, &VideoSchedulerTest::GenerateOnCaptureCompleted)); // Expect the encoder be called. - EXPECT_CALL(*encoder_, Encode(data, false, _)) + EXPECT_CALL(*encoder_, Encode(data_, false, _)) .WillRepeatedly(FinishEncode()); // By default delete the arguments when ProcessVideoPacket is received. |