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

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: Created 7 years, 7 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;
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 if (!frame) {
165 LOG(ERROR) << "Failed to capture a frame.";
166 event_handler_->OnError();
167 return;
168 }
169
170 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
171
163 if (waiting_for_frame_size_) { 172 if (waiting_for_frame_size_) {
164 frame_size_ = capture_data->size(); 173 frame_size_ = frame->size();
165 waiting_for_frame_size_ = false; 174 waiting_for_frame_size_ = false;
166 175
167 // Inform the EventHandler of the video frame dimensions and format. 176 // Inform the EventHandler of the video frame dimensions and format.
168 VideoCaptureCapability caps; 177 VideoCaptureCapability caps;
169 caps.width = frame_size_.width(); 178 caps.width = frame_size_.width();
170 caps.height = frame_size_.height(); 179 caps.height = frame_size_.height();
171 caps.frame_rate = frame_rate_; 180 caps.frame_rate = frame_rate_;
172 caps.color = VideoCaptureCapability::kARGB; 181 caps.color = VideoCaptureCapability::kARGB;
173 caps.expected_capture_delay = 182 caps.expected_capture_delay =
174 base::Time::kMillisecondsPerSecond / frame_rate_; 183 base::Time::kMillisecondsPerSecond / frame_rate_;
175 caps.interlaced = false; 184 caps.interlaced = false;
176 185
177 base::AutoLock auto_lock(event_handler_lock_); 186 base::AutoLock auto_lock(event_handler_lock_);
178 if (event_handler_) 187 if (event_handler_)
179 event_handler_->OnFrameInfo(caps); 188 event_handler_->OnFrameInfo(caps);
180 } 189 }
181 190
182 if (!started_) 191 if (!started_)
183 return; 192 return;
184 193
185 size_t buffer_size = frame_size_.width() * frame_size_.height() * 194 size_t buffer_size = frame_size_.width() * frame_size_.height() *
186 ScreenCaptureData::kBytesPerPixel; 195 webrtc::DesktopFrame::kBytesPerPixel;
187 196
188 if (capture_data->size() == frame_size_) { 197 if (frame->size().equals(frame_size_)) {
189 // If the captured frame matches the requested size, we don't need to 198 // If the captured frame matches the requested size, we don't need to
190 // resize it. 199 // resize it.
191 resized_bitmap_.reset(); 200 resized_bitmap_.reset();
192 201
193 base::AutoLock auto_lock(event_handler_lock_); 202 base::AutoLock auto_lock(event_handler_lock_);
194 if (event_handler_) { 203 if (event_handler_) {
195 event_handler_->OnIncomingCapturedFrame( 204 event_handler_->OnIncomingCapturedFrame(
196 capture_data->data(), buffer_size, base::Time::Now(), 205 frame->data(), buffer_size, base::Time::Now(), 0, false, false);
197 0, false, false);
198 } 206 }
199 return; 207 return;
200 } 208 }
201 209
202 // In case screen size has changed we need to resize the image. Resized image 210 // 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 211 // is stored to |resized_bitmap_|. Only regions of the screen that are
204 // changing are copied. 212 // changing are copied.
205 213
206 SkRegion dirty_region = capture_data->dirty_region(); 214 webrtc::DesktopRegion dirty_region = frame->updated_region();
207 215
208 if (resized_bitmap_.width() != frame_size_.width() || 216 if (resized_bitmap_.width() != frame_size_.width() ||
209 resized_bitmap_.height() != frame_size_.height()) { 217 resized_bitmap_.height() != frame_size_.height()) {
210 resized_bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 218 resized_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
211 frame_size_.width(), frame_size_.height()); 219 frame_size_.width(), frame_size_.height());
212 resized_bitmap_.setIsOpaque(true); 220 resized_bitmap_.setIsOpaque(true);
213 resized_bitmap_.allocPixels(); 221 resized_bitmap_.allocPixels();
214 dirty_region.setRect(SkIRect::MakeSize(frame_size_)); 222 dirty_region.SetRect(webrtc::DesktopRect::MakeSize(frame_size_));
215 } 223 }
216 224
217 float scale_x = static_cast<float>(frame_size_.width()) / 225 float scale_x = static_cast<float>(frame_size_.width()) /
218 capture_data->size().width(); 226 frame->size().width();
219 float scale_y = static_cast<float>(frame_size_.height()) / 227 float scale_y = static_cast<float>(frame_size_.height()) /
220 capture_data->size().height(); 228 frame->size().height();
221 float scale; 229 float scale;
222 float x, y; 230 float x, y;
223 // Center the image in case aspect ratio is different. 231 // Center the image in case aspect ratio is different.
224 if (scale_x > scale_y) { 232 if (scale_x > scale_y) {
225 scale = scale_y; 233 scale = scale_y;
226 x = (scale_x - scale_y) / scale * frame_size_.width() / 2.0; 234 x = (scale_x - scale_y) / scale * frame_size_.width() / 2.0;
227 y = 0.f; 235 y = 0.f;
228 } else { 236 } else {
229 scale = scale_x; 237 scale = scale_x;
230 x = 0.f; 238 x = 0.f;
231 y = (scale_y - scale_x) / scale * frame_size_.height() / 2.0; 239 y = (scale_y - scale_x) / scale * frame_size_.height() / 2.0;
232 } 240 }
233 241
234 // Create skia device and canvas that draw to |resized_bitmap_|. 242 // Create skia device and canvas that draw to |resized_bitmap_|.
235 SkDevice device(resized_bitmap_); 243 SkDevice device(resized_bitmap_);
236 SkCanvas canvas(&device); 244 SkCanvas canvas(&device);
237 canvas.scale(scale, scale); 245 canvas.scale(scale, scale);
238 246
239 int source_stride = capture_data->stride(); 247 int source_stride = frame->stride();
240 for (SkRegion::Iterator i(dirty_region); !i.done(); i.next()) { 248 for (webrtc::DesktopRegion::Iterator i(dirty_region); !i.IsAtEnd();
249 i.Advance()) {
241 SkBitmap source_bitmap; 250 SkBitmap source_bitmap;
242 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 251 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
243 i.rect().width(), i.rect().height(), 252 i.rect().width(), i.rect().height(),
244 source_stride); 253 source_stride);
245 source_bitmap.setIsOpaque(true); 254 source_bitmap.setIsOpaque(true);
246 source_bitmap.setPixels( 255 source_bitmap.setPixels(
247 capture_data->data() + i.rect().top() * source_stride + 256 frame->data() + i.rect().top() * source_stride +
248 i.rect().left() * ScreenCaptureData::kBytesPerPixel); 257 i.rect().left() * webrtc::DesktopFrame::kBytesPerPixel);
249 canvas.drawBitmap(source_bitmap, i.rect().left() + x / scale, 258 canvas.drawBitmap(source_bitmap, i.rect().left() + x / scale,
250 i.rect().top() + y / scale, NULL); 259 i.rect().top() + y / scale, NULL);
251 } 260 }
252 261
253 base::AutoLock auto_lock(event_handler_lock_); 262 base::AutoLock auto_lock(event_handler_lock_);
254 if (event_handler_) { 263 if (event_handler_) {
255 event_handler_->OnIncomingCapturedFrame( 264 event_handler_->OnIncomingCapturedFrame(
256 reinterpret_cast<uint8*>(resized_bitmap_.getPixels()), buffer_size, 265 reinterpret_cast<uint8*>(resized_bitmap_.getPixels()), buffer_size,
257 base::Time::Now(), 0, false, false); 266 base::Time::Now(), 0, false, false);
258 } 267 }
259 } 268 }
260 269
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) { 270 void ScreenCaptureDevice::Core::DoAllocate(int frame_rate) {
269 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 271 DCHECK(task_runner_->RunsTasksOnCurrentThread());
270 272
271 frame_rate_ = frame_rate; 273 frame_rate_ = frame_rate;
272 274
273 // Create and start frame capturer. 275 // Create and start frame capturer.
274 #if defined(OS_CHROMEOS) && !defined(ARCH_CPU_ARMEL) 276 #if defined(OS_CHROMEOS) && !defined(ARCH_CPU_ARMEL)
275 // ScreenCapturerX11 polls by default, due to poor driver support for DAMAGE. 277 // ScreenCapturerX11 polls by default, due to poor driver support for DAMAGE.
276 // ChromeOS' drivers [can be patched to] support DAMAGE properly, so use it. 278 // 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 279 // 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 333
332 if (!started_) 334 if (!started_)
333 return; 335 return;
334 336
335 // Schedule a task for the next frame. 337 // Schedule a task for the next frame.
336 ScheduleCaptureTimer(); 338 ScheduleCaptureTimer();
337 DoCapture(); 339 DoCapture();
338 } 340 }
339 341
340 void ScreenCaptureDevice::Core::DoCapture() { 342 void ScreenCaptureDevice::Core::DoCapture() {
343 DCHECK(task_runner_->RunsTasksOnCurrentThread());
341 DCHECK(!capture_in_progress_); 344 DCHECK(!capture_in_progress_);
342 345
343 capture_in_progress_ = true; 346 capture_in_progress_ = true;
344 screen_capturer_->CaptureFrame(); 347 screen_capturer_->Capture(webrtc::DesktopRegion());
345 348
346 // Assume that ScreenCapturer always calls OnCaptureCompleted() 349 // Currently only synchronous implementations of DesktopCapturer are
347 // callback before it returns. 350 // supported.
348 //
349 // TODO(sergeyu): Fix ScreenCapturer to return video frame
350 // synchronously instead of using Delegate interface.
351 DCHECK(!capture_in_progress_); 351 DCHECK(!capture_in_progress_);
352 } 352 }
353 353
354 ScreenCaptureDevice::ScreenCaptureDevice( 354 ScreenCaptureDevice::ScreenCaptureDevice(
355 scoped_refptr<base::SequencedTaskRunner> task_runner) 355 scoped_refptr<base::SequencedTaskRunner> task_runner)
356 : core_(new Core(task_runner)) { 356 : core_(new Core(task_runner)) {
357 name_.device_name = "Screen"; 357 name_.device_name = "Screen";
358 } 358 }
359 359
360 ScreenCaptureDevice::~ScreenCaptureDevice() { 360 ScreenCaptureDevice::~ScreenCaptureDevice() {
(...skipping 21 matching lines...) Expand all
382 382
383 void ScreenCaptureDevice::DeAllocate() { 383 void ScreenCaptureDevice::DeAllocate() {
384 core_->DeAllocate(); 384 core_->DeAllocate();
385 } 385 }
386 386
387 const VideoCaptureDevice::Name& ScreenCaptureDevice::device_name() { 387 const VideoCaptureDevice::Name& ScreenCaptureDevice::device_name() {
388 return name_; 388 return name_;
389 } 389 }
390 390
391 } // namespace media 391 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/screen/screen_capture_data.cc ('k') | media/video/capture/screen/screen_capture_device_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698