| 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 <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/Xutil.h> | 8 #include <X11/Xutil.h> |
| 9 #include <X11/extensions/Xdamage.h> | 9 #include <X11/extensions/Xdamage.h> |
| 10 #include <X11/extensions/Xfixes.h> | 10 #include <X11/extensions/Xfixes.h> |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 | 76 |
| 77 // A class to perform video frame capturing for Linux. | 77 // A class to perform video frame capturing for Linux. |
| 78 class VideoFrameCapturerLinux : public VideoFrameCapturer { | 78 class VideoFrameCapturerLinux : public VideoFrameCapturer { |
| 79 public: | 79 public: |
| 80 VideoFrameCapturerLinux(); | 80 VideoFrameCapturerLinux(); |
| 81 virtual ~VideoFrameCapturerLinux(); | 81 virtual ~VideoFrameCapturerLinux(); |
| 82 | 82 |
| 83 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? | 83 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? |
| 84 | 84 |
| 85 // Capturer interface. | 85 // Capturer interface. |
| 86 virtual void Start(const CursorShapeChangedCallback& callback) OVERRIDE; | 86 virtual void Start(Delegate* delegate) OVERRIDE; |
| 87 virtual void Stop() OVERRIDE; | 87 virtual void Stop() OVERRIDE; |
| 88 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; | 88 virtual media::VideoFrame::Format pixel_format() const OVERRIDE; |
| 89 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; | 89 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; |
| 90 virtual void CaptureInvalidRegion( | 90 virtual void CaptureInvalidRegion() OVERRIDE; |
| 91 const CaptureCompletedCallback& callback) OVERRIDE; | |
| 92 virtual const SkISize& size_most_recent() const OVERRIDE; | 91 virtual const SkISize& size_most_recent() const OVERRIDE; |
| 93 | 92 |
| 94 private: | 93 private: |
| 95 void InitXDamage(); | 94 void InitXDamage(); |
| 96 | 95 |
| 97 // Read and handle all currently-pending XEvents. | 96 // Read and handle all currently-pending XEvents. |
| 98 // In the DAMAGE case, process the XDamage events and store the resulting | 97 // In the DAMAGE case, process the XDamage events and store the resulting |
| 99 // damage rectangles in the VideoFrameCapturerHelper. | 98 // damage rectangles in the VideoFrameCapturerHelper. |
| 100 // In all cases, call ScreenConfigurationChanged() in response to any | 99 // In all cases, call ScreenConfigurationChanged() in response to any |
| 101 // ConfigNotify events. | 100 // ConfigNotify events. |
| 102 void ProcessPendingXEvents(); | 101 void ProcessPendingXEvents(); |
| 103 | 102 |
| 104 // Capture screen pixels, and return the data in a new CaptureData object, | 103 // Capture screen pixels, and return the data in a new CaptureData object, |
| 105 // to be freed by the caller. | 104 // to be freed by the caller. |
| 106 // In the DAMAGE case, the VideoFrameCapturerHelper already holds the list of | 105 // In the DAMAGE case, the VideoFrameCapturerHelper already holds the list of |
| 107 // invalid rectangles from ProcessPendingXEvents(). | 106 // invalid rectangles from ProcessPendingXEvents(). |
| 108 // In the non-DAMAGE case, this captures the whole screen, then calculates | 107 // In the non-DAMAGE case, this captures the whole screen, then calculates |
| 109 // some invalid rectangles that include any differences between this and the | 108 // some invalid rectangles that include any differences between this and the |
| 110 // previous capture. | 109 // previous capture. |
| 111 CaptureData* CaptureFrame(); | 110 CaptureData* CaptureFrame(); |
| 112 | 111 |
| 113 // Capture the cursor image and call the CursorShapeChangedCallback if it | 112 // Capture the cursor image and notify the delegate if it was captured. |
| 114 // has been set (using SetCursorShapeChangedCallback). | |
| 115 void CaptureCursor(); | 113 void CaptureCursor(); |
| 116 | 114 |
| 117 // Called when the screen configuration is changed. | 115 // Called when the screen configuration is changed. |
| 118 void ScreenConfigurationChanged(); | 116 void ScreenConfigurationChanged(); |
| 119 | 117 |
| 120 // Synchronize the current buffer with |last_buffer_|, by copying pixels from | 118 // Synchronize the current buffer with |last_buffer_|, by copying pixels from |
| 121 // the area of |last_invalid_rects|. | 119 // the area of |last_invalid_rects|. |
| 122 // Note this only works on the assumption that kNumBuffers == 2, as | 120 // Note this only works on the assumption that kNumBuffers == 2, as |
| 123 // |last_invalid_rects| holds the differences from the previous buffer and | 121 // |last_invalid_rects| holds the differences from the previous buffer and |
| 124 // the one prior to that (which will then be the current buffer). | 122 // the one prior to that (which will then be the current buffer). |
| 125 void SynchronizeFrame(); | 123 void SynchronizeFrame(); |
| 126 | 124 |
| 127 void DeinitXlib(); | 125 void DeinitXlib(); |
| 128 | 126 |
| 129 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into | 127 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into |
| 130 // |capture_data|. | 128 // |capture_data|. |
| 131 void CaptureRect(const SkIRect& rect, CaptureData* capture_data); | 129 void CaptureRect(const SkIRect& rect, CaptureData* capture_data); |
| 132 | 130 |
| 133 // We expose two forms of blitting to handle variations in the pixel format. | 131 // We expose two forms of blitting to handle variations in the pixel format. |
| 134 // In FastBlit, the operation is effectively a memcpy. | 132 // In FastBlit, the operation is effectively a memcpy. |
| 135 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); | 133 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); |
| 136 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); | 134 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); |
| 137 | 135 |
| 136 Delegate* delegate_; |
| 137 |
| 138 // X11 graphics context. | 138 // X11 graphics context. |
| 139 Display* display_; | 139 Display* display_; |
| 140 GC gc_; | 140 GC gc_; |
| 141 Window root_window_; | 141 Window root_window_; |
| 142 | 142 |
| 143 // XFixes. | 143 // XFixes. |
| 144 bool has_xfixes_; | 144 bool has_xfixes_; |
| 145 int xfixes_event_base_; | 145 int xfixes_event_base_; |
| 146 int xfixes_error_base_; | 146 int xfixes_error_base_; |
| 147 | 147 |
| 148 // XDamage information. | 148 // XDamage information. |
| 149 bool use_damage_; | 149 bool use_damage_; |
| 150 Damage damage_handle_; | 150 Damage damage_handle_; |
| 151 int damage_event_base_; | 151 int damage_event_base_; |
| 152 int damage_error_base_; | 152 int damage_error_base_; |
| 153 XserverRegion damage_region_; | 153 XserverRegion damage_region_; |
| 154 | 154 |
| 155 // Access to the X Server's pixel buffer. | 155 // Access to the X Server's pixel buffer. |
| 156 XServerPixelBuffer x_server_pixel_buffer_; | 156 XServerPixelBuffer x_server_pixel_buffer_; |
| 157 | 157 |
| 158 // A thread-safe list of invalid rectangles, and the size of the most | 158 // A thread-safe list of invalid rectangles, and the size of the most |
| 159 // recently captured screen. | 159 // recently captured screen. |
| 160 VideoFrameCapturerHelper helper_; | 160 VideoFrameCapturerHelper helper_; |
| 161 | 161 |
| 162 // Callback notified whenever the cursor shape is changed. | |
| 163 CursorShapeChangedCallback cursor_shape_changed_callback_; | |
| 164 | |
| 165 // Capture state. | 162 // Capture state. |
| 166 static const int kNumBuffers = 2; | 163 static const int kNumBuffers = 2; |
| 167 VideoFrameBuffer buffers_[kNumBuffers]; | 164 VideoFrameBuffer buffers_[kNumBuffers]; |
| 168 int current_buffer_; | 165 int current_buffer_; |
| 169 | 166 |
| 170 // Format of pixels returned in buffer. | 167 // Format of pixels returned in buffer. |
| 171 media::VideoFrame::Format pixel_format_; | 168 media::VideoFrame::Format pixel_format_; |
| 172 | 169 |
| 173 // Invalid region from the previous capture. This is used to synchronize the | 170 // Invalid region from the previous capture. This is used to synchronize the |
| 174 // current with the last buffer used. | 171 // current with the last buffer used. |
| 175 SkRegion last_invalid_region_; | 172 SkRegion last_invalid_region_; |
| 176 | 173 |
| 177 // Last capture buffer used. | 174 // Last capture buffer used. |
| 178 int last_buffer_; | 175 int last_buffer_; |
| 179 | 176 |
| 180 // |Differ| for use when polling for changes. | 177 // |Differ| for use when polling for changes. |
| 181 scoped_ptr<Differ> differ_; | 178 scoped_ptr<Differ> differ_; |
| 182 | 179 |
| 183 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerLinux); | 180 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerLinux); |
| 184 }; | 181 }; |
| 185 | 182 |
| 186 VideoFrameCapturerLinux::VideoFrameCapturerLinux() | 183 VideoFrameCapturerLinux::VideoFrameCapturerLinux() |
| 187 : display_(NULL), | 184 : delegate_(NULL), |
| 185 display_(NULL), |
| 188 gc_(NULL), | 186 gc_(NULL), |
| 189 root_window_(BadValue), | 187 root_window_(BadValue), |
| 190 has_xfixes_(false), | 188 has_xfixes_(false), |
| 191 xfixes_event_base_(-1), | 189 xfixes_event_base_(-1), |
| 192 xfixes_error_base_(-1), | 190 xfixes_error_base_(-1), |
| 193 use_damage_(false), | 191 use_damage_(false), |
| 194 damage_handle_(0), | 192 damage_handle_(0), |
| 195 damage_event_base_(-1), | 193 damage_event_base_(-1), |
| 196 damage_error_base_(-1), | 194 damage_error_base_(-1), |
| 197 damage_region_(0), | 195 damage_region_(0), |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 if (!damage_region_) { | 284 if (!damage_region_) { |
| 287 XDamageDestroy(display_, damage_handle_); | 285 XDamageDestroy(display_, damage_handle_); |
| 288 LOG(ERROR) << "Unable to create XFixes region."; | 286 LOG(ERROR) << "Unable to create XFixes region."; |
| 289 return; | 287 return; |
| 290 } | 288 } |
| 291 | 289 |
| 292 use_damage_ = true; | 290 use_damage_ = true; |
| 293 LOG(INFO) << "Using XDamage extension."; | 291 LOG(INFO) << "Using XDamage extension."; |
| 294 } | 292 } |
| 295 | 293 |
| 296 void VideoFrameCapturerLinux::Start( | 294 void VideoFrameCapturerLinux::Start(Delegate* delegate) { |
| 297 const CursorShapeChangedCallback& callback) { | 295 DCHECK(delegate_ == NULL); |
| 298 cursor_shape_changed_callback_ = callback; | 296 |
| 297 delegate_ = delegate; |
| 299 } | 298 } |
| 300 | 299 |
| 301 void VideoFrameCapturerLinux::Stop() { | 300 void VideoFrameCapturerLinux::Stop() { |
| 302 } | 301 } |
| 303 | 302 |
| 304 media::VideoFrame::Format VideoFrameCapturerLinux::pixel_format() const { | 303 media::VideoFrame::Format VideoFrameCapturerLinux::pixel_format() const { |
| 305 return pixel_format_; | 304 return pixel_format_; |
| 306 } | 305 } |
| 307 | 306 |
| 308 void VideoFrameCapturerLinux::InvalidateRegion(const SkRegion& invalid_region) { | 307 void VideoFrameCapturerLinux::InvalidateRegion(const SkRegion& invalid_region) { |
| 309 helper_.InvalidateRegion(invalid_region); | 308 helper_.InvalidateRegion(invalid_region); |
| 310 } | 309 } |
| 311 | 310 |
| 312 void VideoFrameCapturerLinux::CaptureInvalidRegion( | 311 void VideoFrameCapturerLinux::CaptureInvalidRegion() { |
| 313 const CaptureCompletedCallback& callback) { | |
| 314 // Process XEvents for XDamage and cursor shape tracking. | 312 // Process XEvents for XDamage and cursor shape tracking. |
| 315 ProcessPendingXEvents(); | 313 ProcessPendingXEvents(); |
| 316 | 314 |
| 317 // Resize the current buffer if there was a recent change of | 315 // Resize the current buffer if there was a recent change of |
| 318 // screen-resolution. | 316 // screen-resolution. |
| 319 VideoFrameBuffer ¤t = buffers_[current_buffer_]; | 317 VideoFrameBuffer ¤t = buffers_[current_buffer_]; |
| 320 current.Update(display_, root_window_); | 318 current.Update(display_, root_window_); |
| 321 | 319 |
| 322 // Mark the previous frame for update if its dimensions no longer match. | 320 // Mark the previous frame for update if its dimensions no longer match. |
| 323 if (buffers_[last_buffer_].size() != current.size()) { | 321 if (buffers_[last_buffer_].size() != current.size()) { |
| 324 buffers_[last_buffer_].set_needs_update(); | 322 buffers_[last_buffer_].set_needs_update(); |
| 325 | 323 |
| 326 // Also refresh the Differ helper used by CaptureFrame(), if needed. | 324 // Also refresh the Differ helper used by CaptureFrame(), if needed. |
| 327 if (!use_damage_) { | 325 if (!use_damage_) { |
| 328 differ_.reset(new Differ(current.size().width(), current.size().height(), | 326 differ_.reset(new Differ(current.size().width(), current.size().height(), |
| 329 kBytesPerPixel, current.bytes_per_row())); | 327 kBytesPerPixel, current.bytes_per_row())); |
| 330 } | 328 } |
| 331 } | 329 } |
| 332 | 330 |
| 333 scoped_refptr<CaptureData> capture_data(CaptureFrame()); | 331 scoped_refptr<CaptureData> capture_data(CaptureFrame()); |
| 334 | 332 |
| 335 // Swap the current & previous buffers ready for the next capture. | 333 // Swap the current & previous buffers ready for the next capture. |
| 336 last_invalid_region_ = capture_data->dirty_region(); | 334 last_invalid_region_ = capture_data->dirty_region(); |
| 337 last_buffer_ = current_buffer_; | 335 last_buffer_ = current_buffer_; |
| 338 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; | 336 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; |
| 339 | 337 |
| 340 callback.Run(capture_data); | 338 delegate_->OnCaptureCompleted(capture_data); |
| 341 } | 339 } |
| 342 | 340 |
| 343 void VideoFrameCapturerLinux::ProcessPendingXEvents() { | 341 void VideoFrameCapturerLinux::ProcessPendingXEvents() { |
| 344 // Find the number of events that are outstanding "now." We don't just loop | 342 // Find the number of events that are outstanding "now." We don't just loop |
| 345 // on XPending because we want to guarantee this terminates. | 343 // on XPending because we want to guarantee this terminates. |
| 346 int events_to_process = XPending(display_); | 344 int events_to_process = XPending(display_); |
| 347 XEvent e; | 345 XEvent e; |
| 348 | 346 |
| 349 for (int i = 0; i < events_to_process; i++) { | 347 for (int i = 0; i < events_to_process; i++) { |
| 350 XNextEvent(display_, &e); | 348 XNextEvent(display_, &e); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 361 CaptureCursor(); | 359 CaptureCursor(); |
| 362 } | 360 } |
| 363 } else { | 361 } else { |
| 364 LOG(WARNING) << "Got unknown event type: " << e.type; | 362 LOG(WARNING) << "Got unknown event type: " << e.type; |
| 365 } | 363 } |
| 366 } | 364 } |
| 367 } | 365 } |
| 368 | 366 |
| 369 void VideoFrameCapturerLinux::CaptureCursor() { | 367 void VideoFrameCapturerLinux::CaptureCursor() { |
| 370 DCHECK(has_xfixes_); | 368 DCHECK(has_xfixes_); |
| 371 if (cursor_shape_changed_callback_.is_null()) | |
| 372 return; | |
| 373 | 369 |
| 374 XFixesCursorImage* img = XFixesGetCursorImage(display_); | 370 XFixesCursorImage* img = XFixesGetCursorImage(display_); |
| 375 if (!img) { | 371 if (!img) { |
| 376 return; | 372 return; |
| 377 } | 373 } |
| 378 | 374 |
| 379 int width = img->width; | 375 int width = img->width; |
| 380 int height = img->height; | 376 int height = img->height; |
| 381 int total_bytes = width * height * kBytesPerPixel; | 377 int total_bytes = width * height * kBytesPerPixel; |
| 382 | 378 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 393 | 389 |
| 394 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. | 390 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. |
| 395 unsigned long* src = img->pixels; | 391 unsigned long* src = img->pixels; |
| 396 uint32* dst = reinterpret_cast<uint32*>(proto_data); | 392 uint32* dst = reinterpret_cast<uint32*>(proto_data); |
| 397 uint32* dst_end = dst + (width * height); | 393 uint32* dst_end = dst + (width * height); |
| 398 while (dst < dst_end) { | 394 while (dst < dst_end) { |
| 399 *dst++ = static_cast<uint32>(*src++); | 395 *dst++ = static_cast<uint32>(*src++); |
| 400 } | 396 } |
| 401 XFree(img); | 397 XFree(img); |
| 402 | 398 |
| 403 cursor_shape_changed_callback_.Run(cursor_proto.Pass()); | 399 delegate_->OnCursorShapeChanged(cursor_proto.Pass()); |
| 404 } | 400 } |
| 405 | 401 |
| 406 CaptureData* VideoFrameCapturerLinux::CaptureFrame() { | 402 CaptureData* VideoFrameCapturerLinux::CaptureFrame() { |
| 407 VideoFrameBuffer& buffer = buffers_[current_buffer_]; | 403 VideoFrameBuffer& buffer = buffers_[current_buffer_]; |
| 408 DataPlanes planes; | 404 DataPlanes planes; |
| 409 planes.data[0] = buffer.ptr(); | 405 planes.data[0] = buffer.ptr(); |
| 410 planes.strides[0] = buffer.bytes_per_row(); | 406 planes.strides[0] = buffer.bytes_per_row(); |
| 411 | 407 |
| 412 CaptureData* capture_data = new CaptureData(planes, buffer.size(), | 408 CaptureData* capture_data = new CaptureData(planes, buffer.size(), |
| 413 media::VideoFrame::RGB32); | 409 media::VideoFrame::RGB32); |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 } | 624 } |
| 629 return capturer; | 625 return capturer; |
| 630 } | 626 } |
| 631 | 627 |
| 632 // static | 628 // static |
| 633 void VideoFrameCapturer::EnableXDamage(bool enable) { | 629 void VideoFrameCapturer::EnableXDamage(bool enable) { |
| 634 g_should_use_x_damage = enable; | 630 g_should_use_x_damage = enable; |
| 635 } | 631 } |
| 636 | 632 |
| 637 } // namespace remoting | 633 } // namespace remoting |
| OLD | NEW |