OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "content/browser/media/capture/desktop_capture_device_aura.h" | 5 #include "content/browser/media/capture/desktop_capture_device_aura.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/metrics/histogram.h" | |
9 #include "base/timer/timer.h" | 8 #include "base/timer/timer.h" |
10 #include "cc/output/copy_output_request.h" | 9 #include "content/browser/media/capture/aura_window_capture_machine.h" |
11 #include "cc/output/copy_output_result.h" | |
12 #include "content/browser/compositor/image_transport_factory.h" | |
13 #include "content/browser/media/capture/content_video_capture_device_core.h" | 10 #include "content/browser/media/capture/content_video_capture_device_core.h" |
14 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" | |
15 #include "content/common/gpu/client/gl_helper.h" | |
16 #include "content/public/browser/browser_thread.h" | 11 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/power_save_blocker.h" | |
18 #include "media/base/video_capture_types.h" | |
19 #include "media/base/video_util.h" | |
20 #include "skia/ext/image_operations.h" | |
21 #include "third_party/skia/include/core/SkBitmap.h" | |
22 #include "ui/aura/client/screen_position_client.h" | |
23 #include "ui/aura/env.h" | |
24 #include "ui/aura/window.h" | 12 #include "ui/aura/window.h" |
25 #include "ui/aura/window_observer.h" | |
26 #include "ui/aura/window_tree_host.h" | |
27 #include "ui/base/cursor/cursors_aura.h" | |
28 #include "ui/compositor/compositor.h" | |
29 #include "ui/compositor/dip_util.h" | |
30 #include "ui/compositor/layer.h" | |
31 #include "ui/gfx/screen.h" | |
32 | 13 |
33 namespace content { | 14 namespace content { |
34 | 15 |
35 namespace { | 16 namespace { |
36 | 17 |
37 int clip_byte(int x) { | 18 void SetCaptureSource(AuraWindowCaptureMachine* machine, |
38 return std::max(0, std::min(x, 255)); | 19 const DesktopMediaID& source) { |
39 } | |
40 | |
41 int alpha_blend(int alpha, int src, int dst) { | |
42 return (src * alpha + dst * (255 - alpha)) / 255; | |
43 } | |
44 | |
45 // Helper function to composite a cursor bitmap on a YUV420 video frame. | |
46 void RenderCursorOnVideoFrame( | |
47 const scoped_refptr<media::VideoFrame>& target, | |
48 const SkBitmap& cursor_bitmap, | |
49 const gfx::Point& cursor_position) { | |
50 DCHECK(target.get()); | |
51 DCHECK(!cursor_bitmap.isNull()); | |
52 | |
53 gfx::Rect rect = gfx::IntersectRects( | |
54 gfx::Rect(cursor_bitmap.width(), cursor_bitmap.height()) + | |
55 gfx::Vector2d(cursor_position.x(), cursor_position.y()), | |
56 target->visible_rect()); | |
57 | |
58 cursor_bitmap.lockPixels(); | |
59 for (int y = rect.y(); y < rect.bottom(); ++y) { | |
60 int cursor_y = y - cursor_position.y(); | |
61 uint8* yplane = target->data(media::VideoFrame::kYPlane) + | |
62 y * target->row_bytes(media::VideoFrame::kYPlane); | |
63 uint8* uplane = target->data(media::VideoFrame::kUPlane) + | |
64 (y / 2) * target->row_bytes(media::VideoFrame::kUPlane); | |
65 uint8* vplane = target->data(media::VideoFrame::kVPlane) + | |
66 (y / 2) * target->row_bytes(media::VideoFrame::kVPlane); | |
67 for (int x = rect.x(); x < rect.right(); ++x) { | |
68 int cursor_x = x - cursor_position.x(); | |
69 SkColor color = cursor_bitmap.getColor(cursor_x, cursor_y); | |
70 int alpha = SkColorGetA(color); | |
71 int color_r = SkColorGetR(color); | |
72 int color_g = SkColorGetG(color); | |
73 int color_b = SkColorGetB(color); | |
74 int color_y = clip_byte(((color_r * 66 + color_g * 129 + color_b * 25 + | |
75 128) >> 8) + 16); | |
76 yplane[x] = alpha_blend(alpha, color_y, yplane[x]); | |
77 | |
78 // Only sample U and V at even coordinates. | |
79 if ((x % 2 == 0) && (y % 2 == 0)) { | |
80 int color_u = clip_byte(((color_r * -38 + color_g * -74 + | |
81 color_b * 112 + 128) >> 8) + 128); | |
82 int color_v = clip_byte(((color_r * 112 + color_g * -94 + | |
83 color_b * -18 + 128) >> 8) + 128); | |
84 uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]); | |
85 vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]); | |
86 } | |
87 } | |
88 } | |
89 cursor_bitmap.unlockPixels(); | |
90 } | |
91 | |
92 class DesktopVideoCaptureMachine | |
93 : public VideoCaptureMachine, | |
94 public aura::WindowObserver, | |
95 public ui::CompositorObserver, | |
96 public base::SupportsWeakPtr<DesktopVideoCaptureMachine> { | |
97 public: | |
98 DesktopVideoCaptureMachine(const DesktopMediaID& source); | |
99 ~DesktopVideoCaptureMachine() override; | |
100 | |
101 // VideoCaptureFrameSource overrides. | |
102 bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | |
103 const media::VideoCaptureParams& params) override; | |
104 void Stop(const base::Closure& callback) override; | |
105 | |
106 // Implements aura::WindowObserver. | |
107 void OnWindowBoundsChanged(aura::Window* window, | |
108 const gfx::Rect& old_bounds, | |
109 const gfx::Rect& new_bounds) override; | |
110 void OnWindowDestroyed(aura::Window* window) override; | |
111 void OnWindowAddedToRootWindow(aura::Window* window) override; | |
112 void OnWindowRemovingFromRootWindow(aura::Window* window, | |
113 aura::Window* new_root) override; | |
114 | |
115 // Implements ui::CompositorObserver. | |
116 void OnCompositingDidCommit(ui::Compositor* compositor) override {} | |
117 void OnCompositingStarted(ui::Compositor* compositor, | |
118 base::TimeTicks start_time) override {} | |
119 void OnCompositingEnded(ui::Compositor* compositor) override; | |
120 void OnCompositingAborted(ui::Compositor* compositor) override {} | |
121 void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} | |
122 void OnCompositingShuttingDown(ui::Compositor* compositor) override {} | |
123 | |
124 private: | |
125 // Captures a frame. | |
126 // |dirty| is false for timer polls and true for compositor updates. | |
127 void Capture(bool dirty); | |
128 | |
129 // Update capture size. Must be called on the UI thread. | |
130 void UpdateCaptureSize(); | |
131 | |
132 // Response callback for cc::Layer::RequestCopyOfOutput(). | |
133 void DidCopyOutput( | |
134 scoped_refptr<media::VideoFrame> video_frame, | |
135 base::TimeTicks start_time, | |
136 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
137 scoped_ptr<cc::CopyOutputResult> result); | |
138 | |
139 // A helper which does the real work for DidCopyOutput. Returns true if | |
140 // succeeded. | |
141 bool ProcessCopyOutputResponse( | |
142 scoped_refptr<media::VideoFrame> video_frame, | |
143 base::TimeTicks start_time, | |
144 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
145 scoped_ptr<cc::CopyOutputResult> result); | |
146 | |
147 // Helper function to update cursor state. | |
148 // |region_in_frame| defines where the desktop is rendered in the captured | |
149 // frame. | |
150 // Returns the current cursor position in captured frame. | |
151 gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); | |
152 | |
153 // Clears cursor state. | |
154 void ClearCursorState(); | |
155 | |
156 // The window associated with the desktop. | |
157 aura::Window* desktop_window_; | |
158 | |
159 // The timer that kicks off period captures. | |
160 base::Timer timer_; | |
161 | |
162 // The id of the window being captured. | |
163 DesktopMediaID window_id_; | |
164 | |
165 // Makes all the decisions about which frames to copy, and how. | |
166 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; | |
167 | |
168 // The capture parameters for this capture. | |
169 media::VideoCaptureParams capture_params_; | |
170 | |
171 // YUV readback pipeline. | |
172 scoped_ptr<content::ReadbackYUVInterface> yuv_readback_pipeline_; | |
173 | |
174 // Cursor state. | |
175 ui::Cursor last_cursor_; | |
176 gfx::Size desktop_size_when_cursor_last_updated_; | |
177 gfx::Point cursor_hot_point_; | |
178 SkBitmap scaled_cursor_bitmap_; | |
179 | |
180 // TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the | |
181 // screen from sleeping for the drive-by web. | |
182 scoped_ptr<PowerSaveBlocker> power_save_blocker_; | |
183 | |
184 DISALLOW_COPY_AND_ASSIGN(DesktopVideoCaptureMachine); | |
185 }; | |
186 | |
187 DesktopVideoCaptureMachine::DesktopVideoCaptureMachine( | |
188 const DesktopMediaID& source) | |
189 : desktop_window_(NULL), | |
190 timer_(true, true), | |
191 window_id_(source) {} | |
192 | |
193 DesktopVideoCaptureMachine::~DesktopVideoCaptureMachine() {} | |
194 | |
195 bool DesktopVideoCaptureMachine::Start( | |
196 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | |
197 const media::VideoCaptureParams& params) { | |
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 20 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
199 | 21 |
200 desktop_window_ = content::DesktopMediaID::GetAuraWindowById(window_id_); | 22 aura::Window* window = DesktopMediaID::GetAuraWindowById(source); |
201 if (!desktop_window_) | 23 machine->SetWindow(window); |
202 return false; | |
203 | |
204 // If the associated layer is already destroyed then return failure. | |
205 ui::Layer* layer = desktop_window_->layer(); | |
206 if (!layer) | |
207 return false; | |
208 | |
209 DCHECK(oracle_proxy.get()); | |
210 oracle_proxy_ = oracle_proxy; | |
211 capture_params_ = params; | |
212 | |
213 // Update capture size. | |
214 UpdateCaptureSize(); | |
215 | |
216 // Start observing window events. | |
217 desktop_window_->AddObserver(this); | |
218 | |
219 // Start observing compositor updates. | |
220 if (desktop_window_->GetHost()) | |
221 desktop_window_->GetHost()->compositor()->AddObserver(this); | |
222 | |
223 power_save_blocker_.reset( | |
224 PowerSaveBlocker::Create( | |
225 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, | |
226 PowerSaveBlocker::kReasonOther, | |
227 "DesktopCaptureDevice is running").release()); | |
228 | |
229 // Starts timer. | |
230 timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(), | |
231 base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(), | |
232 false)); | |
233 | |
234 return true; | |
235 } | |
236 | |
237 void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) { | |
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
239 power_save_blocker_.reset(); | |
240 | |
241 // Stop observing compositor and window events. | |
242 if (desktop_window_) { | |
243 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); | |
244 // In the host destructor the compositor is destroyed before the window. | |
245 if (window_host && window_host->compositor()) | |
246 window_host->compositor()->RemoveObserver(this); | |
247 desktop_window_->RemoveObserver(this); | |
248 desktop_window_ = NULL; | |
249 } | |
250 | |
251 // Stop timer. | |
252 timer_.Stop(); | |
253 | |
254 callback.Run(); | |
255 } | |
256 | |
257 void DesktopVideoCaptureMachine::UpdateCaptureSize() { | |
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
259 if (oracle_proxy_.get() && desktop_window_) { | |
260 ui::Layer* layer = desktop_window_->layer(); | |
261 oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel( | |
262 layer, layer->bounds().size())); | |
263 } | |
264 ClearCursorState(); | |
265 } | |
266 | |
267 void DesktopVideoCaptureMachine::Capture(bool dirty) { | |
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
269 | |
270 // Do not capture if the desktop window is already destroyed. | |
271 if (!desktop_window_) | |
272 return; | |
273 | |
274 scoped_refptr<media::VideoFrame> frame; | |
275 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; | |
276 | |
277 const base::TimeTicks start_time = base::TimeTicks::Now(); | |
278 const VideoCaptureOracle::Event event = | |
279 dirty ? VideoCaptureOracle::kCompositorUpdate | |
280 : VideoCaptureOracle::kTimerPoll; | |
281 if (oracle_proxy_->ObserveEventAndDecideCapture( | |
282 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) { | |
283 scoped_ptr<cc::CopyOutputRequest> request = | |
284 cc::CopyOutputRequest::CreateRequest( | |
285 base::Bind(&DesktopVideoCaptureMachine::DidCopyOutput, | |
286 AsWeakPtr(), frame, start_time, capture_frame_cb)); | |
287 gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), | |
288 desktop_window_->bounds().height()); | |
289 request->set_area(window_rect); | |
290 desktop_window_->layer()->RequestCopyOfOutput(request.Pass()); | |
291 } | |
292 } | |
293 | |
294 void CopyOutputFinishedForVideo( | |
295 base::TimeTicks start_time, | |
296 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
297 const scoped_refptr<media::VideoFrame>& target, | |
298 const SkBitmap& cursor_bitmap, | |
299 const gfx::Point& cursor_position, | |
300 scoped_ptr<cc::SingleReleaseCallback> release_callback, | |
301 bool result) { | |
302 if (!cursor_bitmap.isNull()) | |
303 RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position); | |
304 release_callback->Run(0, false); | |
305 capture_frame_cb.Run(target, start_time, result); | |
306 } | |
307 | |
308 void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb, | |
309 uint32 sync_point) { | |
310 cb->Run(sync_point, false); | |
311 } | |
312 | |
313 void DesktopVideoCaptureMachine::DidCopyOutput( | |
314 scoped_refptr<media::VideoFrame> video_frame, | |
315 base::TimeTicks start_time, | |
316 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
317 scoped_ptr<cc::CopyOutputResult> result) { | |
318 static bool first_call = true; | |
319 | |
320 bool succeeded = ProcessCopyOutputResponse( | |
321 video_frame, start_time, capture_frame_cb, result.Pass()); | |
322 | |
323 base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; | |
324 | |
325 // The two UMA_ blocks must be put in its own scope since it creates a static | |
326 // variable which expected constant histogram name. | |
327 if (window_id_.type == DesktopMediaID::TYPE_SCREEN) { | |
328 UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time); | |
329 } else { | |
330 UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time); | |
331 } | |
332 | |
333 if (first_call) { | |
334 first_call = false; | |
335 if (window_id_.type == DesktopMediaID::TYPE_SCREEN) { | |
336 IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED | |
337 : FIRST_SCREEN_CAPTURE_FAILED); | |
338 } else { | |
339 IncrementDesktopCaptureCounter(succeeded | |
340 ? FIRST_WINDOW_CAPTURE_SUCCEEDED | |
341 : FIRST_WINDOW_CAPTURE_FAILED); | |
342 } | |
343 } | |
344 } | |
345 | |
346 bool DesktopVideoCaptureMachine::ProcessCopyOutputResponse( | |
347 scoped_refptr<media::VideoFrame> video_frame, | |
348 base::TimeTicks start_time, | |
349 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
350 scoped_ptr<cc::CopyOutputResult> result) { | |
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
352 | |
353 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_) | |
354 return false; | |
355 | |
356 if (capture_params_.requested_format.pixel_format == | |
357 media::PIXEL_FORMAT_TEXTURE) { | |
358 DCHECK(!video_frame.get()); | |
359 cc::TextureMailbox texture_mailbox; | |
360 scoped_ptr<cc::SingleReleaseCallback> release_callback; | |
361 result->TakeTexture(&texture_mailbox, &release_callback); | |
362 DCHECK(texture_mailbox.IsTexture()); | |
363 if (!texture_mailbox.IsTexture()) | |
364 return false; | |
365 video_frame = media::VideoFrame::WrapNativeTexture( | |
366 make_scoped_ptr(new gpu::MailboxHolder(texture_mailbox.mailbox(), | |
367 texture_mailbox.target(), | |
368 texture_mailbox.sync_point())), | |
369 base::Bind(&RunSingleReleaseCallback, base::Passed(&release_callback)), | |
370 result->size(), gfx::Rect(result->size()), result->size(), | |
371 base::TimeDelta(), false); | |
372 capture_frame_cb.Run(video_frame, start_time, true); | |
373 return true; | |
374 } else { | |
375 DCHECK(video_frame.get()); | |
376 } | |
377 | |
378 // Compute the dest size we want after the letterboxing resize. Make the | |
379 // coordinates and sizes even because we letterbox in YUV space | |
380 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to | |
381 // line up correctly. | |
382 // The video frame's visible_rect() and the result's size() are both physical | |
383 // pixels. | |
384 gfx::Rect region_in_frame = media::ComputeLetterboxRegion( | |
385 video_frame->visible_rect(), result->size()); | |
386 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, | |
387 region_in_frame.y() & ~1, | |
388 region_in_frame.width() & ~1, | |
389 region_in_frame.height() & ~1); | |
390 if (region_in_frame.IsEmpty()) | |
391 return false; | |
392 | |
393 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); | |
394 GLHelper* gl_helper = factory->GetGLHelper(); | |
395 if (!gl_helper) | |
396 return false; | |
397 | |
398 cc::TextureMailbox texture_mailbox; | |
399 scoped_ptr<cc::SingleReleaseCallback> release_callback; | |
400 result->TakeTexture(&texture_mailbox, &release_callback); | |
401 DCHECK(texture_mailbox.IsTexture()); | |
402 if (!texture_mailbox.IsTexture()) | |
403 return false; | |
404 | |
405 gfx::Rect result_rect(result->size()); | |
406 if (!yuv_readback_pipeline_ || | |
407 yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() || | |
408 yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect || | |
409 yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) { | |
410 yuv_readback_pipeline_.reset( | |
411 gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST, | |
412 result_rect.size(), | |
413 result_rect, | |
414 region_in_frame.size(), | |
415 true, | |
416 true)); | |
417 } | |
418 | |
419 gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame); | |
420 yuv_readback_pipeline_->ReadbackYUV( | |
421 texture_mailbox.mailbox(), | |
422 texture_mailbox.sync_point(), | |
423 video_frame.get(), | |
424 region_in_frame.origin(), | |
425 base::Bind(&CopyOutputFinishedForVideo, | |
426 start_time, | |
427 capture_frame_cb, | |
428 video_frame, | |
429 scaled_cursor_bitmap_, | |
430 cursor_position_in_frame, | |
431 base::Passed(&release_callback))); | |
432 return true; | |
433 } | |
434 | |
435 gfx::Point DesktopVideoCaptureMachine::UpdateCursorState( | |
436 const gfx::Rect& region_in_frame) { | |
437 const gfx::Rect desktop_bounds = desktop_window_->layer()->bounds(); | |
438 if (desktop_bounds.IsEmpty()) { | |
439 // Return early to prevent divide-by-zero in calculations below. | |
440 ClearCursorState(); | |
441 return gfx::Point(); | |
442 } | |
443 | |
444 gfx::NativeCursor cursor = | |
445 desktop_window_->GetHost()->last_cursor(); | |
446 if (last_cursor_ != cursor || | |
447 desktop_size_when_cursor_last_updated_ != desktop_bounds.size()) { | |
448 SkBitmap cursor_bitmap; | |
449 if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) { | |
450 const int scaled_width = cursor_bitmap.width() * | |
451 region_in_frame.width() / desktop_bounds.width(); | |
452 const int scaled_height = cursor_bitmap.height() * | |
453 region_in_frame.height() / desktop_bounds.height(); | |
454 if (scaled_width <= 0 || scaled_height <= 0) { | |
455 ClearCursorState(); | |
456 return gfx::Point(); | |
457 } | |
458 scaled_cursor_bitmap_ = skia::ImageOperations::Resize( | |
459 cursor_bitmap, | |
460 skia::ImageOperations::RESIZE_BEST, | |
461 scaled_width, | |
462 scaled_height); | |
463 last_cursor_ = cursor; | |
464 desktop_size_when_cursor_last_updated_ = desktop_bounds.size(); | |
465 } else { | |
466 // Clear cursor state if ui::GetCursorBitmap failed so that we do not | |
467 // render cursor on the captured frame. | |
468 ClearCursorState(); | |
469 } | |
470 } | |
471 | |
472 gfx::Point cursor_position = aura::Env::GetInstance()->last_mouse_location(); | |
473 aura::client::GetScreenPositionClient(desktop_window_->GetRootWindow())-> | |
474 ConvertPointFromScreen(desktop_window_, &cursor_position); | |
475 const gfx::Point hot_point_in_dip = ui::ConvertPointToDIP( | |
476 desktop_window_->layer(), cursor_hot_point_); | |
477 cursor_position.Offset(-desktop_bounds.x() - hot_point_in_dip.x(), | |
478 -desktop_bounds.y() - hot_point_in_dip.y()); | |
479 return gfx::Point( | |
480 region_in_frame.x() + cursor_position.x() * region_in_frame.width() / | |
481 desktop_bounds.width(), | |
482 region_in_frame.y() + cursor_position.y() * region_in_frame.height() / | |
483 desktop_bounds.height()); | |
484 } | |
485 | |
486 void DesktopVideoCaptureMachine::ClearCursorState() { | |
487 last_cursor_ = ui::Cursor(); | |
488 desktop_size_when_cursor_last_updated_ = gfx::Size(); | |
489 cursor_hot_point_ = gfx::Point(); | |
490 scaled_cursor_bitmap_.reset(); | |
491 } | |
492 | |
493 void DesktopVideoCaptureMachine::OnWindowBoundsChanged( | |
494 aura::Window* window, | |
495 const gfx::Rect& old_bounds, | |
496 const gfx::Rect& new_bounds) { | |
497 DCHECK(desktop_window_ && window == desktop_window_); | |
498 | |
499 // Post task to update capture size on UI thread. | |
500 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
501 &DesktopVideoCaptureMachine::UpdateCaptureSize, AsWeakPtr())); | |
502 } | |
503 | |
504 void DesktopVideoCaptureMachine::OnWindowDestroyed(aura::Window* window) { | |
505 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
506 | |
507 Stop(base::Bind(&base::DoNothing)); | |
508 | |
509 oracle_proxy_->ReportError("OnWindowDestroyed()"); | |
510 } | |
511 | |
512 void DesktopVideoCaptureMachine::OnWindowAddedToRootWindow( | |
513 aura::Window* window) { | |
514 DCHECK(window == desktop_window_); | |
515 window->GetHost()->compositor()->AddObserver(this); | |
516 } | |
517 | |
518 void DesktopVideoCaptureMachine::OnWindowRemovingFromRootWindow( | |
519 aura::Window* window, | |
520 aura::Window* new_root) { | |
521 DCHECK(window == desktop_window_); | |
522 window->GetHost()->compositor()->RemoveObserver(this); | |
523 } | |
524 | |
525 void DesktopVideoCaptureMachine::OnCompositingEnded( | |
526 ui::Compositor* compositor) { | |
527 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | |
528 &DesktopVideoCaptureMachine::Capture, AsWeakPtr(), true)); | |
529 } | 24 } |
530 | 25 |
531 } // namespace | 26 } // namespace |
532 | 27 |
533 DesktopCaptureDeviceAura::DesktopCaptureDeviceAura( | 28 DesktopCaptureDeviceAura::DesktopCaptureDeviceAura( |
534 const DesktopMediaID& source) | 29 const DesktopMediaID& source) { |
535 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( | 30 AuraWindowCaptureMachine* machine = new AuraWindowCaptureMachine(); |
536 new DesktopVideoCaptureMachine(source)))) {} | 31 core_.reset(new ContentVideoCaptureDeviceCore(make_scoped_ptr(machine))); |
| 32 // |core_| owns |machine| and deletes it on UI thread so passing the raw |
| 33 // pointer to the UI thread is safe here. |
| 34 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 35 base::Bind(&SetCaptureSource, machine, source)); |
| 36 } |
537 | 37 |
538 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { | 38 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { |
539 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; | 39 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; |
540 } | 40 } |
541 | 41 |
542 // static | 42 // static |
543 media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create( | 43 media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create( |
544 const DesktopMediaID& source) { | 44 const DesktopMediaID& source) { |
545 IncrementDesktopCaptureCounter(source.type == DesktopMediaID::TYPE_SCREEN | |
546 ? SCREEN_CAPTURER_CREATED | |
547 : WINDOW_CAPTURER_CREATED); | |
548 return new DesktopCaptureDeviceAura(source); | 45 return new DesktopCaptureDeviceAura(source); |
549 } | 46 } |
550 | 47 |
551 void DesktopCaptureDeviceAura::AllocateAndStart( | 48 void DesktopCaptureDeviceAura::AllocateAndStart( |
552 const media::VideoCaptureParams& params, | 49 const media::VideoCaptureParams& params, |
553 scoped_ptr<Client> client) { | 50 scoped_ptr<Client> client) { |
554 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 51 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
555 core_->AllocateAndStart(params, client.Pass()); | 52 core_->AllocateAndStart(params, client.Pass()); |
556 } | 53 } |
557 | 54 |
558 void DesktopCaptureDeviceAura::StopAndDeAllocate() { | 55 void DesktopCaptureDeviceAura::StopAndDeAllocate() { |
559 core_->StopAndDeAllocate(); | 56 core_->StopAndDeAllocate(); |
560 } | 57 } |
561 | 58 |
562 } // namespace content | 59 } // namespace content |
OLD | NEW |