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" | 8 #include "base/metrics/histogram.h" |
9 #include "base/sys_info.h" | |
9 #include "base/timer/timer.h" | 10 #include "base/timer/timer.h" |
10 #include "cc/output/copy_output_request.h" | 11 #include "cc/output/copy_output_request.h" |
11 #include "cc/output/copy_output_result.h" | 12 #include "cc/output/copy_output_result.h" |
12 #include "content/browser/compositor/image_transport_factory.h" | 13 #include "content/browser/compositor/image_transport_factory.h" |
13 #include "content/browser/media/capture/content_video_capture_device_core.h" | 14 #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/browser/media/capture/desktop_capture_device_uma_types.h" |
15 #include "content/common/gpu/client/gl_helper.h" | 16 #include "content/common/gpu/client/gl_helper.h" |
16 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/power_save_blocker.h" | 18 #include "content/public/browser/power_save_blocker.h" |
18 #include "media/base/video_util.h" | 19 #include "media/base/video_util.h" |
19 #include "media/video/capture/video_capture_types.h" | 20 #include "media/video/capture/video_capture_types.h" |
20 #include "skia/ext/image_operations.h" | 21 #include "skia/ext/image_operations.h" |
21 #include "third_party/skia/include/core/SkBitmap.h" | 22 #include "third_party/skia/include/core/SkBitmap.h" |
22 #include "ui/aura/client/screen_position_client.h" | 23 #include "ui/aura/client/screen_position_client.h" |
23 #include "ui/aura/env.h" | 24 #include "ui/aura/env.h" |
24 #include "ui/aura/window.h" | 25 #include "ui/aura/window.h" |
25 #include "ui/aura/window_observer.h" | 26 #include "ui/aura/window_observer.h" |
26 #include "ui/aura/window_tree_host.h" | 27 #include "ui/aura/window_tree_host.h" |
27 #include "ui/base/cursor/cursors_aura.h" | 28 #include "ui/base/cursor/cursors_aura.h" |
28 #include "ui/compositor/compositor.h" | 29 #include "ui/compositor/compositor.h" |
29 #include "ui/compositor/dip_util.h" | 30 #include "ui/compositor/dip_util.h" |
30 #include "ui/compositor/layer.h" | 31 #include "ui/compositor/layer.h" |
32 #include "ui/gfx/display.h" | |
33 #include "ui/gfx/display_observer.h" | |
31 #include "ui/gfx/screen.h" | 34 #include "ui/gfx/screen.h" |
32 | 35 |
36 #if defined(USE_ASH) | |
37 #include "ash/display/display_controller.h" | |
piman
2015/02/24 01:58:29
content/ is not allowed to depend on ash/
| |
38 #include "ash/shell.h" | |
39 #include "ui/display/chromeos/display_configurator.h" | |
40 #endif | |
41 | |
33 namespace content { | 42 namespace content { |
34 | 43 |
35 namespace { | 44 namespace { |
36 | 45 |
37 int clip_byte(int x) { | 46 int clip_byte(int x) { |
38 return std::max(0, std::min(x, 255)); | 47 return std::max(0, std::min(x, 255)); |
39 } | 48 } |
40 | 49 |
41 int alpha_blend(int alpha, int src, int dst) { | 50 int alpha_blend(int alpha, int src, int dst) { |
42 return (src * alpha + dst * (255 - alpha)) / 255; | 51 return (src * alpha + dst * (255 - alpha)) / 255; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 } | 95 } |
87 } | 96 } |
88 } | 97 } |
89 cursor_bitmap.unlockPixels(); | 98 cursor_bitmap.unlockPixels(); |
90 } | 99 } |
91 | 100 |
92 class DesktopVideoCaptureMachine | 101 class DesktopVideoCaptureMachine |
93 : public VideoCaptureMachine, | 102 : public VideoCaptureMachine, |
94 public aura::WindowObserver, | 103 public aura::WindowObserver, |
95 public ui::CompositorObserver, | 104 public ui::CompositorObserver, |
105 public gfx::DisplayObserver, | |
96 public base::SupportsWeakPtr<DesktopVideoCaptureMachine> { | 106 public base::SupportsWeakPtr<DesktopVideoCaptureMachine> { |
97 public: | 107 public: |
98 DesktopVideoCaptureMachine(const DesktopMediaID& source); | 108 DesktopVideoCaptureMachine(const DesktopMediaID& source); |
99 ~DesktopVideoCaptureMachine() override; | 109 ~DesktopVideoCaptureMachine() override; |
100 | 110 |
101 // VideoCaptureFrameSource overrides. | 111 // VideoCaptureFrameSource overrides. |
102 bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 112 bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
103 const media::VideoCaptureParams& params) override; | 113 const media::VideoCaptureParams& params) override; |
104 void Stop(const base::Closure& callback) override; | 114 void Stop(const base::Closure& callback) override; |
105 | 115 |
106 // Implements aura::WindowObserver. | 116 // Implements aura::WindowObserver. |
107 void OnWindowBoundsChanged(aura::Window* window, | 117 void OnWindowBoundsChanged(aura::Window* window, |
108 const gfx::Rect& old_bounds, | 118 const gfx::Rect& old_bounds, |
109 const gfx::Rect& new_bounds) override; | 119 const gfx::Rect& new_bounds) override; |
110 void OnWindowDestroyed(aura::Window* window) override; | 120 void OnWindowDestroyed(aura::Window* window) override; |
111 void OnWindowAddedToRootWindow(aura::Window* window) override; | 121 void OnWindowAddedToRootWindow(aura::Window* window) override; |
112 void OnWindowRemovingFromRootWindow(aura::Window* window, | 122 void OnWindowRemovingFromRootWindow(aura::Window* window, |
113 aura::Window* new_root) override; | 123 aura::Window* new_root) override; |
114 | 124 |
115 // Implements ui::CompositorObserver. | 125 // Implements ui::CompositorObserver. |
116 void OnCompositingDidCommit(ui::Compositor* compositor) override {} | 126 void OnCompositingDidCommit(ui::Compositor* compositor) override {} |
117 void OnCompositingStarted(ui::Compositor* compositor, | 127 void OnCompositingStarted(ui::Compositor* compositor, |
118 base::TimeTicks start_time) override {} | 128 base::TimeTicks start_time) override {} |
119 void OnCompositingEnded(ui::Compositor* compositor) override; | 129 void OnCompositingEnded(ui::Compositor* compositor) override; |
120 void OnCompositingAborted(ui::Compositor* compositor) override {} | 130 void OnCompositingAborted(ui::Compositor* compositor) override {} |
121 void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} | 131 void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} |
122 void OnCompositingShuttingDown(ui::Compositor* compositor) override {} | 132 void OnCompositingShuttingDown(ui::Compositor* compositor) override {} |
123 | 133 |
134 // Implements gfx::DisplayObserver. | |
135 void OnDisplayAdded(const gfx::Display& new_display) override; | |
136 void OnDisplayRemoved(const gfx::Display& old_display) override {} | |
137 void OnDisplayMetricsChanged(const gfx::Display& display, | |
138 uint32_t changed_metrics) override {} | |
139 | |
124 private: | 140 private: |
125 // Captures a frame. | 141 // Captures a frame. |
126 // |dirty| is false for timer polls and true for compositor updates. | 142 // |dirty| is false for timer polls and true for compositor updates. |
127 void Capture(bool dirty); | 143 void Capture(bool dirty); |
128 | 144 |
129 // Update capture size. Must be called on the UI thread. | 145 // Update capture size. Must be called on the UI thread. |
130 void UpdateCaptureSize(); | 146 void UpdateCaptureSize(); |
131 | 147 |
132 // Response callback for cc::Layer::RequestCopyOfOutput(). | 148 // Response callback for cc::Layer::RequestCopyOfOutput(). |
133 void DidCopyOutput( | 149 void DidCopyOutput( |
(...skipping 11 matching lines...) Expand all Loading... | |
145 scoped_ptr<cc::CopyOutputResult> result); | 161 scoped_ptr<cc::CopyOutputResult> result); |
146 | 162 |
147 // Helper function to update cursor state. | 163 // Helper function to update cursor state. |
148 // |region_in_frame| defines the desktop bound in the captured frame. | 164 // |region_in_frame| defines the desktop bound in the captured frame. |
149 // Returns the current cursor position in captured frame. | 165 // Returns the current cursor position in captured frame. |
150 gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); | 166 gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); |
151 | 167 |
152 // Clears cursor state. | 168 // Clears cursor state. |
153 void ClearCursorState(); | 169 void ClearCursorState(); |
154 | 170 |
171 // Start the capture after setup. | |
172 void StartCapture(); | |
173 | |
155 // The window associated with the desktop. | 174 // The window associated with the desktop. |
156 aura::Window* desktop_window_; | 175 aura::Window* desktop_window_; |
157 | 176 |
158 // The timer that kicks off period captures. | 177 // The timer that kicks off period captures. |
159 base::Timer timer_; | 178 base::Timer timer_; |
160 | 179 |
161 // The id of the window being captured. | 180 // The id of the window being captured. |
162 DesktopMediaID window_id_; | 181 DesktopMediaID window_id_; |
163 | 182 |
164 // Makes all the decisions about which frames to copy, and how. | 183 // Makes all the decisions about which frames to copy, and how. |
(...skipping 18 matching lines...) Expand all Loading... | |
183 }; | 202 }; |
184 | 203 |
185 DesktopVideoCaptureMachine::DesktopVideoCaptureMachine( | 204 DesktopVideoCaptureMachine::DesktopVideoCaptureMachine( |
186 const DesktopMediaID& source) | 205 const DesktopMediaID& source) |
187 : desktop_window_(NULL), | 206 : desktop_window_(NULL), |
188 timer_(true, true), | 207 timer_(true, true), |
189 window_id_(source) {} | 208 window_id_(source) {} |
190 | 209 |
191 DesktopVideoCaptureMachine::~DesktopVideoCaptureMachine() {} | 210 DesktopVideoCaptureMachine::~DesktopVideoCaptureMachine() {} |
192 | 211 |
193 bool DesktopVideoCaptureMachine::Start( | 212 void DesktopVideoCaptureMachine::StartCapture() { |
194 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | |
195 const media::VideoCaptureParams& params) { | |
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
197 | |
198 desktop_window_ = content::DesktopMediaID::GetAuraWindowById(window_id_); | |
199 if (!desktop_window_) | |
200 return false; | |
201 | |
202 // If the associated layer is already destroyed then return failure. | |
203 ui::Layer* layer = desktop_window_->layer(); | |
204 if (!layer) | |
205 return false; | |
206 | |
207 DCHECK(oracle_proxy.get()); | |
208 oracle_proxy_ = oracle_proxy; | |
209 capture_params_ = params; | |
210 | |
211 // Update capture size. | 213 // Update capture size. |
212 UpdateCaptureSize(); | 214 UpdateCaptureSize(); |
213 | 215 |
214 // Start observing window events. | 216 // Start observing window events. |
215 desktop_window_->AddObserver(this); | 217 desktop_window_->AddObserver(this); |
216 | 218 |
217 // Start observing compositor updates. | 219 // Start observing compositor updates. |
218 if (desktop_window_->GetHost()) | 220 if (desktop_window_->GetHost()) |
219 desktop_window_->GetHost()->compositor()->AddObserver(this); | 221 desktop_window_->GetHost()->compositor()->AddObserver(this); |
220 | 222 |
221 power_save_blocker_.reset(PowerSaveBlocker::Create( | 223 power_save_blocker_.reset(PowerSaveBlocker::Create( |
222 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, | 224 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, |
223 "DesktopCaptureDevice is running").release()); | 225 "DesktopCaptureDevice is running").release()); |
224 | 226 |
225 // Starts timer. | 227 // Starts timer. |
226 timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(), | 228 timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(), |
227 base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(), | 229 base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(), |
228 false)); | 230 false)); |
231 } | |
232 | |
233 bool DesktopVideoCaptureMachine::Start( | |
Sergey Ulanov
2015/02/23 23:16:12
Can the virtual-screen logic be moved out of this
oshima
2015/02/24 19:43:21
and please move ash code from content/.
robert.bradford
2015/03/03 19:58:00
I've started working on the non virtual display re
| |
234 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | |
235 const media::VideoCaptureParams& params) { | |
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
237 | |
238 capture_params_ = params; | |
239 DCHECK(oracle_proxy.get()); | |
240 oracle_proxy_ = oracle_proxy; | |
241 | |
242 #if defined(USE_ASH) | |
oshima
2015/02/24 19:43:21
no USE_ASH in content/. You probably should just u
| |
243 // Window for virtual display is available asynchronously after request. The | |
244 // DisplayObserver on the screen will be notified of the new display and | |
245 // Window and start the capture. | |
246 if (window_id_.type == DesktopMediaID::TYPE_AURA_VIRTUAL_SCREEN) { | |
247 DCHECK(base::SysInfo::IsRunningOnChromeOS()); | |
248 ui::DisplayConfigurator* configurator = | |
249 ash::Shell::GetInstance()->display_configurator(); | |
250 gfx::Screen::GetNativeScreen()->AddObserver(this); | |
251 configurator->EnableVirtualDisplay(make_scoped_ptr( | |
252 new ui::DisplayMode(params.requested_format.frame_size, false, 60))); | |
253 return true; | |
254 } | |
255 #else | |
256 desktop_window_ = content::DesktopMediaID::GetAuraWindowById(window_id_); | |
257 #endif | |
258 | |
259 if (!desktop_window_) | |
260 return false; | |
261 | |
262 // If the associated layer is already destroyed then return failure. | |
263 ui::Layer* layer = desktop_window_->layer(); | |
264 if (!layer) | |
265 return false; | |
266 | |
267 StartCapture(); | |
229 | 268 |
230 return true; | 269 return true; |
231 } | 270 } |
232 | 271 |
233 void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) { | 272 void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) { |
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
235 power_save_blocker_.reset(); | 274 power_save_blocker_.reset(); |
236 | 275 |
237 // Stop observing compositor and window events. | 276 // Stop observing compositor and window events. |
238 if (desktop_window_) { | 277 if (desktop_window_) { |
239 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); | 278 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); |
240 // In the host destructor the compositor is destroyed before the window. | 279 // In the host destructor the compositor is destroyed before the window. |
241 if (window_host && window_host->compositor()) | 280 if (window_host && window_host->compositor()) |
242 window_host->compositor()->RemoveObserver(this); | 281 window_host->compositor()->RemoveObserver(this); |
243 desktop_window_->RemoveObserver(this); | 282 desktop_window_->RemoveObserver(this); |
244 desktop_window_ = NULL; | 283 desktop_window_ = NULL; |
245 } | 284 } |
246 | 285 |
286 #if defined(USE_ASH) | |
287 if (window_id_.type == DesktopMediaID::TYPE_AURA_VIRTUAL_SCREEN) { | |
288 gfx::Screen::GetNativeScreen()->RemoveObserver(this); | |
289 ash::Shell::GetInstance()->display_configurator()->DisableVirtualDisplay(); | |
290 } | |
291 #endif | |
292 | |
247 // Stop timer. | 293 // Stop timer. |
248 timer_.Stop(); | 294 timer_.Stop(); |
249 | 295 |
250 callback.Run(); | 296 callback.Run(); |
251 } | 297 } |
252 | 298 |
253 void DesktopVideoCaptureMachine::UpdateCaptureSize() { | 299 void DesktopVideoCaptureMachine::UpdateCaptureSize() { |
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
255 if (oracle_proxy_.get() && desktop_window_) { | 301 if (oracle_proxy_.get() && desktop_window_) { |
256 ui::Layer* layer = desktop_window_->layer(); | 302 ui::Layer* layer = desktop_window_->layer(); |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
500 DCHECK(window == desktop_window_); | 546 DCHECK(window == desktop_window_); |
501 window->GetHost()->compositor()->RemoveObserver(this); | 547 window->GetHost()->compositor()->RemoveObserver(this); |
502 } | 548 } |
503 | 549 |
504 void DesktopVideoCaptureMachine::OnCompositingEnded( | 550 void DesktopVideoCaptureMachine::OnCompositingEnded( |
505 ui::Compositor* compositor) { | 551 ui::Compositor* compositor) { |
506 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 552 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
507 &DesktopVideoCaptureMachine::Capture, AsWeakPtr(), true)); | 553 &DesktopVideoCaptureMachine::Capture, AsWeakPtr(), true)); |
508 } | 554 } |
509 | 555 |
556 void DesktopVideoCaptureMachine::OnDisplayAdded( | |
557 const gfx::Display& new_display) { | |
558 #if defined(USE_ASH) | |
559 DCHECK(base::SysInfo::IsRunningOnChromeOS()); | |
560 ui::DisplayConfigurator* configurator = | |
561 ash::Shell::GetInstance()->display_configurator(); | |
562 int64 display_id = configurator->GetVirtualDisplayId(); | |
563 | |
564 if (display_id == new_display.id()) { | |
565 desktop_window_ = ash::Shell::GetInstance() | |
566 ->display_controller() | |
567 ->GetRootWindowForDisplayId(display_id); | |
568 | |
569 // We only need the observer for a short time. | |
570 gfx::Screen::GetNativeScreen()->RemoveObserver(this); | |
571 | |
572 if (desktop_window_ && desktop_window_->layer()) { | |
573 StartCapture(); | |
574 } else { | |
575 Stop(base::Bind(&base::DoNothing)); | |
576 } | |
577 } | |
578 } | |
579 #endif | |
510 } // namespace | 580 } // namespace |
511 | 581 |
512 DesktopCaptureDeviceAura::DesktopCaptureDeviceAura( | 582 DesktopCaptureDeviceAura::DesktopCaptureDeviceAura( |
513 const DesktopMediaID& source) | 583 const DesktopMediaID& source) |
514 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( | 584 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( |
515 new DesktopVideoCaptureMachine(source)))) {} | 585 new DesktopVideoCaptureMachine(source)))) {} |
516 | 586 |
517 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { | 587 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { |
518 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; | 588 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; |
519 } | 589 } |
(...skipping 12 matching lines...) Expand all Loading... | |
532 scoped_ptr<Client> client) { | 602 scoped_ptr<Client> client) { |
533 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 603 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
534 core_->AllocateAndStart(params, client.Pass()); | 604 core_->AllocateAndStart(params, client.Pass()); |
535 } | 605 } |
536 | 606 |
537 void DesktopCaptureDeviceAura::StopAndDeAllocate() { | 607 void DesktopCaptureDeviceAura::StopAndDeAllocate() { |
538 core_->StopAndDeAllocate(); | 608 core_->StopAndDeAllocate(); |
539 } | 609 } |
540 | 610 |
541 } // namespace content | 611 } // namespace content |
OLD | NEW |