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/capturer/video_frame_capturer.h" | 5 #include "media/video/capture/screen/screen_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> |
11 | 11 |
12 #include <set> | 12 #include <set> |
13 | 13 |
14 #include "base/basictypes.h" | 14 #include "base/basictypes.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/time.h" | 18 #include "base/time.h" |
19 #include "remoting/capturer/capture_data.h" | 19 #include "media/video/capture/screen/differ.h" |
20 #include "remoting/capturer/differ.h" | 20 #include "media/video/capture/screen/linux/x_server_pixel_buffer.h" |
21 #include "remoting/capturer/linux/x_server_pixel_buffer.h" | 21 #include "media/video/capture/screen/mouse_cursor_shape.h" |
22 #include "remoting/capturer/mouse_cursor_shape.h" | 22 #include "media/video/capture/screen/screen_capture_data.h" |
23 #include "remoting/capturer/video_frame.h" | 23 #include "media/video/capture/screen/screen_capture_frame.h" |
24 #include "remoting/capturer/video_frame_capturer_helper.h" | 24 #include "media/video/capture/screen/screen_capture_frame_queue.h" |
25 #include "remoting/capturer/video_frame_queue.h" | 25 #include "media/video/capture/screen/screen_capturer_helper.h" |
26 | 26 |
27 namespace remoting { | 27 namespace media { |
28 | 28 |
29 namespace { | 29 namespace { |
30 | 30 |
31 // Default to false, since many systems have broken XDamage support - see | 31 // Default to false, since many systems have broken XDamage support - see |
32 // http://crbug.com/73423. | 32 // http://crbug.com/73423. |
33 static bool g_should_use_x_damage = false; | 33 static bool g_should_use_x_damage = false; |
34 | 34 |
35 static bool ShouldUseXDamage() { | 35 static bool ShouldUseXDamage() { |
36 return g_should_use_x_damage; | 36 return g_should_use_x_damage; |
37 } | 37 } |
38 | 38 |
39 // A class representing a full-frame pixel buffer. | 39 // A class representing a full-frame pixel buffer. |
40 class VideoFrameLinux : public VideoFrame { | 40 class ScreenCaptureFrameLinux : public ScreenCaptureFrame { |
41 public: | 41 public: |
42 explicit VideoFrameLinux(const SkISize& window_size); | 42 explicit ScreenCaptureFrameLinux(const SkISize& window_size); |
43 virtual ~VideoFrameLinux(); | 43 virtual ~ScreenCaptureFrameLinux(); |
44 | 44 |
45 private: | 45 private: |
46 // Allocated pixel buffer. | 46 // Allocated pixel buffer. |
47 scoped_array<uint8> data_; | 47 scoped_array<uint8> data_; |
48 | 48 |
49 DISALLOW_COPY_AND_ASSIGN(VideoFrameLinux); | 49 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureFrameLinux); |
50 }; | 50 }; |
51 | 51 |
52 // A class to perform video frame capturing for Linux. | 52 // A class to perform video frame capturing for Linux. |
53 class VideoFrameCapturerLinux : public VideoFrameCapturer { | 53 class ScreenCapturerLinux : public ScreenCapturer { |
54 public: | 54 public: |
55 VideoFrameCapturerLinux(); | 55 ScreenCapturerLinux(); |
56 virtual ~VideoFrameCapturerLinux(); | 56 virtual ~ScreenCapturerLinux(); |
57 | 57 |
58 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? | 58 bool Init(); // TODO(ajwong): Do we really want this to be synchronous? |
59 | 59 |
60 // Capturer interface. | 60 // Capturer interface. |
61 virtual void Start(Delegate* delegate) OVERRIDE; | 61 virtual void Start(Delegate* delegate) OVERRIDE; |
62 virtual void Stop() OVERRIDE; | 62 virtual void Stop() OVERRIDE; |
63 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; | 63 virtual void InvalidateRegion(const SkRegion& invalid_region) OVERRIDE; |
64 virtual void CaptureFrame() OVERRIDE; | 64 virtual void CaptureFrame() OVERRIDE; |
65 | 65 |
66 private: | 66 private: |
67 void InitXDamage(); | 67 void InitXDamage(); |
68 | 68 |
69 // Read and handle all currently-pending XEvents. | 69 // Read and handle all currently-pending XEvents. |
70 // In the DAMAGE case, process the XDamage events and store the resulting | 70 // In the DAMAGE case, process the XDamage events and store the resulting |
71 // damage rectangles in the VideoFrameCapturerHelper. | 71 // damage rectangles in the ScreenCapturerHelper. |
72 // In all cases, call ScreenConfigurationChanged() in response to any | 72 // In all cases, call ScreenConfigurationChanged() in response to any |
73 // ConfigNotify events. | 73 // ConfigNotify events. |
74 void ProcessPendingXEvents(); | 74 void ProcessPendingXEvents(); |
75 | 75 |
76 // Capture the cursor image and notify the delegate if it was captured. | 76 // Capture the cursor image and notify the delegate if it was captured. |
77 void CaptureCursor(); | 77 void CaptureCursor(); |
78 | 78 |
79 // Capture screen pixels, and return the data in a new CaptureData object, | 79 // Capture screen pixels, and return the data in a new ScreenCaptureData |
80 // to be freed by the caller. | 80 // object, to be freed by the caller. In the DAMAGE case, the |
81 // In the DAMAGE case, the VideoFrameCapturerHelper already holds the list of | 81 // ScreenCapturerHelper already holds the list of invalid rectangles from |
82 // invalid rectangles from ProcessPendingXEvents(). | 82 // ProcessPendingXEvents(). In the non-DAMAGE case, this captures the whole |
83 // In the non-DAMAGE case, this captures the whole screen, then calculates | 83 // screen, then calculates some invalid rectangles that include any |
84 // some invalid rectangles that include any differences between this and the | 84 // differences between this and the previous capture. |
85 // previous capture. | 85 scoped_refptr<ScreenCaptureData> CaptureScreen(); |
86 scoped_refptr<CaptureData> CaptureScreen(); | |
87 | 86 |
88 // Called when the screen configuration is changed. |root_window_size| | 87 // Called when the screen configuration is changed. |root_window_size| |
89 // specifies the most recent size of the root window. | 88 // specifies the most recent size of the root window. |
90 void ScreenConfigurationChanged(const SkISize& root_window_size); | 89 void ScreenConfigurationChanged(const SkISize& root_window_size); |
91 | 90 |
92 // Synchronize the current buffer with |last_buffer_|, by copying pixels from | 91 // Synchronize the current buffer with |last_buffer_|, by copying pixels from |
93 // the area of |last_invalid_rects|. | 92 // the area of |last_invalid_rects|. |
94 // Note this only works on the assumption that kNumBuffers == 2, as | 93 // Note this only works on the assumption that kNumBuffers == 2, as |
95 // |last_invalid_rects| holds the differences from the previous buffer and | 94 // |last_invalid_rects| holds the differences from the previous buffer and |
96 // the one prior to that (which will then be the current buffer). | 95 // the one prior to that (which will then be the current buffer). |
97 void SynchronizeFrame(); | 96 void SynchronizeFrame(); |
98 | 97 |
99 void DeinitXlib(); | 98 void DeinitXlib(); |
100 | 99 |
101 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into | 100 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into |
102 // |capture_data|. | 101 // |capture_data|. |
103 void CaptureRect(const SkIRect& rect, CaptureData* capture_data); | 102 void CaptureRect(const SkIRect& rect, ScreenCaptureData* capture_data); |
104 | 103 |
105 // We expose two forms of blitting to handle variations in the pixel format. | 104 // We expose two forms of blitting to handle variations in the pixel format. |
106 // In FastBlit, the operation is effectively a memcpy. | 105 // In FastBlit, the operation is effectively a memcpy. |
107 void FastBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); | 106 void FastBlit(uint8* image, |
108 void SlowBlit(uint8* image, const SkIRect& rect, CaptureData* capture_data); | 107 const SkIRect& rect, |
| 108 ScreenCaptureData* capture_data); |
| 109 void SlowBlit(uint8* image, |
| 110 const SkIRect& rect, |
| 111 ScreenCaptureData* capture_data); |
109 | 112 |
110 Delegate* delegate_; | 113 Delegate* delegate_; |
111 | 114 |
112 // X11 graphics context. | 115 // X11 graphics context. |
113 Display* display_; | 116 Display* display_; |
114 GC gc_; | 117 GC gc_; |
115 Window root_window_; | 118 Window root_window_; |
116 | 119 |
117 // Last known dimensions of the root window. | 120 // Last known dimensions of the root window. |
118 SkISize root_window_size_; | 121 SkISize root_window_size_; |
119 | 122 |
120 // XFixes. | 123 // XFixes. |
121 bool has_xfixes_; | 124 bool has_xfixes_; |
122 int xfixes_event_base_; | 125 int xfixes_event_base_; |
123 int xfixes_error_base_; | 126 int xfixes_error_base_; |
124 | 127 |
125 // XDamage information. | 128 // XDamage information. |
126 bool use_damage_; | 129 bool use_damage_; |
127 Damage damage_handle_; | 130 Damage damage_handle_; |
128 int damage_event_base_; | 131 int damage_event_base_; |
129 int damage_error_base_; | 132 int damage_error_base_; |
130 XserverRegion damage_region_; | 133 XserverRegion damage_region_; |
131 | 134 |
132 // Access to the X Server's pixel buffer. | 135 // Access to the X Server's pixel buffer. |
133 XServerPixelBuffer x_server_pixel_buffer_; | 136 XServerPixelBuffer x_server_pixel_buffer_; |
134 | 137 |
135 // A thread-safe list of invalid rectangles, and the size of the most | 138 // A thread-safe list of invalid rectangles, and the size of the most |
136 // recently captured screen. | 139 // recently captured screen. |
137 VideoFrameCapturerHelper helper_; | 140 ScreenCapturerHelper helper_; |
138 | 141 |
139 // Queue of the frames buffers. | 142 // Queue of the frames buffers. |
140 VideoFrameQueue queue_; | 143 ScreenCaptureFrameQueue queue_; |
141 | 144 |
142 // Invalid region from the previous capture. This is used to synchronize the | 145 // Invalid region from the previous capture. This is used to synchronize the |
143 // current with the last buffer used. | 146 // current with the last buffer used. |
144 SkRegion last_invalid_region_; | 147 SkRegion last_invalid_region_; |
145 | 148 |
146 // |Differ| for use when polling for changes. | 149 // |Differ| for use when polling for changes. |
147 scoped_ptr<Differ> differ_; | 150 scoped_ptr<Differ> differ_; |
148 | 151 |
149 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerLinux); | 152 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); |
150 }; | 153 }; |
151 | 154 |
152 VideoFrameLinux::VideoFrameLinux(const SkISize& window_size) { | 155 ScreenCaptureFrameLinux::ScreenCaptureFrameLinux(const SkISize& window_size) { |
153 set_bytes_per_row(window_size.width() * CaptureData::kBytesPerPixel); | 156 set_bytes_per_row(window_size.width() * ScreenCaptureData::kBytesPerPixel); |
154 set_dimensions(window_size); | 157 set_dimensions(window_size); |
155 | 158 |
156 size_t buffer_size = bytes_per_row() * window_size.height(); | 159 size_t buffer_size = bytes_per_row() * window_size.height(); |
157 data_.reset(new uint8[buffer_size]); | 160 data_.reset(new uint8[buffer_size]); |
158 set_pixels(data_.get()); | 161 set_pixels(data_.get()); |
159 } | 162 } |
160 | 163 |
161 VideoFrameLinux::~VideoFrameLinux() { | 164 ScreenCaptureFrameLinux::~ScreenCaptureFrameLinux() { |
162 } | 165 } |
163 | 166 |
164 VideoFrameCapturerLinux::VideoFrameCapturerLinux() | 167 ScreenCapturerLinux::ScreenCapturerLinux() |
165 : delegate_(NULL), | 168 : delegate_(NULL), |
166 display_(NULL), | 169 display_(NULL), |
167 gc_(NULL), | 170 gc_(NULL), |
168 root_window_(BadValue), | 171 root_window_(BadValue), |
169 root_window_size_(SkISize::Make(0, 0)), | 172 root_window_size_(SkISize::Make(0, 0)), |
170 has_xfixes_(false), | 173 has_xfixes_(false), |
171 xfixes_event_base_(-1), | 174 xfixes_event_base_(-1), |
172 xfixes_error_base_(-1), | 175 xfixes_error_base_(-1), |
173 use_damage_(false), | 176 use_damage_(false), |
174 damage_handle_(0), | 177 damage_handle_(0), |
175 damage_event_base_(-1), | 178 damage_event_base_(-1), |
176 damage_error_base_(-1), | 179 damage_error_base_(-1), |
177 damage_region_(0) { | 180 damage_region_(0) { |
178 helper_.SetLogGridSize(4); | 181 helper_.SetLogGridSize(4); |
179 } | 182 } |
180 | 183 |
181 VideoFrameCapturerLinux::~VideoFrameCapturerLinux() { | 184 ScreenCapturerLinux::~ScreenCapturerLinux() { |
182 DeinitXlib(); | 185 DeinitXlib(); |
183 } | 186 } |
184 | 187 |
185 bool VideoFrameCapturerLinux::Init() { | 188 bool ScreenCapturerLinux::Init() { |
186 // TODO(ajwong): We should specify the display string we are attaching to | 189 // TODO(ajwong): We should specify the display string we are attaching to |
187 // in the constructor. | 190 // in the constructor. |
188 display_ = XOpenDisplay(NULL); | 191 display_ = XOpenDisplay(NULL); |
189 if (!display_) { | 192 if (!display_) { |
190 LOG(ERROR) << "Unable to open display"; | 193 LOG(ERROR) << "Unable to open display"; |
191 return false; | 194 return false; |
192 } | 195 } |
193 | 196 |
194 root_window_ = RootWindow(display_, DefaultScreen(display_)); | 197 root_window_ = RootWindow(display_, DefaultScreen(display_)); |
195 if (root_window_ == BadValue) { | 198 if (root_window_ == BadValue) { |
(...skipping 30 matching lines...) Expand all Loading... |
226 XFixesDisplayCursorNotifyMask); | 229 XFixesDisplayCursorNotifyMask); |
227 } | 230 } |
228 | 231 |
229 if (ShouldUseXDamage()) { | 232 if (ShouldUseXDamage()) { |
230 InitXDamage(); | 233 InitXDamage(); |
231 } | 234 } |
232 | 235 |
233 return true; | 236 return true; |
234 } | 237 } |
235 | 238 |
236 void VideoFrameCapturerLinux::InitXDamage() { | 239 void ScreenCapturerLinux::InitXDamage() { |
237 // Our use of XDamage requires XFixes. | 240 // Our use of XDamage requires XFixes. |
238 if (!has_xfixes_) { | 241 if (!has_xfixes_) { |
239 return; | 242 return; |
240 } | 243 } |
241 | 244 |
242 // Check for XDamage extension. | 245 // Check for XDamage extension. |
243 if (!XDamageQueryExtension(display_, &damage_event_base_, | 246 if (!XDamageQueryExtension(display_, &damage_event_base_, |
244 &damage_error_base_)) { | 247 &damage_error_base_)) { |
245 LOG(INFO) << "X server does not support XDamage."; | 248 LOG(INFO) << "X server does not support XDamage."; |
246 return; | 249 return; |
(...skipping 17 matching lines...) Expand all Loading... |
264 if (!damage_region_) { | 267 if (!damage_region_) { |
265 XDamageDestroy(display_, damage_handle_); | 268 XDamageDestroy(display_, damage_handle_); |
266 LOG(ERROR) << "Unable to create XFixes region."; | 269 LOG(ERROR) << "Unable to create XFixes region."; |
267 return; | 270 return; |
268 } | 271 } |
269 | 272 |
270 use_damage_ = true; | 273 use_damage_ = true; |
271 LOG(INFO) << "Using XDamage extension."; | 274 LOG(INFO) << "Using XDamage extension."; |
272 } | 275 } |
273 | 276 |
274 void VideoFrameCapturerLinux::Start(Delegate* delegate) { | 277 void ScreenCapturerLinux::Start(Delegate* delegate) { |
275 DCHECK(delegate_ == NULL); | 278 DCHECK(delegate_ == NULL); |
276 | 279 |
277 delegate_ = delegate; | 280 delegate_ = delegate; |
278 } | 281 } |
279 | 282 |
280 void VideoFrameCapturerLinux::Stop() { | 283 void ScreenCapturerLinux::Stop() { |
281 } | 284 } |
282 | 285 |
283 void VideoFrameCapturerLinux::InvalidateRegion(const SkRegion& invalid_region) { | 286 void ScreenCapturerLinux::InvalidateRegion(const SkRegion& invalid_region) { |
284 helper_.InvalidateRegion(invalid_region); | 287 helper_.InvalidateRegion(invalid_region); |
285 } | 288 } |
286 | 289 |
287 void VideoFrameCapturerLinux::CaptureFrame() { | 290 void ScreenCapturerLinux::CaptureFrame() { |
288 base::Time capture_start_time = base::Time::Now(); | 291 base::Time capture_start_time = base::Time::Now(); |
289 | 292 |
290 // Process XEvents for XDamage and cursor shape tracking. | 293 // Process XEvents for XDamage and cursor shape tracking. |
291 ProcessPendingXEvents(); | 294 ProcessPendingXEvents(); |
292 | 295 |
293 // If the current buffer is from an older generation then allocate a new one. | 296 // If the current buffer is from an older generation then allocate a new one. |
294 // Note that we can't reallocate other buffers at this point, since the caller | 297 // Note that we can't reallocate other buffers at this point, since the caller |
295 // may still be reading from them. | 298 // may still be reading from them. |
296 if (queue_.current_frame_needs_update()) { | 299 if (queue_.current_frame_needs_update()) { |
297 scoped_ptr<VideoFrameLinux> buffer(new VideoFrameLinux( | 300 scoped_ptr<ScreenCaptureFrameLinux> buffer(new ScreenCaptureFrameLinux( |
298 root_window_size_)); | 301 root_window_size_)); |
299 queue_.ReplaceCurrentFrame(buffer.PassAs<VideoFrame>()); | 302 queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>()); |
300 } | 303 } |
301 | 304 |
302 // Refresh the Differ helper used by CaptureFrame(), if needed. | 305 // Refresh the Differ helper used by CaptureFrame(), if needed. |
303 const VideoFrame* current_buffer = queue_.current_frame(); | 306 const ScreenCaptureFrame* current_buffer = queue_.current_frame(); |
304 if (!use_damage_ && ( | 307 if (!use_damage_ && ( |
305 !differ_.get() || | 308 !differ_.get() || |
306 (differ_->width() != current_buffer->dimensions().width()) || | 309 (differ_->width() != current_buffer->dimensions().width()) || |
307 (differ_->height() != current_buffer->dimensions().height()) || | 310 (differ_->height() != current_buffer->dimensions().height()) || |
308 (differ_->bytes_per_row() != current_buffer->bytes_per_row()))) { | 311 (differ_->bytes_per_row() != current_buffer->bytes_per_row()))) { |
309 differ_.reset(new Differ(current_buffer->dimensions().width(), | 312 differ_.reset(new Differ(current_buffer->dimensions().width(), |
310 current_buffer->dimensions().height(), | 313 current_buffer->dimensions().height(), |
311 CaptureData::kBytesPerPixel, | 314 ScreenCaptureData::kBytesPerPixel, |
312 current_buffer->bytes_per_row())); | 315 current_buffer->bytes_per_row())); |
313 } | 316 } |
314 | 317 |
315 scoped_refptr<CaptureData> capture_data(CaptureScreen()); | 318 scoped_refptr<ScreenCaptureData> capture_data(CaptureScreen()); |
316 | 319 |
317 // Swap the current & previous buffers ready for the next capture. | 320 // Swap the current & previous buffers ready for the next capture. |
318 last_invalid_region_ = capture_data->dirty_region(); | 321 last_invalid_region_ = capture_data->dirty_region(); |
319 | 322 |
320 queue_.DoneWithCurrentFrame(); | 323 queue_.DoneWithCurrentFrame(); |
321 | 324 |
322 capture_data->set_capture_time_ms( | 325 capture_data->set_capture_time_ms( |
323 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); | 326 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); |
324 delegate_->OnCaptureCompleted(capture_data); | 327 delegate_->OnCaptureCompleted(capture_data); |
325 } | 328 } |
326 | 329 |
327 void VideoFrameCapturerLinux::ProcessPendingXEvents() { | 330 void ScreenCapturerLinux::ProcessPendingXEvents() { |
328 // Find the number of events that are outstanding "now." We don't just loop | 331 // Find the number of events that are outstanding "now." We don't just loop |
329 // on XPending because we want to guarantee this terminates. | 332 // on XPending because we want to guarantee this terminates. |
330 int events_to_process = XPending(display_); | 333 int events_to_process = XPending(display_); |
331 XEvent e; | 334 XEvent e; |
332 | 335 |
333 for (int i = 0; i < events_to_process; i++) { | 336 for (int i = 0; i < events_to_process; i++) { |
334 XNextEvent(display_, &e); | 337 XNextEvent(display_, &e); |
335 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { | 338 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { |
336 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); | 339 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); |
337 DCHECK(event->level == XDamageReportNonEmpty); | 340 DCHECK(event->level == XDamageReportNonEmpty); |
338 } else if (e.type == ConfigureNotify) { | 341 } else if (e.type == ConfigureNotify) { |
339 const XConfigureEvent& event = e.xconfigure; | 342 const XConfigureEvent& event = e.xconfigure; |
340 ScreenConfigurationChanged(SkISize::Make(event.width, event.height)); | 343 ScreenConfigurationChanged(SkISize::Make(event.width, event.height)); |
341 } else if (has_xfixes_ && | 344 } else if (has_xfixes_ && |
342 e.type == xfixes_event_base_ + XFixesCursorNotify) { | 345 e.type == xfixes_event_base_ + XFixesCursorNotify) { |
343 XFixesCursorNotifyEvent* cne; | 346 XFixesCursorNotifyEvent* cne; |
344 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); | 347 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); |
345 if (cne->subtype == XFixesDisplayCursorNotify) { | 348 if (cne->subtype == XFixesDisplayCursorNotify) { |
346 CaptureCursor(); | 349 CaptureCursor(); |
347 } | 350 } |
348 } else { | 351 } else { |
349 LOG(WARNING) << "Got unknown event type: " << e.type; | 352 LOG(WARNING) << "Got unknown event type: " << e.type; |
350 } | 353 } |
351 } | 354 } |
352 } | 355 } |
353 | 356 |
354 void VideoFrameCapturerLinux::CaptureCursor() { | 357 void ScreenCapturerLinux::CaptureCursor() { |
355 DCHECK(has_xfixes_); | 358 DCHECK(has_xfixes_); |
356 | 359 |
357 XFixesCursorImage* img = XFixesGetCursorImage(display_); | 360 XFixesCursorImage* img = XFixesGetCursorImage(display_); |
358 if (!img) { | 361 if (!img) { |
359 return; | 362 return; |
360 } | 363 } |
361 | 364 |
362 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); | 365 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); |
363 cursor->size.set(img->width, img->height); | 366 cursor->size.set(img->width, img->height); |
364 cursor->hotspot.set(img->xhot, img->yhot); | 367 cursor->hotspot.set(img->xhot, img->yhot); |
365 | 368 |
366 int total_bytes = cursor->size.width() * cursor->size.height() * | 369 int total_bytes = cursor->size.width() * cursor->size.height() * |
367 CaptureData::kBytesPerPixel; | 370 ScreenCaptureData::kBytesPerPixel; |
368 cursor->data.resize(total_bytes); | 371 cursor->data.resize(total_bytes); |
369 | 372 |
370 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. | 373 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. |
371 unsigned long* src = img->pixels; | 374 unsigned long* src = img->pixels; |
372 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data)); | 375 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data)); |
373 uint32* dst_end = dst + (img->width * img->height); | 376 uint32* dst_end = dst + (img->width * img->height); |
374 while (dst < dst_end) { | 377 while (dst < dst_end) { |
375 *dst++ = static_cast<uint32>(*src++); | 378 *dst++ = static_cast<uint32>(*src++); |
376 } | 379 } |
377 XFree(img); | 380 XFree(img); |
378 | 381 |
379 delegate_->OnCursorShapeChanged(cursor.Pass()); | 382 delegate_->OnCursorShapeChanged(cursor.Pass()); |
380 } | 383 } |
381 | 384 |
382 scoped_refptr<CaptureData> VideoFrameCapturerLinux::CaptureScreen() { | 385 scoped_refptr<ScreenCaptureData> ScreenCapturerLinux::CaptureScreen() { |
383 VideoFrame* frame = queue_.current_frame(); | 386 ScreenCaptureFrame* frame = queue_.current_frame(); |
384 scoped_refptr<CaptureData> capture_data(new CaptureData( | 387 scoped_refptr<ScreenCaptureData> capture_data(new ScreenCaptureData( |
385 frame->pixels(), frame->bytes_per_row(), frame->dimensions())); | 388 frame->pixels(), frame->bytes_per_row(), frame->dimensions())); |
386 | 389 |
387 // Pass the screen size to the helper, so it can clip the invalid region if it | 390 // Pass the screen size to the helper, so it can clip the invalid region if it |
388 // expands that region to a grid. | 391 // expands that region to a grid. |
389 helper_.set_size_most_recent(capture_data->size()); | 392 helper_.set_size_most_recent(capture_data->size()); |
390 | 393 |
391 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame | 394 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame |
392 // if any. If there isn't a previous frame, that means a screen-resolution | 395 // if any. If there isn't a previous frame, that means a screen-resolution |
393 // change occurred, and |invalid_rects| will be updated to include the whole | 396 // change occurred, and |invalid_rects| will be updated to include the whole |
394 // screen. | 397 // screen. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 // full-screen notification after a screen-resolution change, so | 446 // full-screen notification after a screen-resolution change, so |
444 // this is done here. | 447 // this is done here. |
445 invalid_region.op(screen_rect, SkRegion::kUnion_Op); | 448 invalid_region.op(screen_rect, SkRegion::kUnion_Op); |
446 } | 449 } |
447 } | 450 } |
448 | 451 |
449 capture_data->mutable_dirty_region() = invalid_region; | 452 capture_data->mutable_dirty_region() = invalid_region; |
450 return capture_data; | 453 return capture_data; |
451 } | 454 } |
452 | 455 |
453 void VideoFrameCapturerLinux::ScreenConfigurationChanged( | 456 void ScreenCapturerLinux::ScreenConfigurationChanged( |
454 const SkISize& root_window_size) { | 457 const SkISize& root_window_size) { |
455 root_window_size_ = root_window_size; | 458 root_window_size_ = root_window_size; |
456 | 459 |
457 // Make sure the frame buffers will be reallocated. | 460 // Make sure the frame buffers will be reallocated. |
458 queue_.SetAllFramesNeedUpdate(); | 461 queue_.SetAllFramesNeedUpdate(); |
459 | 462 |
460 helper_.ClearInvalidRegion(); | 463 helper_.ClearInvalidRegion(); |
461 x_server_pixel_buffer_.Init(display_, root_window_size_); | 464 x_server_pixel_buffer_.Init(display_, root_window_size_); |
462 } | 465 } |
463 | 466 |
464 void VideoFrameCapturerLinux::SynchronizeFrame() { | 467 void ScreenCapturerLinux::SynchronizeFrame() { |
465 // Synchronize the current buffer with the previous one since we do not | 468 // Synchronize the current buffer with the previous one since we do not |
466 // capture the entire desktop. Note that encoder may be reading from the | 469 // capture the entire desktop. Note that encoder may be reading from the |
467 // previous buffer at this time so thread access complaints are false | 470 // previous buffer at this time so thread access complaints are false |
468 // positives. | 471 // positives. |
469 | 472 |
470 // TODO(hclam): We can reduce the amount of copying here by subtracting | 473 // TODO(hclam): We can reduce the amount of copying here by subtracting |
471 // |capturer_helper_|s region from |last_invalid_region_|. | 474 // |capturer_helper_|s region from |last_invalid_region_|. |
472 // http://crbug.com/92354 | 475 // http://crbug.com/92354 |
473 DCHECK(queue_.previous_frame()); | 476 DCHECK(queue_.previous_frame()); |
474 | 477 |
475 VideoFrame* current = queue_.current_frame(); | 478 ScreenCaptureFrame* current = queue_.current_frame(); |
476 VideoFrame* last = queue_.previous_frame(); | 479 ScreenCaptureFrame* last = queue_.previous_frame(); |
477 DCHECK_NE(current, last); | 480 DCHECK_NE(current, last); |
478 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { | 481 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { |
479 const SkIRect& r = it.rect(); | 482 const SkIRect& r = it.rect(); |
480 int offset = r.fTop * current->bytes_per_row() + | 483 int offset = r.fTop * current->bytes_per_row() + |
481 r.fLeft * CaptureData::kBytesPerPixel; | 484 r.fLeft * ScreenCaptureData::kBytesPerPixel; |
482 for (int i = 0; i < r.height(); ++i) { | 485 for (int i = 0; i < r.height(); ++i) { |
483 memcpy(current->pixels() + offset, last->pixels() + offset, | 486 memcpy(current->pixels() + offset, last->pixels() + offset, |
484 r.width() * CaptureData::kBytesPerPixel); | 487 r.width() * ScreenCaptureData::kBytesPerPixel); |
485 offset += current->dimensions().width() * CaptureData::kBytesPerPixel; | 488 offset += current->dimensions().width() * |
| 489 ScreenCaptureData::kBytesPerPixel; |
486 } | 490 } |
487 } | 491 } |
488 } | 492 } |
489 | 493 |
490 void VideoFrameCapturerLinux::DeinitXlib() { | 494 void ScreenCapturerLinux::DeinitXlib() { |
491 if (gc_) { | 495 if (gc_) { |
492 XFreeGC(display_, gc_); | 496 XFreeGC(display_, gc_); |
493 gc_ = NULL; | 497 gc_ = NULL; |
494 } | 498 } |
495 | 499 |
496 x_server_pixel_buffer_.Release(); | 500 x_server_pixel_buffer_.Release(); |
497 | 501 |
498 if (display_) { | 502 if (display_) { |
499 if (damage_handle_) | 503 if (damage_handle_) |
500 XDamageDestroy(display_, damage_handle_); | 504 XDamageDestroy(display_, damage_handle_); |
501 if (damage_region_) | 505 if (damage_region_) |
502 XFixesDestroyRegion(display_, damage_region_); | 506 XFixesDestroyRegion(display_, damage_region_); |
503 XCloseDisplay(display_); | 507 XCloseDisplay(display_); |
504 display_ = NULL; | 508 display_ = NULL; |
505 damage_handle_ = 0; | 509 damage_handle_ = 0; |
506 damage_region_ = 0; | 510 damage_region_ = 0; |
507 } | 511 } |
508 } | 512 } |
509 | 513 |
510 void VideoFrameCapturerLinux::CaptureRect(const SkIRect& rect, | 514 void ScreenCapturerLinux::CaptureRect(const SkIRect& rect, |
511 CaptureData* capture_data) { | 515 ScreenCaptureData* capture_data) { |
512 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); | 516 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); |
513 int depth = x_server_pixel_buffer_.GetDepth(); | 517 int depth = x_server_pixel_buffer_.GetDepth(); |
514 int bpp = x_server_pixel_buffer_.GetBitsPerPixel(); | 518 int bpp = x_server_pixel_buffer_.GetBitsPerPixel(); |
515 bool is_rgb = x_server_pixel_buffer_.IsRgb(); | 519 bool is_rgb = x_server_pixel_buffer_.IsRgb(); |
516 if ((depth == 24 || depth == 32) && bpp == 32 && is_rgb) { | 520 if ((depth == 24 || depth == 32) && bpp == 32 && is_rgb) { |
517 DVLOG(3) << "Fast blitting"; | 521 DVLOG(3) << "Fast blitting"; |
518 FastBlit(image, rect, capture_data); | 522 FastBlit(image, rect, capture_data); |
519 } else { | 523 } else { |
520 DVLOG(3) << "Slow blitting"; | 524 DVLOG(3) << "Slow blitting"; |
521 SlowBlit(image, rect, capture_data); | 525 SlowBlit(image, rect, capture_data); |
522 } | 526 } |
523 } | 527 } |
524 | 528 |
525 void VideoFrameCapturerLinux::FastBlit(uint8* image, const SkIRect& rect, | 529 void ScreenCapturerLinux::FastBlit(uint8* image, const SkIRect& rect, |
526 CaptureData* capture_data) { | 530 ScreenCaptureData* capture_data) { |
527 uint8* src_pos = image; | 531 uint8* src_pos = image; |
528 int src_stride = x_server_pixel_buffer_.GetStride(); | 532 int src_stride = x_server_pixel_buffer_.GetStride(); |
529 int dst_x = rect.fLeft, dst_y = rect.fTop; | 533 int dst_x = rect.fLeft, dst_y = rect.fTop; |
530 | 534 |
531 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; | 535 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; |
532 dst_pos += dst_x * CaptureData::kBytesPerPixel; | 536 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; |
533 | 537 |
534 int height = rect.height(); | 538 int height = rect.height(); |
535 int row_bytes = rect.width() * CaptureData::kBytesPerPixel; | 539 int row_bytes = rect.width() * ScreenCaptureData::kBytesPerPixel; |
536 for (int y = 0; y < height; ++y) { | 540 for (int y = 0; y < height; ++y) { |
537 memcpy(dst_pos, src_pos, row_bytes); | 541 memcpy(dst_pos, src_pos, row_bytes); |
538 src_pos += src_stride; | 542 src_pos += src_stride; |
539 dst_pos += capture_data->stride(); | 543 dst_pos += capture_data->stride(); |
540 } | 544 } |
541 } | 545 } |
542 | 546 |
543 void VideoFrameCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect, | 547 void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect, |
544 CaptureData* capture_data) { | 548 ScreenCaptureData* capture_data) { |
545 int src_stride = x_server_pixel_buffer_.GetStride(); | 549 int src_stride = x_server_pixel_buffer_.GetStride(); |
546 int dst_x = rect.fLeft, dst_y = rect.fTop; | 550 int dst_x = rect.fLeft, dst_y = rect.fTop; |
547 int width = rect.width(), height = rect.height(); | 551 int width = rect.width(), height = rect.height(); |
548 | 552 |
549 unsigned int red_mask = x_server_pixel_buffer_.GetRedMask(); | 553 unsigned int red_mask = x_server_pixel_buffer_.GetRedMask(); |
550 unsigned int blue_mask = x_server_pixel_buffer_.GetBlueMask(); | 554 unsigned int blue_mask = x_server_pixel_buffer_.GetBlueMask(); |
551 unsigned int green_mask = x_server_pixel_buffer_.GetGreenMask(); | 555 unsigned int green_mask = x_server_pixel_buffer_.GetGreenMask(); |
552 unsigned int red_shift = x_server_pixel_buffer_.GetRedShift(); | 556 unsigned int red_shift = x_server_pixel_buffer_.GetRedShift(); |
553 unsigned int blue_shift = x_server_pixel_buffer_.GetBlueShift(); | 557 unsigned int blue_shift = x_server_pixel_buffer_.GetBlueShift(); |
554 unsigned int green_shift = x_server_pixel_buffer_.GetGreenShift(); | 558 unsigned int green_shift = x_server_pixel_buffer_.GetGreenShift(); |
555 | 559 |
556 unsigned int max_red = red_mask >> red_shift; | 560 unsigned int max_red = red_mask >> red_shift; |
557 unsigned int max_blue = blue_mask >> blue_shift; | 561 unsigned int max_blue = blue_mask >> blue_shift; |
558 unsigned int max_green = green_mask >> green_shift; | 562 unsigned int max_green = green_mask >> green_shift; |
559 | 563 |
560 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); | 564 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); |
561 | 565 |
562 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; | 566 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; |
563 uint8* src_pos = image; | 567 uint8* src_pos = image; |
564 dst_pos += dst_x * CaptureData::kBytesPerPixel; | 568 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; |
565 // TODO(hclam): Optimize, perhaps using MMX code or by converting to | 569 // TODO(hclam): Optimize, perhaps using MMX code or by converting to |
566 // YUV directly | 570 // YUV directly |
567 for (int y = 0; y < height; y++) { | 571 for (int y = 0; y < height; y++) { |
568 uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos); | 572 uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos); |
569 uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos); | 573 uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos); |
570 uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos); | 574 uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos); |
571 for (int x = 0; x < width; x++) { | 575 for (int x = 0; x < width; x++) { |
572 // Dereference through an appropriately-aligned pointer. | 576 // Dereference through an appropriately-aligned pointer. |
573 uint32_t pixel; | 577 uint32_t pixel; |
574 if (bits_per_pixel == 32) | 578 if (bits_per_pixel == 32) |
575 pixel = src_pos_32[x]; | 579 pixel = src_pos_32[x]; |
576 else if (bits_per_pixel == 16) | 580 else if (bits_per_pixel == 16) |
577 pixel = src_pos_16[x]; | 581 pixel = src_pos_16[x]; |
578 else | 582 else |
579 pixel = src_pos[x]; | 583 pixel = src_pos[x]; |
580 uint32_t r = (((pixel & red_mask) >> red_shift) * 255) / max_red; | 584 uint32_t r = (((pixel & red_mask) >> red_shift) * 255) / max_red; |
581 uint32_t b = (((pixel & blue_mask) >> blue_shift) * 255) / max_blue; | 585 uint32_t b = (((pixel & blue_mask) >> blue_shift) * 255) / max_blue; |
582 uint32_t g = (((pixel & green_mask) >> green_shift) * 255) / max_green; | 586 uint32_t g = (((pixel & green_mask) >> green_shift) * 255) / max_green; |
583 // Write as 32-bit RGB. | 587 // Write as 32-bit RGB. |
584 dst_pos_32[x] = r << 16 | g << 8 | b; | 588 dst_pos_32[x] = r << 16 | g << 8 | b; |
585 } | 589 } |
586 dst_pos += capture_data->stride(); | 590 dst_pos += capture_data->stride(); |
587 src_pos += src_stride; | 591 src_pos += src_stride; |
588 } | 592 } |
589 } | 593 } |
590 | 594 |
591 } // namespace | 595 } // namespace |
592 | 596 |
593 // static | 597 // static |
594 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::Create() { | 598 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { |
595 scoped_ptr<VideoFrameCapturerLinux> capturer(new VideoFrameCapturerLinux()); | 599 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); |
596 if (!capturer->Init()) | 600 if (!capturer->Init()) |
597 capturer.reset(); | 601 capturer.reset(); |
598 return capturer.PassAs<VideoFrameCapturer>(); | 602 return capturer.PassAs<ScreenCapturer>(); |
599 } | 603 } |
600 | 604 |
601 // static | 605 // static |
602 scoped_ptr<VideoFrameCapturer> VideoFrameCapturer::CreateWithFactory( | 606 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithFactory( |
603 SharedBufferFactory* shared_buffer_factory) { | 607 SharedBufferFactory* shared_buffer_factory) { |
604 NOTIMPLEMENTED(); | 608 NOTIMPLEMENTED(); |
605 return scoped_ptr<VideoFrameCapturer>(); | 609 return scoped_ptr<ScreenCapturer>(); |
606 } | 610 } |
607 | 611 |
608 // static | 612 // static |
609 void VideoFrameCapturer::EnableXDamage(bool enable) { | 613 void ScreenCapturer::EnableXDamage(bool enable) { |
610 g_should_use_x_damage = enable; | 614 g_should_use_x_damage = enable; |
611 } | 615 } |
612 | 616 |
613 } // namespace remoting | 617 } // namespace media |
OLD | NEW |