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