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

Side by Side Diff: media/video/capture/screen/screen_capture_device.cc

Issue 13983010: Use webrtc::DesktopCapturer for screen capturer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: q Created 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "media/video/capture/screen/screen_capture_device.h" 5 #include "media/video/capture/screen/screen_capture_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/sequenced_task_runner.h" 10 #include "base/sequenced_task_runner.h"
11 #include "base/synchronization/lock.h" 11 #include "base/synchronization/lock.h"
12 #include "media/video/capture/screen/mouse_cursor_shape.h" 12 #include "media/video/capture/screen/mouse_cursor_shape.h"
13 #include "media/video/capture/screen/screen_capture_data.h"
14 #include "third_party/skia/include/core/SkCanvas.h" 13 #include "third_party/skia/include/core/SkCanvas.h"
15 #include "third_party/skia/include/core/SkDevice.h" 14 #include "third_party/skia/include/core/SkDevice.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
16 16
17 namespace media { 17 namespace media {
18 18
19 namespace { 19 namespace {
20 const int kBytesPerPixel = 4; 20 const int kBytesPerPixel = 4;
21 } // namespace 21 } // namespace
22 22
23 class ScreenCaptureDevice::Core 23 class ScreenCaptureDevice::Core
24 : public base::RefCountedThreadSafe<Core>, 24 : public base::RefCountedThreadSafe<Core>,
25 public ScreenCapturer::Delegate { 25 public webrtc::DesktopCapturer::Callback {
26 public: 26 public:
27 explicit Core(scoped_refptr<base::SequencedTaskRunner> task_runner); 27 explicit Core(scoped_refptr<base::SequencedTaskRunner> task_runner);
28 28
29 // Helper used in tests to supply a fake capturer. 29 // Helper used in tests to supply a fake capturer.
30 void SetScreenCapturerForTest(scoped_ptr<ScreenCapturer> capturer) { 30 void SetScreenCapturerForTest(scoped_ptr<ScreenCapturer> capturer) {
31 screen_capturer_ = capturer.Pass(); 31 screen_capturer_ = capturer.Pass();
32 } 32 }
33 33
34 // Implementation of VideoCaptureDevice methods. 34 // Implementation of VideoCaptureDevice methods.
35 void Allocate(int width, int height, 35 void Allocate(int width, int height,
36 int frame_rate, 36 int frame_rate,
37 EventHandler* event_handler); 37 EventHandler* event_handler);
38 void Start(); 38 void Start();
39 void Stop(); 39 void Stop();
40 void DeAllocate(); 40 void DeAllocate();
41 41
42 // ScreenCapturer::Delegate interface. Called by |screen_capturer_| on the
43 // |task_runner_|.
44 virtual void OnCaptureCompleted(
45 scoped_refptr<ScreenCaptureData> capture_data) OVERRIDE;
46 virtual void OnCursorShapeChanged(
47 scoped_ptr<MouseCursorShape> cursor_shape) OVERRIDE;
48
49 private: 42 private:
50 friend class base::RefCountedThreadSafe<Core>; 43 friend class base::RefCountedThreadSafe<Core>;
51 virtual ~Core(); 44 virtual ~Core();
52 45
46 // webrtc::DesktopCapturer::Callback interface
47 virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
48 virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE;
49
53 // Helper methods that run on the |task_runner_|. Posted from the 50 // Helper methods that run on the |task_runner_|. Posted from the
54 // corresponding public methods. 51 // corresponding public methods.
55 void DoAllocate(int frame_rate); 52 void DoAllocate(int frame_rate);
56 void DoStart(); 53 void DoStart();
57 void DoStop(); 54 void DoStop();
58 void DoDeAllocate(); 55 void DoDeAllocate();
59 56
60 // Helper to schedule capture tasks. 57 // Helper to schedule capture tasks.
61 void ScheduleCaptureTimer(); 58 void ScheduleCaptureTimer();
62 59
(...skipping 18 matching lines...) Expand all
81 78
82 // The underlying ScreenCapturer instance used to capture frames. 79 // The underlying ScreenCapturer instance used to capture frames.
83 scoped_ptr<ScreenCapturer> screen_capturer_; 80 scoped_ptr<ScreenCapturer> screen_capturer_;
84 81
85 // After Allocate() is called we need to call OnFrameInfo() method of the 82 // After Allocate() is called we need to call OnFrameInfo() method of the
86 // |event_handler_| to specify the size of the frames this capturer will 83 // |event_handler_| to specify the size of the frames this capturer will
87 // produce. In order to get screen size from |screen_capturer_| we need to 84 // produce. In order to get screen size from |screen_capturer_| we need to
88 // capture at least one frame. Once screen size is known it's stored in 85 // capture at least one frame. Once screen size is known it's stored in
89 // |frame_size_|. 86 // |frame_size_|.
90 bool waiting_for_frame_size_; 87 bool waiting_for_frame_size_;
91 SkISize frame_size_; 88 webrtc::DesktopSize frame_size_;
92 SkBitmap resized_bitmap_; 89 SkBitmap resized_bitmap_;
93 90
94 // True between DoStart() and DoStop(). Can't just check |event_handler_| 91 // True between DoStart() and DoStop(). Can't just check |event_handler_|
95 // because |event_handler_| is used on the caller thread. 92 // because |event_handler_| is used on the caller thread.
96 bool started_; 93 bool started_;
97 94
98 // True when we have delayed OnCaptureTimer() task posted on 95 // True when we have delayed OnCaptureTimer() task posted on
99 // |task_runner_|. 96 // |task_runner_|.
100 bool capture_task_posted_; 97 bool capture_task_posted_;
101 98
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 } 142 }
146 143
147 void ScreenCaptureDevice::Core::DeAllocate() { 144 void ScreenCaptureDevice::Core::DeAllocate() {
148 { 145 {
149 base::AutoLock auto_lock(event_handler_lock_); 146 base::AutoLock auto_lock(event_handler_lock_);
150 event_handler_ = NULL; 147 event_handler_ = NULL;
151 } 148 }
152 task_runner_->PostTask(FROM_HERE, base::Bind(&Core::DoDeAllocate, this)); 149 task_runner_->PostTask(FROM_HERE, base::Bind(&Core::DoDeAllocate, this));
153 } 150 }
154 151
152 webrtc::SharedMemory*
153 ScreenCaptureDevice::Core::CreateSharedMemory(size_t size) {
154 return NULL;
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: Consider having the default implementation of
Sergey Ulanov 2013/05/07 22:25:50 Let's do it later, after this code is moved to web
alexeypa (please no reviews) 2013/05/08 22:24:59 OK.
155 }
156
155 void ScreenCaptureDevice::Core::OnCaptureCompleted( 157 void ScreenCaptureDevice::Core::OnCaptureCompleted(
156 scoped_refptr<ScreenCaptureData> capture_data) { 158 webrtc::DesktopFrame* frame) {
157 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 159 DCHECK(task_runner_->RunsTasksOnCurrentThread());
158 DCHECK(capture_in_progress_); 160 DCHECK(capture_in_progress_);
159 DCHECK(!capture_data->size().isEmpty());
160 161
161 capture_in_progress_ = false; 162 capture_in_progress_ = false;
162 163
164 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
165
163 if (waiting_for_frame_size_) { 166 if (waiting_for_frame_size_) {
164 frame_size_ = capture_data->size(); 167 frame_size_ = frame->size();
165 waiting_for_frame_size_ = false; 168 waiting_for_frame_size_ = false;
166 169
167 // Inform the EventHandler of the video frame dimensions and format. 170 // Inform the EventHandler of the video frame dimensions and format.
168 VideoCaptureCapability caps; 171 VideoCaptureCapability caps;
169 caps.width = frame_size_.width(); 172 caps.width = frame_size_.width();
170 caps.height = frame_size_.height(); 173 caps.height = frame_size_.height();
171 caps.frame_rate = frame_rate_; 174 caps.frame_rate = frame_rate_;
172 caps.color = VideoCaptureCapability::kARGB; 175 caps.color = VideoCaptureCapability::kARGB;
173 caps.expected_capture_delay = 176 caps.expected_capture_delay =
174 base::Time::kMillisecondsPerSecond / frame_rate_; 177 base::Time::kMillisecondsPerSecond / frame_rate_;
175 caps.interlaced = false; 178 caps.interlaced = false;
176 179
177 base::AutoLock auto_lock(event_handler_lock_); 180 base::AutoLock auto_lock(event_handler_lock_);
178 if (event_handler_) 181 if (event_handler_)
179 event_handler_->OnFrameInfo(caps); 182 event_handler_->OnFrameInfo(caps);
180 } 183 }
181 184
182 if (!started_) 185 if (!started_)
183 return; 186 return;
184 187
185 size_t buffer_size = frame_size_.width() * frame_size_.height() * 188 size_t buffer_size = frame_size_.width() * frame_size_.height() *
186 ScreenCaptureData::kBytesPerPixel; 189 webrtc::DesktopFrame::kBytesPerPixel;
187 190
188 if (capture_data->size() == frame_size_) { 191 if (frame->size().equals(frame_size_)) {
alexeypa (please no reviews) 2013/04/26 21:33:58 |frame| can be NULL if the capturer could not capt
Sergey Ulanov 2013/05/07 22:25:50 Done.
189 // If the captured frame matches the requested size, we don't need to 192 // If the captured frame matches the requested size, we don't need to
190 // resize it. 193 // resize it.
191 resized_bitmap_.reset(); 194 resized_bitmap_.reset();
192 195
193 base::AutoLock auto_lock(event_handler_lock_); 196 base::AutoLock auto_lock(event_handler_lock_);
194 if (event_handler_) { 197 if (event_handler_) {
195 event_handler_->OnIncomingCapturedFrame( 198 event_handler_->OnIncomingCapturedFrame(
196 capture_data->data(), buffer_size, base::Time::Now(), 199 frame->data(), buffer_size, base::Time::Now(), 0, false, false);
197 0, false, false);
198 } 200 }
199 return; 201 return;
200 } 202 }
201 203
202 // In case screen size has changed we need to resize the image. Resized image 204 // In case screen size has changed we need to resize the image. Resized image
203 // is stored to |resized_bitmap_|. Only regions of the screen that are 205 // is stored to |resized_bitmap_|. Only regions of the screen that are
204 // changing are copied. 206 // changing are copied.
205 207
206 SkRegion dirty_region = capture_data->dirty_region(); 208 webrtc::DesktopRegion dirty_region = frame->updated_region();
207 209
208 if (resized_bitmap_.width() != frame_size_.width() || 210 if (resized_bitmap_.width() != frame_size_.width() ||
209 resized_bitmap_.height() != frame_size_.height()) { 211 resized_bitmap_.height() != frame_size_.height()) {
210 resized_bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 212 resized_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
211 frame_size_.width(), frame_size_.height()); 213 frame_size_.width(), frame_size_.height());
212 resized_bitmap_.setIsOpaque(true); 214 resized_bitmap_.setIsOpaque(true);
213 resized_bitmap_.allocPixels(); 215 resized_bitmap_.allocPixels();
214 dirty_region.setRect(SkIRect::MakeSize(frame_size_)); 216 dirty_region.SetRect(
217 webrtc::DesktopRect::MakeWH(frame_size_.width(), frame_size_.height()));
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: Consider adding MakeSize() to DesktopRect.
Sergey Ulanov 2013/05/07 22:25:50 Done.
215 } 218 }
216 219
217 float scale_x = static_cast<float>(frame_size_.width()) / 220 float scale_x = static_cast<float>(frame_size_.width()) /
218 capture_data->size().width(); 221 frame->size().width();
219 float scale_y = static_cast<float>(frame_size_.height()) / 222 float scale_y = static_cast<float>(frame_size_.height()) /
220 capture_data->size().height(); 223 frame->size().height();
221 float scale; 224 float scale;
222 float x, y; 225 float x, y;
223 // Center the image in case aspect ratio is different. 226 // Center the image in case aspect ratio is different.
224 if (scale_x > scale_y) { 227 if (scale_x > scale_y) {
225 scale = scale_y; 228 scale = scale_y;
226 x = (scale_x - scale_y) / scale * frame_size_.width() / 2.0; 229 x = (scale_x - scale_y) / scale * frame_size_.width() / 2.0;
227 y = 0.f; 230 y = 0.f;
228 } else { 231 } else {
229 scale = scale_x; 232 scale = scale_x;
230 x = 0.f; 233 x = 0.f;
231 y = (scale_y - scale_x) / scale * frame_size_.height() / 2.0; 234 y = (scale_y - scale_x) / scale * frame_size_.height() / 2.0;
232 } 235 }
233 236
234 // Create skia device and canvas that draw to |resized_bitmap_|. 237 // Create skia device and canvas that draw to |resized_bitmap_|.
235 SkDevice device(resized_bitmap_); 238 SkDevice device(resized_bitmap_);
236 SkCanvas canvas(&device); 239 SkCanvas canvas(&device);
237 canvas.scale(scale, scale); 240 canvas.scale(scale, scale);
238 241
239 int source_stride = capture_data->stride(); 242 int source_stride = frame->stride();
240 for (SkRegion::Iterator i(dirty_region); !i.done(); i.next()) { 243 for (webrtc::DesktopRegion::Iterator i(dirty_region); !i.IsAtEnd();
244 i.Advance()) {
241 SkBitmap source_bitmap; 245 SkBitmap source_bitmap;
242 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 246 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
243 i.rect().width(), i.rect().height(), 247 i.rect().width(), i.rect().height(),
244 source_stride); 248 source_stride);
245 source_bitmap.setIsOpaque(true); 249 source_bitmap.setIsOpaque(true);
246 source_bitmap.setPixels( 250 source_bitmap.setPixels(
247 capture_data->data() + i.rect().top() * source_stride + 251 frame->data() + i.rect().top() * source_stride +
248 i.rect().left() * ScreenCaptureData::kBytesPerPixel); 252 i.rect().left() * webrtc::DesktopFrame::kBytesPerPixel);
249 canvas.drawBitmap(source_bitmap, i.rect().left() + x / scale, 253 canvas.drawBitmap(source_bitmap, i.rect().left() + x / scale,
250 i.rect().top() + y / scale, NULL); 254 i.rect().top() + y / scale, NULL);
251 } 255 }
252 256
253 base::AutoLock auto_lock(event_handler_lock_); 257 base::AutoLock auto_lock(event_handler_lock_);
254 if (event_handler_) { 258 if (event_handler_) {
255 event_handler_->OnIncomingCapturedFrame( 259 event_handler_->OnIncomingCapturedFrame(
256 reinterpret_cast<uint8*>(resized_bitmap_.getPixels()), buffer_size, 260 reinterpret_cast<uint8*>(resized_bitmap_.getPixels()), buffer_size,
257 base::Time::Now(), 0, false, false); 261 base::Time::Now(), 0, false, false);
258 } 262 }
259 } 263 }
260 264
261 void ScreenCaptureDevice::Core::OnCursorShapeChanged(
262 scoped_ptr<MouseCursorShape> cursor_shape) {
263 // TODO(sergeyu): Store mouse cursor shape and then render it to each captured
264 // frame. crbug.com/173265 .
265 DCHECK(task_runner_->RunsTasksOnCurrentThread());
266 }
267
268 void ScreenCaptureDevice::Core::DoAllocate(int frame_rate) { 265 void ScreenCaptureDevice::Core::DoAllocate(int frame_rate) {
269 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 266 DCHECK(task_runner_->RunsTasksOnCurrentThread());
270 267
271 frame_rate_ = frame_rate; 268 frame_rate_ = frame_rate;
272 269
273 // Create and start frame capturer. 270 // Create and start frame capturer.
274 #if defined(OS_CHROMEOS) && !defined(ARCH_CPU_ARMEL) 271 #if defined(OS_CHROMEOS) && !defined(ARCH_CPU_ARMEL)
275 // ScreenCapturerX11 polls by default, due to poor driver support for DAMAGE. 272 // ScreenCapturerX11 polls by default, due to poor driver support for DAMAGE.
276 // ChromeOS' drivers [can be patched to] support DAMAGE properly, so use it. 273 // ChromeOS' drivers [can be patched to] support DAMAGE properly, so use it.
277 // However ARM driver seems to not support this properly, so disable it for 274 // However ARM driver seems to not support this properly, so disable it for
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 328
332 if (!started_) 329 if (!started_)
333 return; 330 return;
334 331
335 // Schedule a task for the next frame. 332 // Schedule a task for the next frame.
336 ScheduleCaptureTimer(); 333 ScheduleCaptureTimer();
337 DoCapture(); 334 DoCapture();
338 } 335 }
339 336
340 void ScreenCaptureDevice::Core::DoCapture() { 337 void ScreenCaptureDevice::Core::DoCapture() {
338 DCHECK(task_runner_->RunsTasksOnCurrentThread());
341 DCHECK(!capture_in_progress_); 339 DCHECK(!capture_in_progress_);
342 340
343 capture_in_progress_ = true; 341 capture_in_progress_ = true;
344 screen_capturer_->CaptureFrame(); 342 screen_capturer_->Capture(webrtc::DesktopRegion());
345 343
346 // Assume that ScreenCapturer always calls OnCaptureCompleted() 344 // Currently on synchronous implementations of DesktopCapturer are supported.
Wez 2013/04/26 18:48:14 typo: on -> only
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: on -> only.
Sergey Ulanov 2013/05/07 22:25:50 Done.
Sergey Ulanov 2013/05/07 22:25:50 Done.
347 // callback before it returns.
348 //
349 // TODO(sergeyu): Fix ScreenCapturer to return video frame
350 // synchronously instead of using Delegate interface.
351 DCHECK(!capture_in_progress_); 345 DCHECK(!capture_in_progress_);
352 } 346 }
353 347
354 ScreenCaptureDevice::ScreenCaptureDevice( 348 ScreenCaptureDevice::ScreenCaptureDevice(
355 scoped_refptr<base::SequencedTaskRunner> task_runner) 349 scoped_refptr<base::SequencedTaskRunner> task_runner)
356 : core_(new Core(task_runner)) { 350 : core_(new Core(task_runner)) {
357 name_.device_name = "Screen"; 351 name_.device_name = "Screen";
358 } 352 }
359 353
360 ScreenCaptureDevice::~ScreenCaptureDevice() { 354 ScreenCaptureDevice::~ScreenCaptureDevice() {
(...skipping 21 matching lines...) Expand all
382 376
383 void ScreenCaptureDevice::DeAllocate() { 377 void ScreenCaptureDevice::DeAllocate() {
384 core_->DeAllocate(); 378 core_->DeAllocate();
385 } 379 }
386 380
387 const VideoCaptureDevice::Name& ScreenCaptureDevice::device_name() { 381 const VideoCaptureDevice::Name& ScreenCaptureDevice::device_name() {
388 return name_; 382 return name_;
389 } 383 }
390 384
391 } // namespace media 385 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698