OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 // SharedXDisplay::XEventHandler interface. | 59 // SharedXDisplay::XEventHandler interface. |
60 bool HandleXEvent(const XEvent& event) override; | 60 bool HandleXEvent(const XEvent& event) override; |
61 | 61 |
62 void InitXDamage(); | 62 void InitXDamage(); |
63 | 63 |
64 // Capture screen pixels to the current buffer in the queue. In the DAMAGE | 64 // Capture screen pixels to the current buffer in the queue. In the DAMAGE |
65 // case, the ScreenCapturerHelper already holds the list of invalid rectangles | 65 // case, the ScreenCapturerHelper already holds the list of invalid rectangles |
66 // from HandleXEvent(). In the non-DAMAGE case, this captures the | 66 // from HandleXEvent(). In the non-DAMAGE case, this captures the |
67 // whole screen, then calculates some invalid rectangles that include any | 67 // whole screen, then calculates some invalid rectangles that include any |
68 // differences between this and the previous capture. | 68 // differences between this and the previous capture. |
69 DesktopFrame* CaptureScreen(); | 69 std::unique_ptr<DesktopFrame> CaptureScreen(); |
70 | 70 |
71 // Called when the screen configuration is changed. | 71 // Called when the screen configuration is changed. |
72 void ScreenConfigurationChanged(); | 72 void ScreenConfigurationChanged(); |
73 | 73 |
74 // Synchronize the current buffer with |last_buffer_|, by copying pixels from | 74 // Synchronize the current buffer with |last_buffer_|, by copying pixels from |
75 // the area of |last_invalid_rects|. | 75 // the area of |last_invalid_rects|. |
76 // Note this only works on the assumption that kNumBuffers == 2, as | 76 // Note this only works on the assumption that kNumBuffers == 2, as |
77 // |last_invalid_rects| holds the differences from the previous buffer and | 77 // |last_invalid_rects| holds the differences from the previous buffer and |
78 // the one prior to that (which will then be the current buffer). | 78 // the one prior to that (which will then be the current buffer). |
79 void SynchronizeFrame(); | 79 void SynchronizeFrame(); |
80 | 80 |
81 void DeinitXlib(); | 81 void DeinitXlib(); |
82 | 82 |
83 DesktopCaptureOptions options_; | 83 DesktopCaptureOptions options_; |
84 | 84 |
85 Callback* callback_; | 85 Callback* callback_ = nullptr; |
86 | 86 |
87 // X11 graphics context. | 87 // X11 graphics context. |
88 GC gc_; | 88 GC gc_ = nullptr; |
89 Window root_window_; | 89 Window root_window_ = BadValue; |
90 | 90 |
91 // XFixes. | 91 // XFixes. |
92 bool has_xfixes_; | 92 bool has_xfixes_ = false; |
93 int xfixes_event_base_; | 93 int xfixes_event_base_ = -1; |
94 int xfixes_error_base_; | 94 int xfixes_error_base_ = -1; |
95 | 95 |
96 // XDamage information. | 96 // XDamage information. |
97 bool use_damage_; | 97 bool use_damage_ = false; |
98 Damage damage_handle_; | 98 Damage damage_handle_ = 0; |
99 int damage_event_base_; | 99 int damage_event_base_ = -1; |
100 int damage_error_base_; | 100 int damage_error_base_ = -1; |
101 XserverRegion damage_region_; | 101 XserverRegion damage_region_ = 0; |
102 | 102 |
103 // Access to the X Server's pixel buffer. | 103 // Access to the X Server's pixel buffer. |
104 XServerPixelBuffer x_server_pixel_buffer_; | 104 XServerPixelBuffer x_server_pixel_buffer_; |
105 | 105 |
106 // A thread-safe list of invalid rectangles, and the size of the most | 106 // A thread-safe list of invalid rectangles, and the size of the most |
107 // recently captured screen. | 107 // recently captured screen. |
108 ScreenCapturerHelper helper_; | 108 ScreenCapturerHelper helper_; |
109 | 109 |
110 // Queue of the frames buffers. | 110 // Queue of the frames buffers. |
111 ScreenCaptureFrameQueue<SharedDesktopFrame> queue_; | 111 ScreenCaptureFrameQueue<SharedDesktopFrame> queue_; |
112 | 112 |
113 // Invalid region from the previous capture. This is used to synchronize the | 113 // Invalid region from the previous capture. This is used to synchronize the |
114 // current with the last buffer used. | 114 // current with the last buffer used. |
115 DesktopRegion last_invalid_region_; | 115 DesktopRegion last_invalid_region_; |
116 | 116 |
117 // |Differ| for use when polling for changes. | 117 // |Differ| for use when polling for changes. |
118 std::unique_ptr<Differ> differ_; | 118 std::unique_ptr<Differ> differ_; |
119 | 119 |
120 RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); | 120 RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); |
121 }; | 121 }; |
122 | 122 |
123 ScreenCapturerLinux::ScreenCapturerLinux() | 123 ScreenCapturerLinux::ScreenCapturerLinux() { |
124 : callback_(NULL), | |
125 gc_(NULL), | |
126 root_window_(BadValue), | |
127 has_xfixes_(false), | |
128 xfixes_event_base_(-1), | |
129 xfixes_error_base_(-1), | |
130 use_damage_(false), | |
131 damage_handle_(0), | |
132 damage_event_base_(-1), | |
133 damage_error_base_(-1), | |
134 damage_region_(0) { | |
135 helper_.SetLogGridSize(4); | 124 helper_.SetLogGridSize(4); |
136 } | 125 } |
137 | 126 |
138 ScreenCapturerLinux::~ScreenCapturerLinux() { | 127 ScreenCapturerLinux::~ScreenCapturerLinux() { |
139 options_.x_display()->RemoveEventHandler(ConfigureNotify, this); | 128 options_.x_display()->RemoveEventHandler(ConfigureNotify, this); |
140 if (use_damage_) { | 129 if (use_damage_) { |
141 options_.x_display()->RemoveEventHandler( | 130 options_.x_display()->RemoveEventHandler( |
142 damage_event_base_ + XDamageNotify, this); | 131 damage_event_base_ + XDamageNotify, this); |
143 } | 132 } |
144 DeinitXlib(); | 133 DeinitXlib(); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 RTC_DCHECK(!queue_.current_frame() || !queue_.current_frame()->IsShared()); | 231 RTC_DCHECK(!queue_.current_frame() || !queue_.current_frame()->IsShared()); |
243 | 232 |
244 // Process XEvents for XDamage and cursor shape tracking. | 233 // Process XEvents for XDamage and cursor shape tracking. |
245 options_.x_display()->ProcessPendingXEvents(); | 234 options_.x_display()->ProcessPendingXEvents(); |
246 | 235 |
247 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which | 236 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which |
248 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still | 237 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still |
249 // in a good shape. | 238 // in a good shape. |
250 if (!x_server_pixel_buffer_.is_initialized()) { | 239 if (!x_server_pixel_buffer_.is_initialized()) { |
251 // We failed to initialize pixel buffer. | 240 // We failed to initialize pixel buffer. |
252 callback_->OnCaptureCompleted(NULL); | 241 callback_->OnCaptureCompleted(std::unique_ptr<DesktopFrame>()); |
253 return; | 242 return; |
254 } | 243 } |
255 | 244 |
256 // If the current frame is from an older generation then allocate a new one. | 245 // If the current frame is from an older generation then allocate a new one. |
257 // Note that we can't reallocate other buffers at this point, since the caller | 246 // Note that we can't reallocate other buffers at this point, since the caller |
258 // may still be reading from them. | 247 // may still be reading from them. |
259 if (!queue_.current_frame()) { | 248 if (!queue_.current_frame()) { |
260 std::unique_ptr<DesktopFrame> frame( | 249 queue_.ReplaceCurrentFrame( |
261 new BasicDesktopFrame(x_server_pixel_buffer_.window_size())); | 250 SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>( |
262 queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(frame.release())); | 251 new BasicDesktopFrame(x_server_pixel_buffer_.window_size())))); |
263 } | 252 } |
264 | 253 |
265 // Refresh the Differ helper used by CaptureFrame(), if needed. | 254 // Refresh the Differ helper used by CaptureFrame(), if needed. |
266 DesktopFrame* frame = queue_.current_frame(); | 255 DesktopFrame* frame = queue_.current_frame(); |
267 if (!use_damage_ && ( | 256 if (!use_damage_ && |
268 !differ_.get() || | 257 (!differ_.get() || (differ_->width() != frame->size().width()) || |
Wez
2016/05/18 01:29:50
nit: !differ_
Sergey Ulanov
2016/05/31 12:02:49
Done.
| |
269 (differ_->width() != frame->size().width()) || | 258 (differ_->height() != frame->size().height()) || |
270 (differ_->height() != frame->size().height()) || | 259 (differ_->bytes_per_row() != frame->stride()))) { |
271 (differ_->bytes_per_row() != frame->stride()))) { | |
272 differ_.reset(new Differ(frame->size().width(), frame->size().height(), | 260 differ_.reset(new Differ(frame->size().width(), frame->size().height(), |
273 DesktopFrame::kBytesPerPixel, | 261 DesktopFrame::kBytesPerPixel, frame->stride())); |
274 frame->stride())); | |
275 } | 262 } |
276 | 263 |
277 DesktopFrame* result = CaptureScreen(); | 264 std::unique_ptr<DesktopFrame> result = CaptureScreen(); |
278 last_invalid_region_ = result->updated_region(); | 265 last_invalid_region_ = result->updated_region(); |
279 result->set_capture_time_ms( | 266 result->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) / |
280 (rtc::TimeNanos() - capture_start_time_nanos) / | 267 rtc::kNumNanosecsPerMillisec); |
281 rtc::kNumNanosecsPerMillisec); | 268 callback_->OnCaptureCompleted(std::move(result)); |
282 callback_->OnCaptureCompleted(result); | |
283 } | 269 } |
284 | 270 |
285 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { | 271 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { |
286 RTC_DCHECK(screens->size() == 0); | 272 RTC_DCHECK(screens->size() == 0); |
287 // TODO(jiayl): implement screen enumeration. | 273 // TODO(jiayl): implement screen enumeration. |
288 Screen default_screen; | 274 Screen default_screen; |
289 default_screen.id = 0; | 275 default_screen.id = 0; |
290 screens->push_back(default_screen); | 276 screens->push_back(default_screen); |
291 return true; | 277 return true; |
292 } | 278 } |
(...skipping 11 matching lines...) Expand all Loading... | |
304 return false; | 290 return false; |
305 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty); | 291 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty); |
306 return true; | 292 return true; |
307 } else if (event.type == ConfigureNotify) { | 293 } else if (event.type == ConfigureNotify) { |
308 ScreenConfigurationChanged(); | 294 ScreenConfigurationChanged(); |
309 return true; | 295 return true; |
310 } | 296 } |
311 return false; | 297 return false; |
312 } | 298 } |
313 | 299 |
314 DesktopFrame* ScreenCapturerLinux::CaptureScreen() { | 300 std::unique_ptr<DesktopFrame> ScreenCapturerLinux::CaptureScreen() { |
315 DesktopFrame* frame = queue_.current_frame()->Share(); | 301 std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share(); |
316 assert(x_server_pixel_buffer_.window_size().equals(frame->size())); | 302 assert(x_server_pixel_buffer_.window_size().equals(frame->size())); |
317 | 303 |
318 // Pass the screen size to the helper, so it can clip the invalid region if it | 304 // Pass the screen size to the helper, so it can clip the invalid region if it |
319 // expands that region to a grid. | 305 // expands that region to a grid. |
320 helper_.set_size_most_recent(frame->size()); | 306 helper_.set_size_most_recent(frame->size()); |
321 | 307 |
322 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame | 308 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame |
323 // if any. If there isn't a previous frame, that means a screen-resolution | 309 // if any. If there isn't a previous frame, that means a screen-resolution |
324 // change occurred, and |invalid_rects| will be updated to include the whole | 310 // change occurred, and |invalid_rects| will be updated to include the whole |
325 // screen. | 311 // screen. |
(...skipping 21 matching lines...) Expand all Loading... | |
347 helper_.TakeInvalidRegion(updated_region); | 333 helper_.TakeInvalidRegion(updated_region); |
348 | 334 |
349 // Clip the damaged portions to the current screen size, just in case some | 335 // Clip the damaged portions to the current screen size, just in case some |
350 // spurious XDamage notifications were received for a previous (larger) | 336 // spurious XDamage notifications were received for a previous (larger) |
351 // screen size. | 337 // screen size. |
352 updated_region->IntersectWith( | 338 updated_region->IntersectWith( |
353 DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); | 339 DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); |
354 | 340 |
355 for (DesktopRegion::Iterator it(*updated_region); | 341 for (DesktopRegion::Iterator it(*updated_region); |
356 !it.IsAtEnd(); it.Advance()) { | 342 !it.IsAtEnd(); it.Advance()) { |
357 x_server_pixel_buffer_.CaptureRect(it.rect(), frame); | 343 x_server_pixel_buffer_.CaptureRect(it.rect(), frame.get()); |
358 } | 344 } |
359 } else { | 345 } else { |
360 // Doing full-screen polling, or this is the first capture after a | 346 // Doing full-screen polling, or this is the first capture after a |
361 // screen-resolution change. In either case, need a full-screen capture. | 347 // screen-resolution change. In either case, need a full-screen capture. |
362 DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); | 348 DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); |
363 x_server_pixel_buffer_.CaptureRect(screen_rect, frame); | 349 x_server_pixel_buffer_.CaptureRect(screen_rect, frame.get()); |
364 | 350 |
365 if (queue_.previous_frame()) { | 351 if (queue_.previous_frame()) { |
366 // Full-screen polling, so calculate the invalid rects here, based on the | 352 // Full-screen polling, so calculate the invalid rects here, based on the |
367 // changed pixels between current and previous buffers. | 353 // changed pixels between current and previous buffers. |
368 RTC_DCHECK(differ_.get() != NULL); | 354 RTC_DCHECK(differ_); |
369 RTC_DCHECK(queue_.previous_frame()->data()); | 355 RTC_DCHECK(queue_.previous_frame()->data()); |
370 differ_->CalcDirtyRegion(queue_.previous_frame()->data(), | 356 differ_->CalcDirtyRegion(queue_.previous_frame()->data(), |
371 frame->data(), updated_region); | 357 frame->data(), updated_region); |
372 } else { | 358 } else { |
373 // No previous buffer, so always invalidate the whole screen, whether | 359 // No previous buffer, so always invalidate the whole screen, whether |
374 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a | 360 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a |
375 // full-screen notification after a screen-resolution change, so | 361 // full-screen notification after a screen-resolution change, so |
376 // this is done here. | 362 // this is done here. |
377 updated_region->SetRect(screen_rect); | 363 updated_region->SetRect(screen_rect); |
378 } | 364 } |
379 } | 365 } |
380 | 366 |
381 return frame; | 367 return std::move(frame); |
382 } | 368 } |
383 | 369 |
384 void ScreenCapturerLinux::ScreenConfigurationChanged() { | 370 void ScreenCapturerLinux::ScreenConfigurationChanged() { |
385 // Make sure the frame buffers will be reallocated. | 371 // Make sure the frame buffers will be reallocated. |
386 queue_.Reset(); | 372 queue_.Reset(); |
387 | 373 |
388 helper_.ClearInvalidRegion(); | 374 helper_.ClearInvalidRegion(); |
389 if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { | 375 if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { |
390 LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " | 376 LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " |
391 "configuration change."; | 377 "configuration change."; |
(...skipping 16 matching lines...) Expand all Loading... | |
408 RTC_DCHECK(current != last); | 394 RTC_DCHECK(current != last); |
409 for (DesktopRegion::Iterator it(last_invalid_region_); | 395 for (DesktopRegion::Iterator it(last_invalid_region_); |
410 !it.IsAtEnd(); it.Advance()) { | 396 !it.IsAtEnd(); it.Advance()) { |
411 current->CopyPixelsFrom(*last, it.rect().top_left(), it.rect()); | 397 current->CopyPixelsFrom(*last, it.rect().top_left(), it.rect()); |
412 } | 398 } |
413 } | 399 } |
414 | 400 |
415 void ScreenCapturerLinux::DeinitXlib() { | 401 void ScreenCapturerLinux::DeinitXlib() { |
416 if (gc_) { | 402 if (gc_) { |
417 XFreeGC(display(), gc_); | 403 XFreeGC(display(), gc_); |
418 gc_ = NULL; | 404 gc_ = nullptr; |
419 } | 405 } |
420 | 406 |
421 x_server_pixel_buffer_.Release(); | 407 x_server_pixel_buffer_.Release(); |
422 | 408 |
423 if (display()) { | 409 if (display()) { |
424 if (damage_handle_) { | 410 if (damage_handle_) { |
425 XDamageDestroy(display(), damage_handle_); | 411 XDamageDestroy(display(), damage_handle_); |
426 damage_handle_ = 0; | 412 damage_handle_ = 0; |
427 } | 413 } |
428 | 414 |
429 if (damage_region_) { | 415 if (damage_region_) { |
430 XFixesDestroyRegion(display(), damage_region_); | 416 XFixesDestroyRegion(display(), damage_region_); |
431 damage_region_ = 0; | 417 damage_region_ = 0; |
432 } | 418 } |
433 } | 419 } |
434 } | 420 } |
435 | 421 |
436 } // namespace | 422 } // namespace |
437 | 423 |
438 // static | 424 // static |
439 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { | 425 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { |
440 if (!options.x_display()) | 426 if (!options.x_display()) |
441 return NULL; | 427 return nullptr; |
442 | 428 |
443 std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); | 429 std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); |
444 if (!capturer->Init(options)) | 430 if (!capturer->Init(options)) |
445 capturer.reset(); | 431 capturer.reset(); |
446 return capturer.release(); | 432 return capturer.release(); |
447 } | 433 } |
448 | 434 |
449 } // namespace webrtc | 435 } // namespace webrtc |
OLD | NEW |