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/capturer.h" | 5 #include "remoting/host/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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
81 void UpdateBufferCapture(const SkISize& size); | 81 void UpdateBufferCapture(const SkISize& size); |
82 | 82 |
83 // Allocate memory for a buffer of a given size, freeing any memory previously | 83 // Allocate memory for a buffer of a given size, freeing any memory previously |
84 // allocated for that buffer. | 84 // allocated for that buffer. |
85 void ReallocateBuffer(int buffer_index, const SkISize& size); | 85 void ReallocateBuffer(int buffer_index, const SkISize& size); |
86 | 86 |
87 void CalculateInvalidRegion(); | 87 void CalculateInvalidRegion(); |
88 void CaptureRegion(const SkRegion& region, | 88 void CaptureRegion(const SkRegion& region, |
89 const CaptureCompletedCallback& callback); | 89 const CaptureCompletedCallback& callback); |
90 | 90 |
91 void ReleaseBuffers(); | 91 // Release all GDI resources, including bitmaps and device contexts. |
92 void ReleaseGdiResources(); | |
93 | |
92 // Generates an image in the current buffer. | 94 // Generates an image in the current buffer. |
93 void CaptureImage(); | 95 void CaptureImage(); |
94 | 96 |
95 // Expand the cursor shape to add a white outline for visibility against | 97 // Expand the cursor shape to add a white outline for visibility against |
96 // dark backgrounds. | 98 // dark backgrounds. |
97 void AddCursorOutline(int width, int height, uint32* dst); | 99 void AddCursorOutline(int width, int height, uint32* dst); |
98 | 100 |
99 // Capture the current cursor shape. | 101 // Capture the current cursor shape. |
100 void CaptureCursor(); | 102 void CaptureCursor(); |
101 | 103 |
(...skipping 12 matching lines...) Expand all Loading... | |
114 // message when the shape has changed. | 116 // message when the shape has changed. |
115 scoped_array<uint8> last_cursor_; | 117 scoped_array<uint8> last_cursor_; |
116 SkISize last_cursor_size_; | 118 SkISize last_cursor_size_; |
117 | 119 |
118 // There are two buffers for the screen images, as required by Capturer. | 120 // There are two buffers for the screen images, as required by Capturer. |
119 static const int kNumBuffers = 2; | 121 static const int kNumBuffers = 2; |
120 VideoFrameBuffer buffers_[kNumBuffers]; | 122 VideoFrameBuffer buffers_[kNumBuffers]; |
121 | 123 |
122 ScopedThreadDesktopWin desktop_; | 124 ScopedThreadDesktopWin desktop_; |
123 | 125 |
124 // Gdi specific information about screen. | 126 // GDI resources used for screen capture. |
125 HWND desktop_window_; | |
126 HDC desktop_dc_; | 127 HDC desktop_dc_; |
alexeypa (please no reviews)
2012/07/02 15:50:11
nit: There are ScopedGetDC and ScopedCreateDC avai
Wez
2012/07/03 20:56:26
Done.
| |
127 HDC memory_dc_; | 128 HDC memory_dc_; |
128 HBITMAP target_bitmap_[kNumBuffers]; | 129 HBITMAP target_bitmap_[kNumBuffers]; |
alexeypa (please no reviews)
2012/07/02 15:50:11
nit: ScopedBitmap can be used here.
Wez
2012/07/03 20:56:26
Done.
| |
129 | 130 |
130 // The screen size attached to the device contexts through which the screen | 131 // The screen size attached to the device contexts through which the screen |
131 // is captured. | 132 // is captured. |
132 SkISize dc_size_; | 133 SkISize dc_size_; |
133 | 134 |
134 // The current buffer with valid data for reading. | 135 // The current buffer with valid data for reading. |
135 int current_buffer_; | 136 int current_buffer_; |
136 | 137 |
137 // Format of pixels returned in buffer. | 138 // Format of pixels returned in buffer. |
138 media::VideoFrame::Format pixel_format_; | 139 media::VideoFrame::Format pixel_format_; |
139 | 140 |
140 // Class to calculate the difference between two screen bitmaps. | 141 // Class to calculate the difference between two screen bitmaps. |
141 scoped_ptr<Differ> differ_; | 142 scoped_ptr<Differ> differ_; |
142 | 143 |
143 base::ScopedNativeLibrary dwmapi_library_; | 144 base::ScopedNativeLibrary dwmapi_library_; |
144 DwmEnableCompositionFunc composition_func_; | 145 DwmEnableCompositionFunc composition_func_; |
145 | 146 |
146 DISALLOW_COPY_AND_ASSIGN(CapturerGdi); | 147 DISALLOW_COPY_AND_ASSIGN(CapturerGdi); |
147 }; | 148 }; |
148 | 149 |
149 // 3780 pixels per meter is equivalent to 96 DPI, typical on desktop monitors. | 150 // 3780 pixels per meter is equivalent to 96 DPI, typical on desktop monitors. |
150 static const int kPixelsPerMeter = 3780; | 151 static const int kPixelsPerMeter = 3780; |
151 // 32 bit RGBA is 4 bytes per pixel. | 152 // 32 bit RGBA is 4 bytes per pixel. |
152 static const int kBytesPerPixel = 4; | 153 static const int kBytesPerPixel = 4; |
153 | 154 |
154 CapturerGdi::CapturerGdi() | 155 CapturerGdi::CapturerGdi() |
155 : last_cursor_size_(SkISize::Make(0, 0)), | 156 : last_cursor_size_(SkISize::Make(0, 0)), |
156 desktop_window_(NULL), | |
157 desktop_dc_(NULL), | 157 desktop_dc_(NULL), |
158 memory_dc_(NULL), | 158 memory_dc_(NULL), |
159 dc_size_(SkISize::Make(0, 0)), | 159 dc_size_(SkISize::Make(0, 0)), |
160 current_buffer_(0), | 160 current_buffer_(0), |
161 pixel_format_(media::VideoFrame::RGB32), | 161 pixel_format_(media::VideoFrame::RGB32), |
162 composition_func_(NULL) { | 162 composition_func_(NULL) { |
163 memset(target_bitmap_, 0, sizeof(target_bitmap_)); | 163 memset(target_bitmap_, 0, sizeof(target_bitmap_)); |
164 memset(buffers_, 0, sizeof(buffers_)); | 164 memset(buffers_, 0, sizeof(buffers_)); |
165 ScreenConfigurationChanged(); | 165 ScreenConfigurationChanged(); |
166 } | 166 } |
167 | 167 |
168 CapturerGdi::~CapturerGdi() { | 168 CapturerGdi::~CapturerGdi() { |
169 ReleaseBuffers(); | 169 ReleaseGdiResources(); |
170 } | 170 } |
171 | 171 |
172 media::VideoFrame::Format CapturerGdi::pixel_format() const { | 172 media::VideoFrame::Format CapturerGdi::pixel_format() const { |
173 return pixel_format_; | 173 return pixel_format_; |
174 } | 174 } |
175 | 175 |
176 void CapturerGdi::ClearInvalidRegion() { | 176 void CapturerGdi::ClearInvalidRegion() { |
177 helper_.ClearInvalidRegion(); | 177 helper_.ClearInvalidRegion(); |
178 } | 178 } |
179 | 179 |
(...skipping 21 matching lines...) Expand all Loading... | |
201 CaptureRegion(invalid_region, callback); | 201 CaptureRegion(invalid_region, callback); |
202 | 202 |
203 // Check for cursor shape update. | 203 // Check for cursor shape update. |
204 CaptureCursor(); | 204 CaptureCursor(); |
205 } | 205 } |
206 | 206 |
207 const SkISize& CapturerGdi::size_most_recent() const { | 207 const SkISize& CapturerGdi::size_most_recent() const { |
208 return helper_.size_most_recent(); | 208 return helper_.size_most_recent(); |
209 } | 209 } |
210 | 210 |
211 void CapturerGdi::ReleaseBuffers() { | 211 void CapturerGdi::ReleaseGdiResources() { |
212 for (int i = kNumBuffers - 1; i >= 0; i--) { | 212 for (int i = kNumBuffers - 1; i >= 0; i--) { |
213 if (target_bitmap_[i]) { | 213 if (target_bitmap_[i]) { |
214 DeleteObject(target_bitmap_[i]); | 214 DeleteObject(target_bitmap_[i]); |
215 target_bitmap_[i] = NULL; | 215 target_bitmap_[i] = NULL; |
216 } | 216 } |
217 if (buffers_[i].data) { | 217 if (buffers_[i].data) { |
218 DeleteObject(buffers_[i].data); | 218 DeleteObject(buffers_[i].data); |
219 buffers_[i].data = NULL; | 219 buffers_[i].data = NULL; |
220 } | 220 } |
221 } | 221 } |
222 | 222 |
223 if (desktop_dc_) { | 223 if (desktop_dc_) { |
224 ReleaseDC(desktop_window_, desktop_dc_); | 224 ReleaseDC(NULL, desktop_dc_); |
225 desktop_window_ = NULL; | |
226 desktop_dc_ = NULL; | 225 desktop_dc_ = NULL; |
227 } | 226 } |
228 | 227 |
229 if (memory_dc_) { | 228 if (memory_dc_) { |
230 DeleteDC(memory_dc_); | 229 DeleteDC(memory_dc_); |
231 memory_dc_ = NULL; | 230 memory_dc_ = NULL; |
232 } | 231 } |
233 } | 232 } |
234 | 233 |
235 void CapturerGdi::Start( | 234 void CapturerGdi::Start( |
(...skipping 29 matching lines...) Expand all Loading... | |
265 void CapturerGdi::ScreenConfigurationChanged() { | 264 void CapturerGdi::ScreenConfigurationChanged() { |
266 // We poll for screen configuration changes, so ignore notifications. | 265 // We poll for screen configuration changes, so ignore notifications. |
267 } | 266 } |
268 | 267 |
269 void CapturerGdi::UpdateBufferCapture(const SkISize& size) { | 268 void CapturerGdi::UpdateBufferCapture(const SkISize& size) { |
270 // Switch to the desktop receiving user input if different from the current | 269 // Switch to the desktop receiving user input if different from the current |
271 // one. | 270 // one. |
272 scoped_ptr<DesktopWin> input_desktop = DesktopWin::GetInputDesktop(); | 271 scoped_ptr<DesktopWin> input_desktop = DesktopWin::GetInputDesktop(); |
273 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { | 272 if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) { |
274 // Release GDI resources otherwise SetThreadDesktop will fail. | 273 // Release GDI resources otherwise SetThreadDesktop will fail. |
275 if (desktop_dc_) { | 274 ReleaseGdiResources(); |
276 ReleaseDC(desktop_window_, desktop_dc_); | |
277 desktop_window_ = NULL; | |
278 desktop_dc_ = NULL; | |
279 } | |
280 | |
281 if (memory_dc_) { | |
282 DeleteDC(memory_dc_); | |
283 memory_dc_ = NULL; | |
284 } | |
285 | |
286 ReleaseBuffers(); | |
287 | 275 |
288 // If SetThreadDesktop() fails, the thread is still assigned a desktop. | 276 // If SetThreadDesktop() fails, the thread is still assigned a desktop. |
289 // So we can continue capture screen bits, just from a diffented desktop. | 277 // So we can continue capture screen bits, just from a diffented desktop. |
290 desktop_.SetThreadDesktop(input_desktop.Pass()); | 278 desktop_.SetThreadDesktop(input_desktop.Pass()); |
291 } | 279 } |
292 | 280 |
293 // Make sure the DCs have the correct dimensions. | 281 // If the display dimensions have changed then recreate GDI resources. |
294 if (size != dc_size_) { | 282 if (size != dc_size_) { |
295 // TODO(simonmorris): screen dimensions changing isn't equivalent to needing | 283 ReleaseGdiResources(); |
296 // a new DC, but it's good enough for now. | |
297 if (desktop_dc_) { | |
298 ReleaseDC(desktop_window_, desktop_dc_); | |
299 desktop_window_ = NULL; | |
300 desktop_dc_ = NULL; | |
301 } | |
302 | |
303 if (memory_dc_) { | |
304 DeleteDC(memory_dc_); | |
305 memory_dc_ = NULL; | |
306 } | |
307 } | 284 } |
308 | 285 |
286 // Create GDI device contexts to capture from the desktop into memory. | |
309 if (desktop_dc_ == NULL) { | 287 if (desktop_dc_ == NULL) { |
310 DCHECK(desktop_window_ == NULL); | |
311 DCHECK(memory_dc_ == NULL); | 288 DCHECK(memory_dc_ == NULL); |
289 DCHECK(target_bitmap_[0] == NULL); | |
290 DCHECK(buffers_[0].data == NULL); | |
312 | 291 |
313 desktop_window_ = GetDesktopWindow(); | 292 desktop_dc_ = GetDC(NULL); |
314 desktop_dc_ = GetDC(desktop_window_); | |
315 memory_dc_ = CreateCompatibleDC(desktop_dc_); | 293 memory_dc_ = CreateCompatibleDC(desktop_dc_); |
316 dc_size_ = size; | 294 dc_size_ = size; |
317 } | 295 } |
318 | 296 |
319 // Make sure the current bitmap has the correct dimensions. | 297 // Make sure the current bitmap has the correct dimensions. |
320 if (buffers_[current_buffer_].data == NULL || | 298 if (buffers_[current_buffer_].data == NULL || |
321 size != buffers_[current_buffer_].size) { | 299 size != buffers_[current_buffer_].size) { |
322 ReallocateBuffer(current_buffer_, size); | 300 ReallocateBuffer(current_buffer_, size); |
alexeypa (please no reviews)
2012/07/02 15:50:11
nit: We could separate allocation and deletion of
Wez
2012/07/03 20:56:26
As discussed, we can't just tear down the buffers
| |
323 InvalidateFullScreen(); | 301 InvalidateFullScreen(); |
324 } | 302 } |
325 } | 303 } |
326 | 304 |
327 void CapturerGdi::ReallocateBuffer(int buffer_index, const SkISize& size) { | 305 void CapturerGdi::ReallocateBuffer(int buffer_index, const SkISize& size) { |
328 // Delete any previously constructed bitmap. | 306 // Delete any previously constructed bitmap. |
329 if (target_bitmap_[buffer_index]) { | 307 if (target_bitmap_[buffer_index]) { |
330 DeleteObject(target_bitmap_[buffer_index]); | 308 DeleteObject(target_bitmap_[buffer_index]); |
331 target_bitmap_[buffer_index] = NULL; | 309 target_bitmap_[buffer_index] = NULL; |
332 } | 310 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 | 402 |
425 void CapturerGdi::CaptureImage() { | 403 void CapturerGdi::CaptureImage() { |
426 // Make sure the structures we use to capture the image have the correct size. | 404 // Make sure the structures we use to capture the image have the correct size. |
427 UpdateBufferCapture(GetScreenSize()); | 405 UpdateBufferCapture(GetScreenSize()); |
428 | 406 |
429 // Select the target bitmap into the memory dc. | 407 // Select the target bitmap into the memory dc. |
430 SelectObject(memory_dc_, target_bitmap_[current_buffer_]); | 408 SelectObject(memory_dc_, target_bitmap_[current_buffer_]); |
431 | 409 |
432 // And then copy the rect from desktop to memory. | 410 // And then copy the rect from desktop to memory. |
433 BitBlt(memory_dc_, 0, 0, buffers_[current_buffer_].size.width(), | 411 BitBlt(memory_dc_, 0, 0, buffers_[current_buffer_].size.width(), |
434 buffers_[current_buffer_].size.height(), desktop_dc_, 0, 0, | 412 buffers_[current_buffer_].size.height(), desktop_dc_, |
413 GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), | |
alexeypa (please no reviews)
2012/07/02 15:50:11
There is a race between this code and CapturerGdi:
Wez
2012/07/03 20:56:26
There's no race as such, since the width & height
| |
435 SRCCOPY | CAPTUREBLT); | 414 SRCCOPY | CAPTUREBLT); |
436 } | 415 } |
437 | 416 |
438 void CapturerGdi::AddCursorOutline(int width, int height, uint32* dst) { | 417 void CapturerGdi::AddCursorOutline(int width, int height, uint32* dst) { |
439 for (int y = 0; y < height; y++) { | 418 for (int y = 0; y < height; y++) { |
440 for (int x = 0; x < width; x++) { | 419 for (int x = 0; x < width; x++) { |
441 // If this is a transparent pixel (bgr == 0 and alpha = 0), check the | 420 // If this is a transparent pixel (bgr == 0 and alpha = 0), check the |
442 // neighbor pixels to see if this should be changed to an outline pixel. | 421 // neighbor pixels to see if this should be changed to an outline pixel. |
443 if (*dst == kPixelBgraTransparent) { | 422 if (*dst == kPixelBgraTransparent) { |
444 // Change to white pixel if any neighbors (top, bottom, left, right) | 423 // Change to white pixel if any neighbors (top, bottom, left, right) |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
602 | 581 |
603 // Record the last cursor image that we sent to the client. | 582 // Record the last cursor image that we sent to the client. |
604 last_cursor_.reset(new uint8[data_size]); | 583 last_cursor_.reset(new uint8[data_size]); |
605 memcpy(last_cursor_.get(), cursor_dst_data, data_size); | 584 memcpy(last_cursor_.get(), cursor_dst_data, data_size); |
606 last_cursor_size_ = SkISize::Make(width, height); | 585 last_cursor_size_ = SkISize::Make(width, height); |
607 | 586 |
608 cursor_shape_changed_callback_.Run(cursor_proto.Pass()); | 587 cursor_shape_changed_callback_.Run(cursor_proto.Pass()); |
609 } | 588 } |
610 | 589 |
611 SkISize CapturerGdi::GetScreenSize() { | 590 SkISize CapturerGdi::GetScreenSize() { |
612 return SkISize::Make(GetSystemMetrics(SM_CXSCREEN), | 591 return SkISize::Make(GetSystemMetrics(SM_CXVIRTUALSCREEN), |
613 GetSystemMetrics(SM_CYSCREEN)); | 592 GetSystemMetrics(SM_CYVIRTUALSCREEN)); |
614 } | 593 } |
615 | 594 |
616 } // namespace | 595 } // namespace |
617 | 596 |
618 // static | 597 // static |
619 Capturer* Capturer::Create() { | 598 Capturer* Capturer::Create() { |
620 return new CapturerGdi(); | 599 return new CapturerGdi(); |
621 } | 600 } |
622 | 601 |
623 } // namespace remoting | 602 } // namespace remoting |
OLD | NEW |