| 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 std::unique_ptr<DesktopFrame> CaptureScreen(); | 69 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_ = nullptr; | 85 Callback* callback_; |
| 86 | 86 |
| 87 // X11 graphics context. | 87 // X11 graphics context. |
| 88 GC gc_ = nullptr; | 88 GC gc_; |
| 89 Window root_window_ = BadValue; | 89 Window root_window_; |
| 90 | 90 |
| 91 // XFixes. | 91 // XFixes. |
| 92 bool has_xfixes_ = false; | 92 bool has_xfixes_; |
| 93 int xfixes_event_base_ = -1; | 93 int xfixes_event_base_; |
| 94 int xfixes_error_base_ = -1; | 94 int xfixes_error_base_; |
| 95 | 95 |
| 96 // XDamage information. | 96 // XDamage information. |
| 97 bool use_damage_ = false; | 97 bool use_damage_; |
| 98 Damage damage_handle_ = 0; | 98 Damage damage_handle_; |
| 99 int damage_event_base_ = -1; | 99 int damage_event_base_; |
| 100 int damage_error_base_ = -1; | 100 int damage_error_base_; |
| 101 XserverRegion damage_region_ = 0; | 101 XserverRegion damage_region_; |
| 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) { |
| 124 helper_.SetLogGridSize(4); | 135 helper_.SetLogGridSize(4); |
| 125 } | 136 } |
| 126 | 137 |
| 127 ScreenCapturerLinux::~ScreenCapturerLinux() { | 138 ScreenCapturerLinux::~ScreenCapturerLinux() { |
| 128 options_.x_display()->RemoveEventHandler(ConfigureNotify, this); | 139 options_.x_display()->RemoveEventHandler(ConfigureNotify, this); |
| 129 if (use_damage_) { | 140 if (use_damage_) { |
| 130 options_.x_display()->RemoveEventHandler( | 141 options_.x_display()->RemoveEventHandler( |
| 131 damage_event_base_ + XDamageNotify, this); | 142 damage_event_base_ + XDamageNotify, this); |
| 132 } | 143 } |
| 133 DeinitXlib(); | 144 DeinitXlib(); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 RTC_DCHECK(!queue_.current_frame() || !queue_.current_frame()->IsShared()); | 242 RTC_DCHECK(!queue_.current_frame() || !queue_.current_frame()->IsShared()); |
| 232 | 243 |
| 233 // Process XEvents for XDamage and cursor shape tracking. | 244 // Process XEvents for XDamage and cursor shape tracking. |
| 234 options_.x_display()->ProcessPendingXEvents(); | 245 options_.x_display()->ProcessPendingXEvents(); |
| 235 | 246 |
| 236 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which | 247 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which |
| 237 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still | 248 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still |
| 238 // in a good shape. | 249 // in a good shape. |
| 239 if (!x_server_pixel_buffer_.is_initialized()) { | 250 if (!x_server_pixel_buffer_.is_initialized()) { |
| 240 // We failed to initialize pixel buffer. | 251 // We failed to initialize pixel buffer. |
| 241 callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); | 252 callback_->OnCaptureCompleted(NULL); |
| 242 return; | 253 return; |
| 243 } | 254 } |
| 244 | 255 |
| 245 // If the current frame is from an older generation then allocate a new one. | 256 // If the current frame is from an older generation then allocate a new one. |
| 246 // Note that we can't reallocate other buffers at this point, since the caller | 257 // Note that we can't reallocate other buffers at this point, since the caller |
| 247 // may still be reading from them. | 258 // may still be reading from them. |
| 248 if (!queue_.current_frame()) { | 259 if (!queue_.current_frame()) { |
| 249 queue_.ReplaceCurrentFrame( | 260 std::unique_ptr<DesktopFrame> frame( |
| 250 SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>( | 261 new BasicDesktopFrame(x_server_pixel_buffer_.window_size())); |
| 251 new BasicDesktopFrame(x_server_pixel_buffer_.window_size())))); | 262 queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(frame.release())); |
| 252 } | 263 } |
| 253 | 264 |
| 254 // Refresh the Differ helper used by CaptureFrame(), if needed. | 265 // Refresh the Differ helper used by CaptureFrame(), if needed. |
| 255 DesktopFrame* frame = queue_.current_frame(); | 266 DesktopFrame* frame = queue_.current_frame(); |
| 256 if (!use_damage_ && | 267 if (!use_damage_ && ( |
| 257 (!differ_ || (differ_->width() != frame->size().width()) || | 268 !differ_.get() || |
| 258 (differ_->height() != frame->size().height()) || | 269 (differ_->width() != frame->size().width()) || |
| 259 (differ_->bytes_per_row() != frame->stride()))) { | 270 (differ_->height() != frame->size().height()) || |
| 271 (differ_->bytes_per_row() != frame->stride()))) { |
| 260 differ_.reset(new Differ(frame->size().width(), frame->size().height(), | 272 differ_.reset(new Differ(frame->size().width(), frame->size().height(), |
| 261 DesktopFrame::kBytesPerPixel, frame->stride())); | 273 DesktopFrame::kBytesPerPixel, |
| 274 frame->stride())); |
| 262 } | 275 } |
| 263 | 276 |
| 264 std::unique_ptr<DesktopFrame> result = CaptureScreen(); | 277 DesktopFrame* result = CaptureScreen(); |
| 265 last_invalid_region_ = result->updated_region(); | 278 last_invalid_region_ = result->updated_region(); |
| 266 result->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) / | 279 result->set_capture_time_ms( |
| 267 rtc::kNumNanosecsPerMillisec); | 280 (rtc::TimeNanos() - capture_start_time_nanos) / |
| 268 callback_->OnCaptureResult(Result::SUCCESS, std::move(result)); | 281 rtc::kNumNanosecsPerMillisec); |
| 282 callback_->OnCaptureCompleted(result); |
| 269 } | 283 } |
| 270 | 284 |
| 271 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { | 285 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { |
| 272 RTC_DCHECK(screens->size() == 0); | 286 RTC_DCHECK(screens->size() == 0); |
| 273 // TODO(jiayl): implement screen enumeration. | 287 // TODO(jiayl): implement screen enumeration. |
| 274 Screen default_screen; | 288 Screen default_screen; |
| 275 default_screen.id = 0; | 289 default_screen.id = 0; |
| 276 screens->push_back(default_screen); | 290 screens->push_back(default_screen); |
| 277 return true; | 291 return true; |
| 278 } | 292 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 290 return false; | 304 return false; |
| 291 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty); | 305 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty); |
| 292 return true; | 306 return true; |
| 293 } else if (event.type == ConfigureNotify) { | 307 } else if (event.type == ConfigureNotify) { |
| 294 ScreenConfigurationChanged(); | 308 ScreenConfigurationChanged(); |
| 295 return true; | 309 return true; |
| 296 } | 310 } |
| 297 return false; | 311 return false; |
| 298 } | 312 } |
| 299 | 313 |
| 300 std::unique_ptr<DesktopFrame> ScreenCapturerLinux::CaptureScreen() { | 314 DesktopFrame* ScreenCapturerLinux::CaptureScreen() { |
| 301 std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share(); | 315 DesktopFrame* frame = queue_.current_frame()->Share(); |
| 302 assert(x_server_pixel_buffer_.window_size().equals(frame->size())); | 316 assert(x_server_pixel_buffer_.window_size().equals(frame->size())); |
| 303 | 317 |
| 304 // Pass the screen size to the helper, so it can clip the invalid region if it | 318 // Pass the screen size to the helper, so it can clip the invalid region if it |
| 305 // expands that region to a grid. | 319 // expands that region to a grid. |
| 306 helper_.set_size_most_recent(frame->size()); | 320 helper_.set_size_most_recent(frame->size()); |
| 307 | 321 |
| 308 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame | 322 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame |
| 309 // if any. If there isn't a previous frame, that means a screen-resolution | 323 // if any. If there isn't a previous frame, that means a screen-resolution |
| 310 // change occurred, and |invalid_rects| will be updated to include the whole | 324 // change occurred, and |invalid_rects| will be updated to include the whole |
| 311 // screen. | 325 // screen. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 333 helper_.TakeInvalidRegion(updated_region); | 347 helper_.TakeInvalidRegion(updated_region); |
| 334 | 348 |
| 335 // Clip the damaged portions to the current screen size, just in case some | 349 // Clip the damaged portions to the current screen size, just in case some |
| 336 // spurious XDamage notifications were received for a previous (larger) | 350 // spurious XDamage notifications were received for a previous (larger) |
| 337 // screen size. | 351 // screen size. |
| 338 updated_region->IntersectWith( | 352 updated_region->IntersectWith( |
| 339 DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); | 353 DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); |
| 340 | 354 |
| 341 for (DesktopRegion::Iterator it(*updated_region); | 355 for (DesktopRegion::Iterator it(*updated_region); |
| 342 !it.IsAtEnd(); it.Advance()) { | 356 !it.IsAtEnd(); it.Advance()) { |
| 343 x_server_pixel_buffer_.CaptureRect(it.rect(), frame.get()); | 357 x_server_pixel_buffer_.CaptureRect(it.rect(), frame); |
| 344 } | 358 } |
| 345 } else { | 359 } else { |
| 346 // Doing full-screen polling, or this is the first capture after a | 360 // Doing full-screen polling, or this is the first capture after a |
| 347 // screen-resolution change. In either case, need a full-screen capture. | 361 // screen-resolution change. In either case, need a full-screen capture. |
| 348 DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); | 362 DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); |
| 349 x_server_pixel_buffer_.CaptureRect(screen_rect, frame.get()); | 363 x_server_pixel_buffer_.CaptureRect(screen_rect, frame); |
| 350 | 364 |
| 351 if (queue_.previous_frame()) { | 365 if (queue_.previous_frame()) { |
| 352 // Full-screen polling, so calculate the invalid rects here, based on the | 366 // Full-screen polling, so calculate the invalid rects here, based on the |
| 353 // changed pixels between current and previous buffers. | 367 // changed pixels between current and previous buffers. |
| 354 RTC_DCHECK(differ_); | 368 RTC_DCHECK(differ_.get() != NULL); |
| 355 RTC_DCHECK(queue_.previous_frame()->data()); | 369 RTC_DCHECK(queue_.previous_frame()->data()); |
| 356 differ_->CalcDirtyRegion(queue_.previous_frame()->data(), | 370 differ_->CalcDirtyRegion(queue_.previous_frame()->data(), |
| 357 frame->data(), updated_region); | 371 frame->data(), updated_region); |
| 358 } else { | 372 } else { |
| 359 // No previous buffer, so always invalidate the whole screen, whether | 373 // No previous buffer, so always invalidate the whole screen, whether |
| 360 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a | 374 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a |
| 361 // full-screen notification after a screen-resolution change, so | 375 // full-screen notification after a screen-resolution change, so |
| 362 // this is done here. | 376 // this is done here. |
| 363 updated_region->SetRect(screen_rect); | 377 updated_region->SetRect(screen_rect); |
| 364 } | 378 } |
| 365 } | 379 } |
| 366 | 380 |
| 367 return std::move(frame); | 381 return frame; |
| 368 } | 382 } |
| 369 | 383 |
| 370 void ScreenCapturerLinux::ScreenConfigurationChanged() { | 384 void ScreenCapturerLinux::ScreenConfigurationChanged() { |
| 371 // Make sure the frame buffers will be reallocated. | 385 // Make sure the frame buffers will be reallocated. |
| 372 queue_.Reset(); | 386 queue_.Reset(); |
| 373 | 387 |
| 374 helper_.ClearInvalidRegion(); | 388 helper_.ClearInvalidRegion(); |
| 375 if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { | 389 if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { |
| 376 LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " | 390 LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " |
| 377 "configuration change."; | 391 "configuration change."; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 394 RTC_DCHECK(current != last); | 408 RTC_DCHECK(current != last); |
| 395 for (DesktopRegion::Iterator it(last_invalid_region_); | 409 for (DesktopRegion::Iterator it(last_invalid_region_); |
| 396 !it.IsAtEnd(); it.Advance()) { | 410 !it.IsAtEnd(); it.Advance()) { |
| 397 current->CopyPixelsFrom(*last, it.rect().top_left(), it.rect()); | 411 current->CopyPixelsFrom(*last, it.rect().top_left(), it.rect()); |
| 398 } | 412 } |
| 399 } | 413 } |
| 400 | 414 |
| 401 void ScreenCapturerLinux::DeinitXlib() { | 415 void ScreenCapturerLinux::DeinitXlib() { |
| 402 if (gc_) { | 416 if (gc_) { |
| 403 XFreeGC(display(), gc_); | 417 XFreeGC(display(), gc_); |
| 404 gc_ = nullptr; | 418 gc_ = NULL; |
| 405 } | 419 } |
| 406 | 420 |
| 407 x_server_pixel_buffer_.Release(); | 421 x_server_pixel_buffer_.Release(); |
| 408 | 422 |
| 409 if (display()) { | 423 if (display()) { |
| 410 if (damage_handle_) { | 424 if (damage_handle_) { |
| 411 XDamageDestroy(display(), damage_handle_); | 425 XDamageDestroy(display(), damage_handle_); |
| 412 damage_handle_ = 0; | 426 damage_handle_ = 0; |
| 413 } | 427 } |
| 414 | 428 |
| 415 if (damage_region_) { | 429 if (damage_region_) { |
| 416 XFixesDestroyRegion(display(), damage_region_); | 430 XFixesDestroyRegion(display(), damage_region_); |
| 417 damage_region_ = 0; | 431 damage_region_ = 0; |
| 418 } | 432 } |
| 419 } | 433 } |
| 420 } | 434 } |
| 421 | 435 |
| 422 } // namespace | 436 } // namespace |
| 423 | 437 |
| 424 // static | 438 // static |
| 425 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { | 439 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { |
| 426 if (!options.x_display()) | 440 if (!options.x_display()) |
| 427 return nullptr; | 441 return NULL; |
| 428 | 442 |
| 429 std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); | 443 std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); |
| 430 if (!capturer->Init(options)) | 444 if (!capturer->Init(options)) |
| 431 capturer.reset(); | 445 capturer.reset(); |
| 432 return capturer.release(); | 446 return capturer.release(); |
| 433 } | 447 } |
| 434 | 448 |
| 435 } // namespace webrtc | 449 } // namespace webrtc |
| OLD | NEW |