Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(497)

Side by Side Diff: remoting/host/video_frame_capturer_linux.cc

Issue 11196012: Compare the sizes of current & previous frames before each capture. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 ptr_.reset(new uint8[buffer_size]); 56 ptr_.reset(new uint8[buffer_size]);
57 } 57 }
58 } 58 }
59 } 59 }
60 60
61 SkISize size() const { return size_; } 61 SkISize size() const { return size_; }
62 int bytes_per_row() const { return bytes_per_row_; } 62 int bytes_per_row() const { return bytes_per_row_; }
63 uint8* ptr() const { return ptr_.get(); } 63 uint8* ptr() const { return ptr_.get(); }
64 64
65 void set_needs_update() { needs_update_ = true; } 65 void set_needs_update() { needs_update_ = true; }
66 bool needs_update() const { return needs_update_; }
66 67
67 private: 68 private:
68 SkISize size_; 69 SkISize size_;
69 int bytes_per_row_; 70 int bytes_per_row_;
70 scoped_array<uint8> ptr_; 71 scoped_array<uint8> ptr_;
71 bool needs_update_; 72 bool needs_update_;
72 73
73 DISALLOW_COPY_AND_ASSIGN(VideoFrameBuffer); 74 DISALLOW_COPY_AND_ASSIGN(VideoFrameBuffer);
74 }; 75 };
75 76
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 int current_buffer_; 168 int current_buffer_;
168 169
169 // Format of pixels returned in buffer. 170 // Format of pixels returned in buffer.
170 media::VideoFrame::Format pixel_format_; 171 media::VideoFrame::Format pixel_format_;
171 172
172 // Invalid region from the previous capture. This is used to synchronize the 173 // Invalid region from the previous capture. This is used to synchronize the
173 // current with the last buffer used. 174 // current with the last buffer used.
174 SkRegion last_invalid_region_; 175 SkRegion last_invalid_region_;
175 176
176 // Last capture buffer used. 177 // Last capture buffer used.
177 uint8* last_buffer_; 178 int last_buffer_;
178 179
179 // |Differ| for use when polling for changes. 180 // |Differ| for use when polling for changes.
180 scoped_ptr<Differ> differ_; 181 scoped_ptr<Differ> differ_;
181 182
182 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerLinux); 183 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerLinux);
183 }; 184 };
184 185
185 VideoFrameCapturerLinux::VideoFrameCapturerLinux() 186 VideoFrameCapturerLinux::VideoFrameCapturerLinux()
186 : display_(NULL), 187 : display_(NULL),
187 gc_(NULL), 188 gc_(NULL),
188 root_window_(BadValue), 189 root_window_(BadValue),
189 has_xfixes_(false), 190 has_xfixes_(false),
190 xfixes_event_base_(-1), 191 xfixes_event_base_(-1),
191 xfixes_error_base_(-1), 192 xfixes_error_base_(-1),
192 use_damage_(false), 193 use_damage_(false),
193 damage_handle_(0), 194 damage_handle_(0),
194 damage_event_base_(-1), 195 damage_event_base_(-1),
195 damage_error_base_(-1), 196 damage_error_base_(-1),
196 damage_region_(0), 197 damage_region_(0),
197 current_buffer_(0), 198 current_buffer_(0),
198 pixel_format_(media::VideoFrame::RGB32), 199 pixel_format_(media::VideoFrame::RGB32),
199 last_buffer_(NULL) { 200 last_buffer_(kNumBuffers - 1) {
200 helper_.SetLogGridSize(4); 201 helper_.SetLogGridSize(4);
201 } 202 }
202 203
203 VideoFrameCapturerLinux::~VideoFrameCapturerLinux() { 204 VideoFrameCapturerLinux::~VideoFrameCapturerLinux() {
204 DeinitXlib(); 205 DeinitXlib();
205 } 206 }
206 207
207 bool VideoFrameCapturerLinux::Init() { 208 bool VideoFrameCapturerLinux::Init() {
208 // TODO(ajwong): We should specify the display string we are attaching to 209 // TODO(ajwong): We should specify the display string we are attaching to
209 // in the constructor. 210 // in the constructor.
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 311
311 void VideoFrameCapturerLinux::CaptureInvalidRegion( 312 void VideoFrameCapturerLinux::CaptureInvalidRegion(
312 const CaptureCompletedCallback& callback) { 313 const CaptureCompletedCallback& callback) {
313 // Process XEvents for XDamage and cursor shape tracking. 314 // Process XEvents for XDamage and cursor shape tracking.
314 ProcessPendingXEvents(); 315 ProcessPendingXEvents();
315 316
316 // Resize the current buffer if there was a recent change of 317 // Resize the current buffer if there was a recent change of
317 // screen-resolution. 318 // screen-resolution.
318 VideoFrameBuffer &current = buffers_[current_buffer_]; 319 VideoFrameBuffer &current = buffers_[current_buffer_];
319 current.Update(display_, root_window_); 320 current.Update(display_, root_window_);
320 // Also refresh the Differ helper used by CaptureFrame(), if needed. 321
321 if (!use_damage_ && !last_buffer_) { 322 // Mark the previous frame for update if its dimensions no longer match.
322 differ_.reset(new Differ(current.size().width(), current.size().height(), 323 if (buffers_[last_buffer_].size() != current.size()) {
323 kBytesPerPixel, current.bytes_per_row())); 324 buffers_[last_buffer_].set_needs_update();
325
326 // Also refresh the Differ helper used by CaptureFrame(), if needed.
327 if (!use_damage_) {
328 differ_.reset(new Differ(current.size().width(), current.size().height(),
329 kBytesPerPixel, current.bytes_per_row()));
330 }
324 } 331 }
325 332
326 scoped_refptr<CaptureData> capture_data(CaptureFrame()); 333 scoped_refptr<CaptureData> capture_data(CaptureFrame());
327 334
335 // Swap the current & previous buffers ready for the next capture.
336 last_invalid_region_ = capture_data->dirty_region();
337 last_buffer_ = current_buffer_;
328 current_buffer_ = (current_buffer_ + 1) % kNumBuffers; 338 current_buffer_ = (current_buffer_ + 1) % kNumBuffers;
329 339
330 callback.Run(capture_data); 340 callback.Run(capture_data);
331 } 341 }
332 342
333 void VideoFrameCapturerLinux::ProcessPendingXEvents() { 343 void VideoFrameCapturerLinux::ProcessPendingXEvents() {
334 // Find the number of events that are outstanding "now." We don't just loop 344 // Find the number of events that are outstanding "now." We don't just loop
335 // on XPending because we want to guarantee this terminates. 345 // on XPending because we want to guarantee this terminates.
336 int events_to_process = XPending(display_); 346 int events_to_process = XPending(display_);
337 XEvent e; 347 XEvent e;
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 media::VideoFrame::RGB32); 413 media::VideoFrame::RGB32);
404 414
405 // Pass the screen size to the helper, so it can clip the invalid region if it 415 // Pass the screen size to the helper, so it can clip the invalid region if it
406 // expands that region to a grid. 416 // expands that region to a grid.
407 helper_.set_size_most_recent(capture_data->size()); 417 helper_.set_size_most_recent(capture_data->size());
408 418
409 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame 419 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame
410 // if any. If there isn't a previous frame, that means a screen-resolution 420 // if any. If there isn't a previous frame, that means a screen-resolution
411 // change occurred, and |invalid_rects| will be updated to include the whole 421 // change occurred, and |invalid_rects| will be updated to include the whole
412 // screen. 422 // screen.
413 if (use_damage_ && last_buffer_) 423 if (use_damage_ && !buffers_[last_buffer_].needs_update())
414 SynchronizeFrame(); 424 SynchronizeFrame();
415 425
416 SkRegion invalid_region; 426 SkRegion invalid_region;
417 427
418 x_server_pixel_buffer_.Synchronize(); 428 x_server_pixel_buffer_.Synchronize();
419 if (use_damage_ && last_buffer_) { 429 if (use_damage_ && !buffers_[last_buffer_].needs_update()) {
420 // Atomically fetch and clear the damage region. 430 // Atomically fetch and clear the damage region.
421 XDamageSubtract(display_, damage_handle_, None, damage_region_); 431 XDamageSubtract(display_, damage_handle_, None, damage_region_);
422 int nRects = 0; 432 int nRects = 0;
423 XRectangle bounds; 433 XRectangle bounds;
424 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, 434 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_,
425 &nRects, &bounds); 435 &nRects, &bounds);
426 for (int i=0; i<nRects; ++i) { 436 for (int i=0; i<nRects; ++i) {
427 invalid_region.op(SkIRect::MakeXYWH(rects[i].x, rects[i].y, 437 invalid_region.op(SkIRect::MakeXYWH(rects[i].x, rects[i].y,
428 rects[i].width, rects[i].height), 438 rects[i].width, rects[i].height),
429 SkRegion::kUnion_Op); 439 SkRegion::kUnion_Op);
430 } 440 }
431 XFree(rects); 441 XFree(rects);
432 helper_.InvalidateRegion(invalid_region); 442 helper_.InvalidateRegion(invalid_region);
433 443
434 // Capture the damaged portions of the desktop. 444 // Capture the damaged portions of the desktop.
435 helper_.SwapInvalidRegion(&invalid_region); 445 helper_.SwapInvalidRegion(&invalid_region);
436 for (SkRegion::Iterator it(invalid_region); !it.done(); it.next()) { 446 for (SkRegion::Iterator it(invalid_region); !it.done(); it.next()) {
437 CaptureRect(it.rect(), capture_data); 447 CaptureRect(it.rect(), capture_data);
438 } 448 }
439 } else { 449 } else {
440 // Doing full-screen polling, or this is the first capture after a 450 // Doing full-screen polling, or this is the first capture after a
441 // screen-resolution change. In either case, need a full-screen capture. 451 // screen-resolution change. In either case, need a full-screen capture.
442 SkIRect screen_rect = SkIRect::MakeWH(buffer.size().width(), 452 SkIRect screen_rect = SkIRect::MakeWH(buffer.size().width(),
443 buffer.size().height()); 453 buffer.size().height());
444 CaptureRect(screen_rect, capture_data); 454 CaptureRect(screen_rect, capture_data);
445 455
446 if (last_buffer_) { 456 if (!buffers_[last_buffer_].needs_update()) {
447 // Full-screen polling, so calculate the invalid rects here, based on the 457 // Full-screen polling, so calculate the invalid rects here, based on the
448 // changed pixels between current and previous buffers. 458 // changed pixels between current and previous buffers.
449 DCHECK(differ_ != NULL); 459 DCHECK(differ_ != NULL);
450 differ_->CalcDirtyRegion(last_buffer_, buffer.ptr(), &invalid_region); 460 VideoFrameBuffer& last_buffer = buffers_[last_buffer_];
461 differ_->CalcDirtyRegion(
462 last_buffer.ptr(), buffer.ptr(), &invalid_region);
451 } else { 463 } else {
452 // No previous buffer, so always invalidate the whole screen, whether 464 // No previous buffer, so always invalidate the whole screen, whether
453 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a 465 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a
454 // full-screen notification after a screen-resolution change, so 466 // full-screen notification after a screen-resolution change, so
455 // this is done here. 467 // this is done here.
456 invalid_region.op(screen_rect, SkRegion::kUnion_Op); 468 invalid_region.op(screen_rect, SkRegion::kUnion_Op);
457 } 469 }
458 } 470 }
459 471
460 capture_data->mutable_dirty_region() = invalid_region; 472 capture_data->mutable_dirty_region() = invalid_region;
461 last_invalid_region_ = invalid_region;
462 last_buffer_ = buffer.ptr();
463 return capture_data; 473 return capture_data;
464 } 474 }
465 475
466 void VideoFrameCapturerLinux::ScreenConfigurationChanged() { 476 void VideoFrameCapturerLinux::ScreenConfigurationChanged() {
467 last_buffer_ = NULL;
468 for (int i = 0; i < kNumBuffers; ++i) { 477 for (int i = 0; i < kNumBuffers; ++i) {
469 buffers_[i].set_needs_update(); 478 buffers_[i].set_needs_update();
470 } 479 }
471 helper_.ClearInvalidRegion(); 480 helper_.ClearInvalidRegion();
472 x_server_pixel_buffer_.Init(display_); 481 x_server_pixel_buffer_.Init(display_);
473 } 482 }
474 483
475 void VideoFrameCapturerLinux::SynchronizeFrame() { 484 void VideoFrameCapturerLinux::SynchronizeFrame() {
476 // Synchronize the current buffer with the previous one since we do not 485 // Synchronize the current buffer with the previous one since we do not
477 // capture the entire desktop. Note that encoder may be reading from the 486 // capture the entire desktop. Note that encoder may be reading from the
478 // previous buffer at this time so thread access complaints are false 487 // previous buffer at this time so thread access complaints are false
479 // positives. 488 // positives.
480 489
481 // TODO(hclam): We can reduce the amount of copying here by subtracting 490 // TODO(hclam): We can reduce the amount of copying here by subtracting
482 // |capturer_helper_|s region from |last_invalid_region_|. 491 // |capturer_helper_|s region from |last_invalid_region_|.
483 // http://crbug.com/92354 492 // http://crbug.com/92354
484 DCHECK(last_buffer_); 493 DCHECK(!buffers_[last_buffer_].needs_update());
494 DCHECK_NE(last_buffer_, current_buffer_);
485 VideoFrameBuffer& buffer = buffers_[current_buffer_]; 495 VideoFrameBuffer& buffer = buffers_[current_buffer_];
496 VideoFrameBuffer& last_buffer = buffers_[last_buffer_];
486 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { 497 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) {
487 const SkIRect& r = it.rect(); 498 const SkIRect& r = it.rect();
488 int offset = r.fTop * buffer.bytes_per_row() + r.fLeft * kBytesPerPixel; 499 int offset = r.fTop * buffer.bytes_per_row() + r.fLeft * kBytesPerPixel;
489 for (int i = 0; i < r.height(); ++i) { 500 for (int i = 0; i < r.height(); ++i) {
490 memcpy(buffer.ptr() + offset, last_buffer_ + offset, 501 memcpy(buffer.ptr() + offset, last_buffer.ptr() + offset,
491 r.width() * kBytesPerPixel); 502 r.width() * kBytesPerPixel);
492 offset += buffer.size().width() * kBytesPerPixel; 503 offset += buffer.size().width() * kBytesPerPixel;
493 } 504 }
494 } 505 }
495 } 506 }
496 507
497 void VideoFrameCapturerLinux::DeinitXlib() { 508 void VideoFrameCapturerLinux::DeinitXlib() {
498 if (gc_) { 509 if (gc_) {
499 XFreeGC(display_, gc_); 510 XFreeGC(display_, gc_);
500 gc_ = NULL; 511 gc_ = NULL;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 } 628 }
618 return capturer; 629 return capturer;
619 } 630 }
620 631
621 // static 632 // static
622 void VideoFrameCapturer::EnableXDamage(bool enable) { 633 void VideoFrameCapturer::EnableXDamage(bool enable) {
623 g_should_use_x_damage = enable; 634 g_should_use_x_damage = enable;
624 } 635 }
625 636
626 } // namespace remoting 637 } // namespace remoting
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698