OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/video_frame_capturer.h" | 5 #include "remoting/capturer/video_frame_capturer.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/scoped_native_library.h" | 14 #include "base/scoped_native_library.h" |
15 #include "base/time.h" | 15 #include "base/time.h" |
16 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
17 #include "base/win/scoped_gdi_object.h" | 17 #include "base/win/scoped_gdi_object.h" |
18 #include "base/win/scoped_hdc.h" | 18 #include "base/win/scoped_hdc.h" |
19 #include "remoting/base/capture_data.h" | 19 #include "remoting/capturer/capture_data.h" |
20 #include "remoting/base/shared_buffer_factory.h" | 20 #include "remoting/capturer/differ.h" |
21 #include "remoting/host/differ.h" | 21 #include "remoting/capturer/mouse_cursor_shape.h" |
22 #include "remoting/host/video_frame.h" | 22 #include "remoting/capturer/shared_buffer_factory.h" |
23 #include "remoting/host/video_frame_capturer_helper.h" | 23 #include "remoting/capturer/video_frame.h" |
24 #include "remoting/host/video_frame_queue.h" | 24 #include "remoting/capturer/video_frame_capturer_helper.h" |
25 #include "remoting/host/win/desktop.h" | 25 #include "remoting/capturer/video_frame_queue.h" |
26 #include "remoting/host/win/scoped_thread_desktop.h" | 26 #include "remoting/capturer/win/desktop.h" |
| 27 #include "remoting/capturer/win/scoped_thread_desktop.h" |
27 #include "remoting/proto/control.pb.h" | 28 #include "remoting/proto/control.pb.h" |
28 #include "third_party/skia/include/core/SkColorPriv.h" | 29 #include "third_party/skia/include/core/SkColorPriv.h" |
29 | 30 |
30 namespace remoting { | 31 namespace remoting { |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 // Constants from dwmapi.h. | 35 // Constants from dwmapi.h. |
35 const UINT DWM_EC_DISABLECOMPOSITION = 0; | 36 const UINT DWM_EC_DISABLECOMPOSITION = 0; |
36 const UINT DWM_EC_ENABLECOMPOSITION = 1; | 37 const UINT DWM_EC_ENABLECOMPOSITION = 1; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 | 113 |
113 Delegate* delegate_; | 114 Delegate* delegate_; |
114 | 115 |
115 // A thread-safe list of invalid rectangles, and the size of the most | 116 // A thread-safe list of invalid rectangles, and the size of the most |
116 // recently captured screen. | 117 // recently captured screen. |
117 VideoFrameCapturerHelper helper_; | 118 VideoFrameCapturerHelper helper_; |
118 | 119 |
119 // Snapshot of the last cursor bitmap we sent to the client. This is used | 120 // Snapshot of the last cursor bitmap we sent to the client. This is used |
120 // to diff against the current cursor so we only send a cursor-change | 121 // to diff against the current cursor so we only send a cursor-change |
121 // message when the shape has changed. | 122 // message when the shape has changed. |
122 scoped_array<uint8> last_cursor_; | 123 MouseCursorShape last_cursor_; |
123 SkISize last_cursor_size_; | |
124 | 124 |
125 ScopedThreadDesktop desktop_; | 125 ScopedThreadDesktop desktop_; |
126 | 126 |
127 // GDI resources used for screen capture. | 127 // GDI resources used for screen capture. |
128 scoped_ptr<base::win::ScopedGetDC> desktop_dc_; | 128 scoped_ptr<base::win::ScopedGetDC> desktop_dc_; |
129 base::win::ScopedCreateDC memory_dc_; | 129 base::win::ScopedCreateDC memory_dc_; |
130 | 130 |
131 // Queue of the frames buffers. | 131 // Queue of the frames buffers. |
132 VideoFrameQueue queue_; | 132 VideoFrameQueue queue_; |
133 | 133 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 set_pixels(reinterpret_cast<uint8*>(data)); | 207 set_pixels(reinterpret_cast<uint8*>(data)); |
208 set_dimensions(SkISize::Make(bmi.bmiHeader.biWidth, | 208 set_dimensions(SkISize::Make(bmi.bmiHeader.biWidth, |
209 std::abs(bmi.bmiHeader.biHeight))); | 209 std::abs(bmi.bmiHeader.biHeight))); |
210 set_bytes_per_row( | 210 set_bytes_per_row( |
211 bmi.bmiHeader.biSizeImage / std::abs(bmi.bmiHeader.biHeight)); | 211 bmi.bmiHeader.biSizeImage / std::abs(bmi.bmiHeader.biHeight)); |
212 } | 212 } |
213 | 213 |
214 VideoFrameCapturerWin::VideoFrameCapturerWin() | 214 VideoFrameCapturerWin::VideoFrameCapturerWin() |
215 : shared_buffer_factory_(NULL), | 215 : shared_buffer_factory_(NULL), |
216 delegate_(NULL), | 216 delegate_(NULL), |
217 last_cursor_size_(SkISize::Make(0, 0)), | |
218 desktop_dc_rect_(SkIRect::MakeEmpty()), | 217 desktop_dc_rect_(SkIRect::MakeEmpty()), |
219 pixel_format_(media::VideoFrame::RGB32), | 218 pixel_format_(media::VideoFrame::RGB32), |
220 composition_func_(NULL) { | 219 composition_func_(NULL) { |
221 } | 220 } |
222 | 221 |
223 VideoFrameCapturerWin::VideoFrameCapturerWin( | 222 VideoFrameCapturerWin::VideoFrameCapturerWin( |
224 SharedBufferFactory* shared_buffer_factory) | 223 SharedBufferFactory* shared_buffer_factory) |
225 : shared_buffer_factory_(shared_buffer_factory), | 224 : shared_buffer_factory_(shared_buffer_factory), |
226 delegate_(NULL), | 225 delegate_(NULL), |
227 last_cursor_size_(SkISize::Make(0, 0)), | |
228 desktop_dc_rect_(SkIRect::MakeEmpty()), | 226 desktop_dc_rect_(SkIRect::MakeEmpty()), |
229 pixel_format_(media::VideoFrame::RGB32), | 227 pixel_format_(media::VideoFrame::RGB32), |
230 composition_func_(NULL) { | 228 composition_func_(NULL) { |
231 } | 229 } |
232 | 230 |
233 VideoFrameCapturerWin::~VideoFrameCapturerWin() { | 231 VideoFrameCapturerWin::~VideoFrameCapturerWin() { |
234 } | 232 } |
235 | 233 |
236 media::VideoFrame::Format VideoFrameCapturerWin::pixel_format() const { | 234 media::VideoFrame::Format VideoFrameCapturerWin::pixel_format() const { |
237 return pixel_format_; | 235 return pixel_format_; |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 int width = bitmap.bmWidth; | 496 int width = bitmap.bmWidth; |
499 int height = bitmap.bmHeight; | 497 int height = bitmap.bmHeight; |
500 // For non-color cursors, the mask contains both an AND and an XOR mask and | 498 // For non-color cursors, the mask contains both an AND and an XOR mask and |
501 // the height includes both. Thus, the width is correct, but we need to | 499 // the height includes both. Thus, the width is correct, but we need to |
502 // divide by 2 to get the correct mask height. | 500 // divide by 2 to get the correct mask height. |
503 if (!color_bitmap) { | 501 if (!color_bitmap) { |
504 height /= 2; | 502 height /= 2; |
505 } | 503 } |
506 int data_size = height * width * kBytesPerPixel; | 504 int data_size = height * width * kBytesPerPixel; |
507 | 505 |
508 scoped_ptr<protocol::CursorShapeInfo> cursor_proto( | 506 scoped_ptr<MouseCursorShape> cursor; |
509 new protocol::CursorShapeInfo()); | 507 cursor->data.resize(data_size); |
510 cursor_proto->mutable_data()->resize(data_size); | 508 uint8* cursor_dst_data = |
511 uint8* cursor_dst_data = const_cast<uint8*>(reinterpret_cast<const uint8*>( | 509 reinterpret_cast<uint8*>(string_as_array(&cursor->data)); |
512 cursor_proto->mutable_data()->data())); | |
513 | 510 |
514 // Copy/convert cursor bitmap into format needed by chromotocol. | 511 // Copy/convert cursor bitmap into format needed by chromotocol. |
515 int row_bytes = bitmap.bmWidthBytes; | 512 int row_bytes = bitmap.bmWidthBytes; |
516 if (color_bitmap) { | 513 if (color_bitmap) { |
517 if (bitmap.bmPlanes != 1 || bitmap.bmBitsPixel != 32) { | 514 if (bitmap.bmPlanes != 1 || bitmap.bmBitsPixel != 32) { |
518 VLOG(3) << "Unsupported color cursor format. Error = " << GetLastError(); | 515 VLOG(3) << "Unsupported color cursor format. Error = " << GetLastError(); |
519 return; | 516 return; |
520 } | 517 } |
521 | 518 |
522 // Copy across colour cursor imagery. | 519 // Copy across colour cursor imagery. |
523 // CursorShapeInfo stores imagery top-down, and premultiplied | 520 // MouseCursorShape stores imagery top-down, and premultiplied |
524 // by the alpha channel, whereas windows stores them bottom-up | 521 // by the alpha channel, whereas windows stores them bottom-up |
525 // and not premultiplied. | 522 // and not premultiplied. |
526 uint8* cursor_src_data = reinterpret_cast<uint8*>(bitmap.bmBits); | 523 uint8* cursor_src_data = reinterpret_cast<uint8*>(bitmap.bmBits); |
527 uint8* src = cursor_src_data + ((height - 1) * row_bytes); | 524 uint8* src = cursor_src_data + ((height - 1) * row_bytes); |
528 uint8* dst = cursor_dst_data; | 525 uint8* dst = cursor_dst_data; |
529 for (int row = 0; row < height; ++row) { | 526 for (int row = 0; row < height; ++row) { |
530 for (int column = 0; column < width; ++column) { | 527 for (int column = 0; column < width; ++column) { |
531 dst[0] = SkAlphaMul(src[0], src[3]); | 528 dst[0] = SkAlphaMul(src[0], src[3]); |
532 dst[1] = SkAlphaMul(src[1], src[3]); | 529 dst[1] = SkAlphaMul(src[1], src[3]); |
533 dst[2] = SkAlphaMul(src[2], src[3]); | 530 dst[2] = SkAlphaMul(src[2], src[3]); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 add_outline = true; | 577 add_outline = true; |
581 } | 578 } |
582 } | 579 } |
583 } | 580 } |
584 if (add_outline) { | 581 if (add_outline) { |
585 AddCursorOutline(width, height, | 582 AddCursorOutline(width, height, |
586 reinterpret_cast<uint32*>(cursor_dst_data)); | 583 reinterpret_cast<uint32*>(cursor_dst_data)); |
587 } | 584 } |
588 } | 585 } |
589 | 586 |
| 587 cursor->size.set(width, height); |
| 588 cursor->hotspot.set(hotspot_x, hotspot_y); |
| 589 |
590 // Compare the current cursor with the last one we sent to the client. If | 590 // Compare the current cursor with the last one we sent to the client. If |
591 // they're the same, then don't bother sending the cursor again. | 591 // they're the same, then don't bother sending the cursor again. |
592 if (last_cursor_size_.equals(width, height) && | 592 if (last_cursor_ == *cursor) { |
593 memcmp(last_cursor_.get(), cursor_dst_data, data_size) == 0) { | |
594 return; | 593 return; |
595 } | 594 } |
596 | 595 |
597 VLOG(3) << "Sending updated cursor: " << width << "x" << height; | 596 VLOG(3) << "Sending updated cursor: " << width << "x" << height; |
598 | 597 |
599 cursor_proto->set_width(width); | 598 // Record the last cursor image that we sent to the client. |
600 cursor_proto->set_height(height); | 599 last_cursor_ = *cursor; |
601 cursor_proto->set_hotspot_x(hotspot_x); | |
602 cursor_proto->set_hotspot_y(hotspot_y); | |
603 | 600 |
604 // Record the last cursor image that we sent to the client. | 601 delegate_->OnCursorShapeChanged(cursor.Pass()); |
605 last_cursor_.reset(new uint8[data_size]); | |
606 memcpy(last_cursor_.get(), cursor_dst_data, data_size); | |
607 last_cursor_size_ = SkISize::Make(width, height); | |
608 | |
609 delegate_->OnCursorShapeChanged(cursor_proto.Pass()); | |
610 } | 602 } |
611 | 603 |
612 } // namespace | 604 } // namespace |
613 | 605 |
614 // static | 606 // static |
615 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::Create() { | 607 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::Create() { |
616 return scoped_ptr<VideoFrameCapturer>(new VideoFrameCapturerWin()); | 608 return scoped_ptr<VideoFrameCapturer>(new VideoFrameCapturerWin()); |
617 } | 609 } |
618 | 610 |
619 // static | 611 // static |
620 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::CreateWithFactory( | 612 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::CreateWithFactory( |
621 SharedBufferFactory* shared_buffer_factory) { | 613 SharedBufferFactory* shared_buffer_factory) { |
622 scoped_ptr<VideoFrameCapturerWin> capturer( | 614 scoped_ptr<VideoFrameCapturerWin> capturer( |
623 new VideoFrameCapturerWin(shared_buffer_factory)); | 615 new VideoFrameCapturerWin(shared_buffer_factory)); |
624 return capturer.PassAs<VideoFrameCapturer>(); | 616 return capturer.PassAs<VideoFrameCapturer>(); |
625 } | 617 } |
626 | 618 |
627 } // namespace remoting | 619 } // namespace remoting |
OLD | NEW |