Chromium Code Reviews| 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 |