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

Side by Side Diff: webrtc/modules/desktop_capture/screen_capturer_x11.cc

Issue 1861893002: Fix screen capturers to initialize on the same thread on which Start() is called. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « webrtc/modules/desktop_capture/screen_capturer_mac.mm ('k') | 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 /* 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
11 #include "webrtc/modules/desktop_capture/screen_capturer.h" 11 #include "webrtc/modules/desktop_capture/screen_capturer.h"
12 12
13 #include <string.h> 13 #include <string.h>
14 14
15 #include <memory> 15 #include <memory>
16 #include <set> 16 #include <set>
17 17
18 #include <X11/extensions/Xdamage.h> 18 #include <X11/extensions/Xdamage.h>
19 #include <X11/extensions/Xfixes.h> 19 #include <X11/extensions/Xfixes.h>
20 #include <X11/Xlib.h> 20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h> 21 #include <X11/Xutil.h>
22 22
23 #include "webrtc/base/checks.h" 23 #include "webrtc/base/checks.h"
24 #include "webrtc/base/thread_checker.h"
24 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" 25 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
25 #include "webrtc/modules/desktop_capture/desktop_frame.h" 26 #include "webrtc/modules/desktop_capture/desktop_frame.h"
26 #include "webrtc/modules/desktop_capture/differ.h" 27 #include "webrtc/modules/desktop_capture/differ.h"
27 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" 28 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
28 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" 29 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
29 #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" 30 #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
30 #include "webrtc/system_wrappers/include/logging.h" 31 #include "webrtc/system_wrappers/include/logging.h"
31 #include "webrtc/system_wrappers/include/tick_util.h" 32 #include "webrtc/system_wrappers/include/tick_util.h"
32 33
33 namespace webrtc { 34 namespace webrtc {
34 namespace { 35 namespace {
35 36
36 // A class to perform video frame capturing for Linux. 37 // A class to perform video frame capturing for Linux.
37 class ScreenCapturerLinux : public ScreenCapturer, 38 class ScreenCapturerLinux : public ScreenCapturer,
38 public SharedXDisplay::XEventHandler { 39 public SharedXDisplay::XEventHandler {
39 public: 40 public:
40 ScreenCapturerLinux(); 41 explicit ScreenCapturerLinux(const DesktopCaptureOptions& options);
41 virtual ~ScreenCapturerLinux(); 42 virtual ~ScreenCapturerLinux();
42 43
43 // TODO(ajwong): Do we really want this to be synchronous?
44 bool Init(const DesktopCaptureOptions& options);
45
46 // DesktopCapturer interface. 44 // DesktopCapturer interface.
47 void Start(Callback* delegate) override; 45 void Start(Callback* delegate) override;
48 void Capture(const DesktopRegion& region) override; 46 void Capture(const DesktopRegion& region) override;
49 47
50 // ScreenCapturer interface. 48 // ScreenCapturer interface.
51 bool GetScreenList(ScreenList* screens) override; 49 bool GetScreenList(ScreenList* screens) override;
52 bool SelectScreen(ScreenId id) override; 50 bool SelectScreen(ScreenId id) override;
53 51
54 private: 52 private:
55 Display* display() { return options_.x_display()->display(); } 53 Display* display() { return options_.x_display()->display(); }
56 54
55 bool Initialize();
56
57 void InitXDamage();
58
57 // SharedXDisplay::XEventHandler interface. 59 // SharedXDisplay::XEventHandler interface.
58 bool HandleXEvent(const XEvent& event) override; 60 bool HandleXEvent(const XEvent& event) override;
59 61
60 void InitXDamage();
61
62 // Capture screen pixels to the current buffer in the queue. In the DAMAGE 62 // Capture screen pixels to the current buffer in the queue. In the DAMAGE
63 // case, the ScreenCapturerHelper already holds the list of invalid rectangles 63 // case, the ScreenCapturerHelper already holds the list of invalid rectangles
64 // from HandleXEvent(). In the non-DAMAGE case, this captures the 64 // from HandleXEvent(). In the non-DAMAGE case, this captures the
65 // whole screen, then calculates some invalid rectangles that include any 65 // whole screen, then calculates some invalid rectangles that include any
66 // differences between this and the previous capture. 66 // differences between this and the previous capture.
67 DesktopFrame* CaptureScreen(); 67 DesktopFrame* CaptureScreen();
68 68
69 // Called when the screen configuration is changed. 69 // Called when the screen configuration is changed.
70 void ScreenConfigurationChanged(); 70 void ScreenConfigurationChanged();
71 71
72 // Synchronize the current buffer with |last_buffer_|, by copying pixels from 72 // Synchronize the current buffer with |last_buffer_|, by copying pixels from
73 // the area of |last_invalid_rects|. 73 // the area of |last_invalid_rects|.
74 // Note this only works on the assumption that kNumBuffers == 2, as 74 // Note this only works on the assumption that kNumBuffers == 2, as
75 // |last_invalid_rects| holds the differences from the previous buffer and 75 // |last_invalid_rects| holds the differences from the previous buffer and
76 // the one prior to that (which will then be the current buffer). 76 // the one prior to that (which will then be the current buffer).
77 void SynchronizeFrame(); 77 void SynchronizeFrame();
78 78
79 void DeinitXlib(); 79 void DeinitXlib();
80 80
81 rtc::ThreadChecker thread_checker_;
82
81 DesktopCaptureOptions options_; 83 DesktopCaptureOptions options_;
82 84
83 Callback* callback_; 85 Callback* callback_ = nullptr;
84 86
85 // X11 graphics context. 87 // X11 graphics context.
86 GC gc_; 88 GC gc_ = nullptr;
87 Window root_window_; 89 Window root_window_ = BadValue;
88 90
89 // XFixes. 91 // XFixes.
90 bool has_xfixes_; 92 bool has_xfixes_ = false;
91 int xfixes_event_base_; 93 int xfixes_event_base_ = -1;
92 int xfixes_error_base_; 94 int xfixes_error_base_ = -1;
93 95
94 // XDamage information. 96 // XDamage information.
95 bool use_damage_; 97 bool use_damage_ = false;
96 Damage damage_handle_; 98 Damage damage_handle_ = 0;
97 int damage_event_base_; 99 int damage_event_base_ = -1;
98 int damage_error_base_; 100 int damage_error_base_ = -1;
99 XserverRegion damage_region_; 101 XserverRegion damage_region_ = 0;
100 102
101 // Access to the X Server's pixel buffer. 103 // Access to the X Server's pixel buffer.
102 XServerPixelBuffer x_server_pixel_buffer_; 104 XServerPixelBuffer x_server_pixel_buffer_;
103 105
104 // 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
105 // recently captured screen. 107 // recently captured screen.
106 ScreenCapturerHelper helper_; 108 ScreenCapturerHelper helper_;
107 109
108 // Queue of the frames buffers. 110 // Queue of the frames buffers.
109 ScreenCaptureFrameQueue queue_; 111 ScreenCaptureFrameQueue queue_;
110 112
111 // 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
112 // current with the last buffer used. 114 // current with the last buffer used.
113 DesktopRegion last_invalid_region_; 115 DesktopRegion last_invalid_region_;
114 116
115 // |Differ| for use when polling for changes. 117 // |Differ| for use when polling for changes.
116 std::unique_ptr<Differ> differ_; 118 std::unique_ptr<Differ> differ_;
117 119
118 RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); 120 RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
119 }; 121 };
120 122
121 ScreenCapturerLinux::ScreenCapturerLinux() 123 ScreenCapturerLinux::ScreenCapturerLinux(const DesktopCaptureOptions& options)
122 : callback_(NULL), 124 : options_(options) {
123 gc_(NULL), 125 // ScreenCapturer can be used on a thread different from the thread on which
124 root_window_(BadValue), 126 // it's created.
125 has_xfixes_(false), 127 thread_checker_.DetachFromThread();
126 xfixes_event_base_(-1),
127 xfixes_error_base_(-1),
128 use_damage_(false),
129 damage_handle_(0),
130 damage_event_base_(-1),
131 damage_error_base_(-1),
132 damage_region_(0) {
133 helper_.SetLogGridSize(4);
134 } 128 }
135 129
136 ScreenCapturerLinux::~ScreenCapturerLinux() { 130 ScreenCapturerLinux::~ScreenCapturerLinux() {
131 RTC_DCHECK(thread_checker_.CalledOnValidThread());
132
137 options_.x_display()->RemoveEventHandler(ConfigureNotify, this); 133 options_.x_display()->RemoveEventHandler(ConfigureNotify, this);
138 if (use_damage_) { 134 if (use_damage_) {
139 options_.x_display()->RemoveEventHandler( 135 options_.x_display()->RemoveEventHandler(
140 damage_event_base_ + XDamageNotify, this); 136 damage_event_base_ + XDamageNotify, this);
141 } 137 }
142 DeinitXlib(); 138 DeinitXlib();
143 } 139 }
144 140
145 bool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) { 141 bool ScreenCapturerLinux::Initialize() {
146 options_ = options; 142 helper_.SetLogGridSize(4);
147 143
148 root_window_ = RootWindow(display(), DefaultScreen(display())); 144 root_window_ = RootWindow(display(), DefaultScreen(display()));
149 if (root_window_ == BadValue) { 145 if (root_window_ == BadValue) {
150 LOG(LS_ERROR) << "Unable to get the root window"; 146 LOG(LS_ERROR) << "Unable to get the root window";
151 DeinitXlib(); 147 DeinitXlib();
152 return false; 148 return false;
153 } 149 }
154 150
155 gc_ = XCreateGC(display(), root_window_, 0, NULL); 151 gc_ = XCreateGC(display(), root_window_, 0, NULL);
156 if (gc_ == NULL) { 152 if (gc_ == NULL) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 return; 187 return;
192 } 188 }
193 189
194 // Check for XDamage extension. 190 // Check for XDamage extension.
195 if (!XDamageQueryExtension(display(), &damage_event_base_, 191 if (!XDamageQueryExtension(display(), &damage_event_base_,
196 &damage_error_base_)) { 192 &damage_error_base_)) {
197 LOG(LS_INFO) << "X server does not support XDamage."; 193 LOG(LS_INFO) << "X server does not support XDamage.";
198 return; 194 return;
199 } 195 }
200 196
201 // TODO(lambroslambrou): Disable DAMAGE in situations where it is known
202 // to fail, such as when Desktop Effects are enabled, with graphics
203 // drivers (nVidia, ATI) that fail to report DAMAGE notifications
204 // properly.
205
206 // Request notifications every time the screen becomes damaged. 197 // Request notifications every time the screen becomes damaged.
207 damage_handle_ = XDamageCreate(display(), root_window_, 198 damage_handle_ = XDamageCreate(display(), root_window_,
208 XDamageReportNonEmpty); 199 XDamageReportNonEmpty);
209 if (!damage_handle_) { 200 if (!damage_handle_) {
210 LOG(LS_ERROR) << "Unable to initialize XDamage."; 201 LOG(LS_ERROR) << "Unable to initialize XDamage.";
211 return; 202 return;
212 } 203 }
213 204
214 // Create an XFixes server-side region to collate damage into. 205 // Create an XFixes server-side region to collate damage into.
215 damage_region_ = XFixesCreateRegion(display(), 0, 0); 206 damage_region_ = XFixesCreateRegion(display(), 0, 0);
216 if (!damage_region_) { 207 if (!damage_region_) {
217 XDamageDestroy(display(), damage_handle_); 208 XDamageDestroy(display(), damage_handle_);
218 LOG(LS_ERROR) << "Unable to create XFixes region."; 209 LOG(LS_ERROR) << "Unable to create XFixes region.";
219 return; 210 return;
220 } 211 }
221 212
222 options_.x_display()->AddEventHandler( 213 options_.x_display()->AddEventHandler(
223 damage_event_base_ + XDamageNotify, this); 214 damage_event_base_ + XDamageNotify, this);
224 215
225 use_damage_ = true; 216 use_damage_ = true;
226 LOG(LS_INFO) << "Using XDamage extension."; 217 LOG(LS_INFO) << "Using XDamage extension.";
227 } 218 }
228 219
229 void ScreenCapturerLinux::Start(Callback* callback) { 220 void ScreenCapturerLinux::Start(Callback* callback) {
221 RTC_DCHECK(thread_checker_.CalledOnValidThread());
230 RTC_DCHECK(!callback_); 222 RTC_DCHECK(!callback_);
231 RTC_DCHECK(callback); 223 RTC_DCHECK(callback);
232 224
233 callback_ = callback; 225 callback_ = callback;
226
227 if (!Initialize()) {
228 callback_->OnInitializationFailed();
229 }
234 } 230 }
235 231
236 void ScreenCapturerLinux::Capture(const DesktopRegion& region) { 232 void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
233 RTC_DCHECK(thread_checker_.CalledOnValidThread());
234
237 TickTime capture_start_time = TickTime::Now(); 235 TickTime capture_start_time = TickTime::Now();
238 236
239 queue_.MoveToNextFrame(); 237 queue_.MoveToNextFrame();
240 238
241 // Process XEvents for XDamage and cursor shape tracking. 239 // Process XEvents for XDamage and cursor shape tracking.
242 options_.x_display()->ProcessPendingXEvents(); 240 options_.x_display()->ProcessPendingXEvents();
243 241
244 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which 242 // ProcessPendingXEvents() may call ScreenConfigurationChanged() which
245 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still 243 // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still
246 // in a good shape. 244 // in a good shape.
(...skipping 25 matching lines...) Expand all
272 } 270 }
273 271
274 DesktopFrame* result = CaptureScreen(); 272 DesktopFrame* result = CaptureScreen();
275 last_invalid_region_ = result->updated_region(); 273 last_invalid_region_ = result->updated_region();
276 result->set_capture_time_ms( 274 result->set_capture_time_ms(
277 (TickTime::Now() - capture_start_time).Milliseconds()); 275 (TickTime::Now() - capture_start_time).Milliseconds());
278 callback_->OnCaptureCompleted(result); 276 callback_->OnCaptureCompleted(result);
279 } 277 }
280 278
281 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { 279 bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
280 RTC_DCHECK(thread_checker_.CalledOnValidThread());
282 RTC_DCHECK(screens->size() == 0); 281 RTC_DCHECK(screens->size() == 0);
282
283 // TODO(jiayl): implement screen enumeration. 283 // TODO(jiayl): implement screen enumeration.
284 Screen default_screen; 284 Screen default_screen;
285 default_screen.id = 0; 285 default_screen.id = 0;
286 screens->push_back(default_screen); 286 screens->push_back(default_screen);
287 return true; 287 return true;
288 } 288 }
289 289
290 bool ScreenCapturerLinux::SelectScreen(ScreenId id) { 290 bool ScreenCapturerLinux::SelectScreen(ScreenId id) {
291 RTC_DCHECK(thread_checker_.CalledOnValidThread());
291 // TODO(jiayl): implement screen selection. 292 // TODO(jiayl): implement screen selection.
292 return true; 293 return true;
293 } 294 }
294 295
295 bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) { 296 bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
297 RTC_DCHECK(thread_checker_.CalledOnValidThread());
298
296 if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) { 299 if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) {
297 const XDamageNotifyEvent* damage_event = 300 const XDamageNotifyEvent* damage_event =
298 reinterpret_cast<const XDamageNotifyEvent*>(&event); 301 reinterpret_cast<const XDamageNotifyEvent*>(&event);
299 if (damage_event->damage != damage_handle_) 302 if (damage_event->damage != damage_handle_)
300 return false; 303 return false;
301 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty); 304 RTC_DCHECK(damage_event->level == XDamageReportNonEmpty);
302 return true; 305 return true;
303 } else if (event.type == ConfigureNotify) { 306 } else if (event.type == ConfigureNotify) {
304 ScreenConfigurationChanged(); 307 ScreenConfigurationChanged();
305 return true; 308 return true;
306 } 309 }
307 return false; 310 return false;
308 } 311 }
309 312
310 DesktopFrame* ScreenCapturerLinux::CaptureScreen() { 313 DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
311 DesktopFrame* frame = queue_.current_frame()->Share(); 314 DesktopFrame* frame = queue_.current_frame()->Share();
312 assert(x_server_pixel_buffer_.window_size().equals(frame->size())); 315 RTC_DCHECK(x_server_pixel_buffer_.window_size().equals(frame->size()));
313 316
314 // Pass the screen size to the helper, so it can clip the invalid region if it 317 // Pass the screen size to the helper, so it can clip the invalid region if it
315 // expands that region to a grid. 318 // expands that region to a grid.
316 helper_.set_size_most_recent(frame->size()); 319 helper_.set_size_most_recent(frame->size());
317 320
318 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame 321 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame
319 // if any. If there isn't a previous frame, that means a screen-resolution 322 // if any. If there isn't a previous frame, that means a screen-resolution
320 // change occurred, and |invalid_rects| will be updated to include the whole 323 // change occurred, and |invalid_rects| will be updated to include the whole
321 // screen. 324 // screen.
322 if (use_damage_ && queue_.previous_frame()) 325 if (use_damage_ && queue_.previous_frame())
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 } 432 }
430 } 433 }
431 434
432 } // namespace 435 } // namespace
433 436
434 // static 437 // static
435 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { 438 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
436 if (!options.x_display()) 439 if (!options.x_display())
437 return NULL; 440 return NULL;
438 441
439 std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 442 return new ScreenCapturerLinux(options);
440 if (!capturer->Init(options))
441 capturer.reset();
442 return capturer.release();
443 } 443 }
444 444
445 } // namespace webrtc 445 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/desktop_capture/screen_capturer_mac.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698