| 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/host/video_frame_capturer.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 // VideoFrameCapturerWin captures 32bit RGB using GDI. | 41 // VideoFrameCapturerWin captures 32bit RGB using GDI. |
| 42 // | 42 // |
| 43 // VideoFrameCapturerWin is double-buffered as required by VideoFrameCapturer. | 43 // VideoFrameCapturerWin is double-buffered as required by VideoFrameCapturer. |
| 44 // See remoting/host/video_frame_capturer.h. | 44 // See remoting/host/video_frame_capturer.h. |
| 45 class VideoFrameCapturerWin : public VideoFrameCapturer { | 45 class VideoFrameCapturerWin : public VideoFrameCapturer { |
| 46 public: | 46 public: |
| 47 VideoFrameCapturerWin(); | 47 VideoFrameCapturerWin(); |
| 48 virtual ~VideoFrameCapturerWin(); | 48 virtual ~VideoFrameCapturerWin(); |
| 49 | 49 |
| 50 // Overridden from VideoFrameCapturer: | 50 // Overridden from VideoFrameCapturer: |
| 51 virtual void Start(const CursorShapeChangedCallback& callback) OVERRIDE; | 51 virtual void Start(Delegate* delegate) OVERRIDE; |
| 52 virtual void Stop() OVERRIDE; | 52 virtual void Stop() OVERRIDE; |
| 53 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; | 53 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; |
| 54 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; | 54 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; |
| 55 virtual void CaptureInvalidRegion( | 55 virtual void CaptureInvalidRegion() OVERRIDE; |
| 56 const CaptureCompletedCallback& callback) OVERRIDE; | |
| 57 virtual const SkISize& size_most_recent() const OVERRIDE; | 56 virtual const SkISize& size_most_recent() const OVERRIDE; |
| 58 | 57 |
| 59 private: | 58 private: |
| 60 struct VideoFrameBuffer { | 59 struct VideoFrameBuffer { |
| 61 VideoFrameBuffer(); | 60 VideoFrameBuffer(); |
| 62 | 61 |
| 63 void* data; | 62 void* data; |
| 64 SkISize size; | 63 SkISize size; |
| 65 int bytes_per_pixel; | 64 int bytes_per_pixel; |
| 66 int bytes_per_row; | 65 int bytes_per_row; |
| 67 int resource_generation; | 66 int resource_generation; |
| 68 }; | 67 }; |
| 69 | 68 |
| 70 // Make sure that the device contexts and the current buffer match the screen | 69 // Make sure that the device contexts and the current buffer match the screen |
| 71 // configuration. | 70 // configuration. |
| 72 void PrepareCaptureResources(); | 71 void PrepareCaptureResources(); |
| 73 | 72 |
| 74 // Allocates the specified capture buffer using the current device contexts | 73 // Allocates the specified capture buffer using the current device contexts |
| 75 // and desktop dimensions, releasing any pre-existing buffer. | 74 // and desktop dimensions, releasing any pre-existing buffer. |
| 76 void AllocateBuffer(int buffer_index, int resource_generation); | 75 void AllocateBuffer(int buffer_index, int resource_generation); |
| 77 | 76 |
| 78 // Compares the most recently captured screen contents with the previous | 77 // Compares the most recently captured screen contents with the previous |
| 79 // contents reported to the caller, to determine the dirty region. | 78 // contents reported to the caller, to determine the dirty region. |
| 80 void CalculateInvalidRegion(); | 79 void CalculateInvalidRegion(); |
| 81 | 80 |
| 82 // Creates a CaptureData instance wrapping the current framebuffer and calls | 81 // Creates a CaptureData instance wrapping the current framebuffer and |
| 83 // |callback| with it. | 82 // notifies |delegate_|. |
| 84 void CaptureRegion(const SkRegion& region, | 83 void CaptureRegion(const SkRegion& region); |
| 85 const CaptureCompletedCallback& callback); | |
| 86 | 84 |
| 87 // Captures the current screen contents into the next available framebuffer. | 85 // Captures the current screen contents into the next available framebuffer. |
| 88 void CaptureImage(); | 86 void CaptureImage(); |
| 89 | 87 |
| 90 // Expand the cursor shape to add a white outline for visibility against | 88 // Expand the cursor shape to add a white outline for visibility against |
| 91 // dark backgrounds. | 89 // dark backgrounds. |
| 92 void AddCursorOutline(int width, int height, uint32* dst); | 90 void AddCursorOutline(int width, int height, uint32* dst); |
| 93 | 91 |
| 94 // Capture the current cursor shape. | 92 // Capture the current cursor shape. |
| 95 void CaptureCursor(); | 93 void CaptureCursor(); |
| 96 | 94 |
| 95 Delegate* delegate_; |
| 96 |
| 97 // A thread-safe list of invalid rectangles, and the size of the most | 97 // A thread-safe list of invalid rectangles, and the size of the most |
| 98 // recently captured screen. | 98 // recently captured screen. |
| 99 VideoFrameCapturerHelper helper_; | 99 VideoFrameCapturerHelper helper_; |
| 100 | 100 |
| 101 // Callback notified whenever the cursor shape is changed. | |
| 102 CursorShapeChangedCallback cursor_shape_changed_callback_; | |
| 103 | |
| 104 // Snapshot of the last cursor bitmap we sent to the client. This is used | 101 // Snapshot of the last cursor bitmap we sent to the client. This is used |
| 105 // to diff against the current cursor so we only send a cursor-change | 102 // to diff against the current cursor so we only send a cursor-change |
| 106 // message when the shape has changed. | 103 // message when the shape has changed. |
| 107 scoped_array<uint8> last_cursor_; | 104 scoped_array<uint8> last_cursor_; |
| 108 SkISize last_cursor_size_; | 105 SkISize last_cursor_size_; |
| 109 | 106 |
| 110 // There are two buffers for the screen images, as required by Capturer. | 107 // There are two buffers for the screen images, as required by Capturer. |
| 111 static const int kNumBuffers = 2; | 108 static const int kNumBuffers = 2; |
| 112 VideoFrameBuffer buffers_[kNumBuffers]; | 109 VideoFrameBuffer buffers_[kNumBuffers]; |
| 113 | 110 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 144 | 141 |
| 145 VideoFrameCapturerWin::VideoFrameBuffer::VideoFrameBuffer() | 142 VideoFrameCapturerWin::VideoFrameBuffer::VideoFrameBuffer() |
| 146 : data(NULL), | 143 : data(NULL), |
| 147 size(SkISize::Make(0, 0)), | 144 size(SkISize::Make(0, 0)), |
| 148 bytes_per_pixel(0), | 145 bytes_per_pixel(0), |
| 149 bytes_per_row(0), | 146 bytes_per_row(0), |
| 150 resource_generation(0) { | 147 resource_generation(0) { |
| 151 } | 148 } |
| 152 | 149 |
| 153 VideoFrameCapturerWin::VideoFrameCapturerWin() | 150 VideoFrameCapturerWin::VideoFrameCapturerWin() |
| 154 : last_cursor_size_(SkISize::Make(0, 0)), | 151 : delegate_(NULL), |
| 152 last_cursor_size_(SkISize::Make(0, 0)), |
| 155 desktop_dc_rect_(SkIRect::MakeEmpty()), | 153 desktop_dc_rect_(SkIRect::MakeEmpty()), |
| 156 resource_generation_(0), | 154 resource_generation_(0), |
| 157 current_buffer_(0), | 155 current_buffer_(0), |
| 158 pixel_format_(media::VideoFrame::RGB32), | 156 pixel_format_(media::VideoFrame::RGB32), |
| 159 composition_func_(NULL) { | 157 composition_func_(NULL) { |
| 160 } | 158 } |
| 161 | 159 |
| 162 VideoFrameCapturerWin::~VideoFrameCapturerWin() { | 160 VideoFrameCapturerWin::~VideoFrameCapturerWin() { |
| 163 } | 161 } |
| 164 | 162 |
| 165 media::VideoFrame::Format VideoFrameCapturerWin::pixel_format() const { | 163 media::VideoFrame::Format VideoFrameCapturerWin::pixel_format() const { |
| 166 return pixel_format_; | 164 return pixel_format_; |
| 167 } | 165 } |
| 168 | 166 |
| 169 void VideoFrameCapturerWin::InvalidateRegion(const SkRegion& invalid_region) { | 167 void VideoFrameCapturerWin::InvalidateRegion(const SkRegion& invalid_region) { |
| 170 helper_.InvalidateRegion(invalid_region); | 168 helper_.InvalidateRegion(invalid_region); |
| 171 } | 169 } |
| 172 | 170 |
| 173 void VideoFrameCapturerWin::CaptureInvalidRegion( | 171 void VideoFrameCapturerWin::CaptureInvalidRegion() { |
| 174 const CaptureCompletedCallback& callback) { | |
| 175 // Force the system to power-up display hardware, if it has been suspended. | 172 // Force the system to power-up display hardware, if it has been suspended. |
| 176 SetThreadExecutionState(ES_DISPLAY_REQUIRED); | 173 SetThreadExecutionState(ES_DISPLAY_REQUIRED); |
| 177 | 174 |
| 178 // Perform the capture. | 175 // Perform the capture. |
| 179 CalculateInvalidRegion(); | 176 CalculateInvalidRegion(); |
| 180 SkRegion invalid_region; | 177 SkRegion invalid_region; |
| 181 helper_.SwapInvalidRegion(&invalid_region); | 178 helper_.SwapInvalidRegion(&invalid_region); |
| 182 CaptureRegion(invalid_region, callback); | 179 CaptureRegion(invalid_region); |
| 183 | 180 |
| 184 // Check for cursor shape update. | 181 // Check for cursor shape update. |
| 185 CaptureCursor(); | 182 CaptureCursor(); |
| 186 } | 183 } |
| 187 | 184 |
| 188 const SkISize& VideoFrameCapturerWin::size_most_recent() const { | 185 const SkISize& VideoFrameCapturerWin::size_most_recent() const { |
| 189 return helper_.size_most_recent(); | 186 return helper_.size_most_recent(); |
| 190 } | 187 } |
| 191 | 188 |
| 192 void VideoFrameCapturerWin::Start( | 189 void VideoFrameCapturerWin::Start(Delegate* delegate) { |
| 193 const CursorShapeChangedCallback& callback) { | 190 DCHECK(delegate_ == NULL); |
| 194 cursor_shape_changed_callback_ = callback; | 191 |
| 192 delegate_ = delegate; |
| 195 | 193 |
| 196 // Load dwmapi.dll dynamically since it is not available on XP. | 194 // Load dwmapi.dll dynamically since it is not available on XP. |
| 197 if (!dwmapi_library_.is_valid()) { | 195 if (!dwmapi_library_.is_valid()) { |
| 198 FilePath path(base::GetNativeLibraryName(UTF8ToUTF16(kDwmapiLibraryName))); | 196 FilePath path(base::GetNativeLibraryName(UTF8ToUTF16(kDwmapiLibraryName))); |
| 199 dwmapi_library_.Reset(base::LoadNativeLibrary(path, NULL)); | 197 dwmapi_library_.Reset(base::LoadNativeLibrary(path, NULL)); |
| 200 } | 198 } |
| 201 | 199 |
| 202 if (dwmapi_library_.is_valid() && composition_func_ == NULL) { | 200 if (dwmapi_library_.is_valid() && composition_func_ == NULL) { |
| 203 composition_func_ = static_cast<DwmEnableCompositionFunc>( | 201 composition_func_ = static_cast<DwmEnableCompositionFunc>( |
| 204 dwmapi_library_.GetFunctionPointer("DwmEnableComposition")); | 202 dwmapi_library_.GetFunctionPointer("DwmEnableComposition")); |
| 205 } | 203 } |
| 206 | 204 |
| 207 // Vote to disable Aero composited desktop effects while capturing. Windows | 205 // Vote to disable Aero composited desktop effects while capturing. Windows |
| 208 // will restore Aero automatically if the process exits. This has no effect | 206 // will restore Aero automatically if the process exits. This has no effect |
| 209 // under Windows 8 or higher. See crbug.com/124018. | 207 // under Windows 8 or higher. See crbug.com/124018. |
| 210 if (composition_func_ != NULL) { | 208 if (composition_func_ != NULL) { |
| 211 (*composition_func_)(DWM_EC_DISABLECOMPOSITION); | 209 (*composition_func_)(DWM_EC_DISABLECOMPOSITION); |
| 212 } | 210 } |
| 213 } | 211 } |
| 214 | 212 |
| 215 void VideoFrameCapturerWin::Stop() { | 213 void VideoFrameCapturerWin::Stop() { |
| 216 // Restore Aero. | 214 // Restore Aero. |
| 217 if (composition_func_ != NULL) { | 215 if (composition_func_ != NULL) { |
| 218 (*composition_func_)(DWM_EC_ENABLECOMPOSITION); | 216 (*composition_func_)(DWM_EC_ENABLECOMPOSITION); |
| 219 } | 217 } |
| 218 |
| 219 delegate_ = NULL; |
| 220 } | 220 } |
| 221 | 221 |
| 222 void VideoFrameCapturerWin::PrepareCaptureResources() { | 222 void VideoFrameCapturerWin::PrepareCaptureResources() { |
| 223 // Switch to the desktop receiving user input if different from the current | 223 // Switch to the desktop receiving user input if different from the current |
| 224 // one. | 224 // one. |
| 225 scoped_ptr<Desktop> input_desktop = Desktop::GetInputDesktop(); | 225 scoped_ptr<Desktop> input_desktop = Desktop::GetInputDesktop(); |
| 226 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { | 226 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { |
| 227 // Release GDI resources otherwise SetThreadDesktop will fail. | 227 // Release GDI resources otherwise SetThreadDesktop will fail. |
| 228 desktop_dc_.reset(); | 228 desktop_dc_.reset(); |
| 229 memory_dc_.Set(NULL); | 229 memory_dc_.Set(NULL); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 differ_.reset(new Differ(current.size.width(), current.size.height(), | 340 differ_.reset(new Differ(current.size.width(), current.size.height(), |
| 341 current.bytes_per_pixel, current.bytes_per_row)); | 341 current.bytes_per_pixel, current.bytes_per_row)); |
| 342 } | 342 } |
| 343 | 343 |
| 344 SkRegion region; | 344 SkRegion region; |
| 345 differ_->CalcDirtyRegion(prev.data, current.data, ®ion); | 345 differ_->CalcDirtyRegion(prev.data, current.data, ®ion); |
| 346 | 346 |
| 347 InvalidateRegion(region); | 347 InvalidateRegion(region); |
| 348 } | 348 } |
| 349 | 349 |
| 350 void VideoFrameCapturerWin::CaptureRegion( | 350 void VideoFrameCapturerWin::CaptureRegion(const SkRegion& region) { |
| 351 const SkRegion& region, | |
| 352 const CaptureCompletedCallback& callback) { | |
| 353 const VideoFrameBuffer& buffer = buffers_[current_buffer_]; | 351 const VideoFrameBuffer& buffer = buffers_[current_buffer_]; |
| 354 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; | 352 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; |
| 355 | 353 |
| 356 DataPlanes planes; | 354 DataPlanes planes; |
| 357 planes.data[0] = static_cast<uint8*>(buffer.data); | 355 planes.data[0] = static_cast<uint8*>(buffer.data); |
| 358 planes.strides[0] = buffer.bytes_per_row; | 356 planes.strides[0] = buffer.bytes_per_row; |
| 359 | 357 |
| 360 scoped_refptr<CaptureData> data(new CaptureData(planes, | 358 scoped_refptr<CaptureData> data(new CaptureData(planes, |
| 361 buffer.size, | 359 buffer.size, |
| 362 pixel_format_)); | 360 pixel_format_)); |
| 363 data->mutable_dirty_region() = region; | 361 data->mutable_dirty_region() = region; |
| 364 | 362 |
| 365 helper_.set_size_most_recent(data->size()); | 363 helper_.set_size_most_recent(data->size()); |
| 366 | 364 |
| 367 callback.Run(data); | 365 delegate_->OnCaptureCompleted(data); |
| 368 } | 366 } |
| 369 | 367 |
| 370 void VideoFrameCapturerWin::CaptureImage() { | 368 void VideoFrameCapturerWin::CaptureImage() { |
| 371 // Make sure the GDI capture resources are up-to-date. | 369 // Make sure the GDI capture resources are up-to-date. |
| 372 PrepareCaptureResources(); | 370 PrepareCaptureResources(); |
| 373 | 371 |
| 374 // Select the target bitmap into the memory dc. | 372 // Select the target bitmap into the memory dc. |
| 375 SelectObject(memory_dc_, target_bitmap_[current_buffer_]); | 373 SelectObject(memory_dc_, target_bitmap_[current_buffer_]); |
| 376 | 374 |
| 377 // And then copy the rect from desktop to memory. | 375 // And then copy the rect from desktop to memory. |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 cursor_proto->set_width(width); | 552 cursor_proto->set_width(width); |
| 555 cursor_proto->set_height(height); | 553 cursor_proto->set_height(height); |
| 556 cursor_proto->set_hotspot_x(hotspot_x); | 554 cursor_proto->set_hotspot_x(hotspot_x); |
| 557 cursor_proto->set_hotspot_y(hotspot_y); | 555 cursor_proto->set_hotspot_y(hotspot_y); |
| 558 | 556 |
| 559 // Record the last cursor image that we sent to the client. | 557 // Record the last cursor image that we sent to the client. |
| 560 last_cursor_.reset(new uint8[data_size]); | 558 last_cursor_.reset(new uint8[data_size]); |
| 561 memcpy(last_cursor_.get(), cursor_dst_data, data_size); | 559 memcpy(last_cursor_.get(), cursor_dst_data, data_size); |
| 562 last_cursor_size_ = SkISize::Make(width, height); | 560 last_cursor_size_ = SkISize::Make(width, height); |
| 563 | 561 |
| 564 cursor_shape_changed_callback_.Run(cursor_proto.Pass()); | 562 delegate_->OnCursorShapeChanged(cursor_proto.Pass()); |
| 565 } | 563 } |
| 566 | 564 |
| 567 } // namespace | 565 } // namespace |
| 568 | 566 |
| 569 // static | 567 // static |
| 570 VideoFrameCapturer* VideoFrameCapturer::Create() { | 568 VideoFrameCapturer* VideoFrameCapturer::Create() { |
| 571 return new VideoFrameCapturerWin(); | 569 return new VideoFrameCapturerWin(); |
| 572 } | 570 } |
| 573 | 571 |
| 574 } // namespace remoting | 572 } // namespace remoting |
| OLD | NEW |