| 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/aura_window_capture_machine.h" | 5 #include "content/browser/media/capture/aura_window_capture_machine.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/timer/timer.h" | 9 #include "base/timer/timer.h" |
| 10 #include "cc/output/copy_output_request.h" | 10 #include "cc/output/copy_output_request.h" |
| 11 #include "cc/output/copy_output_result.h" | 11 #include "cc/output/copy_output_result.h" |
| 12 #include "content/browser/compositor/image_transport_factory.h" | 12 #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/desktop_capture_device_uma_types.h" | 13 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" |
| 15 #include "content/common/gpu/client/gl_helper.h" | 14 #include "content/common/gpu/client/gl_helper.h" |
| 16 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
| 17 #include "content/public/browser/power_save_blocker.h" | 16 #include "content/public/browser/power_save_blocker.h" |
| 18 #include "media/base/video_capture_types.h" | 17 #include "media/base/video_capture_types.h" |
| 19 #include "media/base/video_util.h" | 18 #include "media/base/video_util.h" |
| 19 #include "media/capture/media_video_capture_device_core.h" |
| 20 #include "skia/ext/image_operations.h" | 20 #include "skia/ext/image_operations.h" |
| 21 #include "third_party/skia/include/core/SkBitmap.h" | 21 #include "third_party/skia/include/core/SkBitmap.h" |
| 22 #include "ui/aura/client/screen_position_client.h" | 22 #include "ui/aura/client/screen_position_client.h" |
| 23 #include "ui/aura/env.h" | 23 #include "ui/aura/env.h" |
| 24 #include "ui/aura/window.h" | 24 #include "ui/aura/window.h" |
| 25 #include "ui/aura/window_observer.h" | 25 #include "ui/aura/window_observer.h" |
| 26 #include "ui/aura/window_tree_host.h" | 26 #include "ui/aura/window_tree_host.h" |
| 27 #include "ui/base/cursor/cursors_aura.h" | 27 #include "ui/base/cursor/cursors_aura.h" |
| 28 #include "ui/compositor/compositor.h" | 28 #include "ui/compositor/compositor.h" |
| 29 #include "ui/compositor/dip_util.h" | 29 #include "ui/compositor/dip_util.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]); | 84 uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]); |
| 85 vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]); | 85 vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]); |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 } | 88 } |
| 89 cursor_bitmap.unlockPixels(); | 89 cursor_bitmap.unlockPixels(); |
| 90 } | 90 } |
| 91 | 91 |
| 92 void CopyOutputFinishedForVideo( | 92 void CopyOutputFinishedForVideo( |
| 93 base::TimeTicks start_time, | 93 base::TimeTicks start_time, |
| 94 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 94 const CaptureFrameCallback& capture_frame_cb, |
| 95 const scoped_refptr<media::VideoFrame>& target, | 95 const scoped_refptr<media::VideoFrame>& target, |
| 96 const SkBitmap& cursor_bitmap, | 96 const SkBitmap& cursor_bitmap, |
| 97 const gfx::Point& cursor_position, | 97 const gfx::Point& cursor_position, |
| 98 scoped_ptr<cc::SingleReleaseCallback> release_callback, | 98 scoped_ptr<cc::SingleReleaseCallback> release_callback, |
| 99 bool result) { | 99 bool result) { |
| 100 if (!cursor_bitmap.isNull()) | 100 if (!cursor_bitmap.isNull()) |
| 101 RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position); | 101 RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position); |
| 102 release_callback->Run(0, false); | 102 release_callback->Run(0, false); |
| 103 capture_frame_cb.Run(target, start_time, result); | 103 capture_frame_cb.Run(target, start_time, result); |
| 104 } | 104 } |
| 105 | 105 |
| 106 void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb, | 106 void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb, |
| 107 uint32 sync_point) { | 107 uint32 sync_point) { |
| 108 cb->Run(sync_point, false); | 108 cb->Run(sync_point, false); |
| 109 } | 109 } |
| 110 | 110 |
| 111 } // namespace | 111 } // namespace |
| 112 | 112 |
| 113 AuraWindowCaptureMachine::AuraWindowCaptureMachine() | 113 AuraWindowCaptureMachine::AuraWindowCaptureMachine() |
| 114 : desktop_window_(NULL), | 114 : desktop_window_(NULL), |
| 115 timer_(true, true), | 115 timer_(true, true), |
| 116 screen_capture_(false) {} | 116 screen_capture_(false) {} |
| 117 | 117 |
| 118 AuraWindowCaptureMachine::~AuraWindowCaptureMachine() {} | 118 AuraWindowCaptureMachine::~AuraWindowCaptureMachine() {} |
| 119 | 119 |
| 120 bool AuraWindowCaptureMachine::Start( | 120 void AuraWindowCaptureMachine::Start( |
| 121 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 121 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
| 122 const media::VideoCaptureParams& params, |
| 123 const base::Callback<void(bool)> callback) { |
| 124 // Starts the capture machine asynchronously. |
| 125 BrowserThread::PostTaskAndReplyWithResult( |
| 126 BrowserThread::UI, |
| 127 FROM_HERE, |
| 128 base::Bind(&AuraWindowCaptureMachine::InternalStart, |
| 129 base::Unretained(this), |
| 130 oracle_proxy, |
| 131 params), |
| 132 callback); |
| 133 } |
| 134 |
| 135 bool AuraWindowCaptureMachine::InternalStart( |
| 136 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
| 122 const media::VideoCaptureParams& params) { | 137 const media::VideoCaptureParams& params) { |
| 123 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 138 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 124 | 139 |
| 125 // The window might be destroyed between SetWindow() and Start(). | 140 // The window might be destroyed between SetWindow() and Start(). |
| 126 if (!desktop_window_) | 141 if (!desktop_window_) |
| 127 return false; | 142 return false; |
| 128 | 143 |
| 129 // If the associated layer is already destroyed then return failure. | 144 // If the associated layer is already destroyed then return failure. |
| 130 ui::Layer* layer = desktop_window_->layer(); | 145 ui::Layer* layer = desktop_window_->layer(); |
| 131 if (!layer) | 146 if (!layer) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 153 std::max(oracle_proxy_->min_capture_period(), | 168 std::max(oracle_proxy_->min_capture_period(), |
| 154 base::TimeDelta::FromMilliseconds( | 169 base::TimeDelta::FromMilliseconds( |
| 155 VideoCaptureOracle::kMinTimerPollPeriodMillis)), | 170 VideoCaptureOracle::kMinTimerPollPeriodMillis)), |
| 156 base::Bind(&AuraWindowCaptureMachine::Capture, AsWeakPtr(), | 171 base::Bind(&AuraWindowCaptureMachine::Capture, AsWeakPtr(), |
| 157 false)); | 172 false)); |
| 158 | 173 |
| 159 return true; | 174 return true; |
| 160 } | 175 } |
| 161 | 176 |
| 162 void AuraWindowCaptureMachine::Stop(const base::Closure& callback) { | 177 void AuraWindowCaptureMachine::Stop(const base::Closure& callback) { |
| 178 // Stops the capture machine asynchronously. |
| 179 BrowserThread::PostTask( |
| 180 BrowserThread::UI, FROM_HERE, base::Bind( |
| 181 &AuraWindowCaptureMachine::InternalStop, |
| 182 base::Unretained(this), |
| 183 callback)); |
| 184 } |
| 185 |
| 186 void AuraWindowCaptureMachine::InternalStop(const base::Closure& callback) { |
| 163 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 187 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 164 power_save_blocker_.reset(); | 188 power_save_blocker_.reset(); |
| 165 | 189 |
| 166 // Stop observing compositor and window events. | 190 // Stop observing compositor and window events. |
| 167 if (desktop_window_) { | 191 if (desktop_window_) { |
| 168 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); | 192 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); |
| 169 // In the host destructor the compositor is destroyed before the window. | 193 // In the host destructor the compositor is destroyed before the window. |
| 170 if (window_host && window_host->compositor()) | 194 if (window_host && window_host->compositor()) |
| 171 window_host->compositor()->RemoveObserver(this); | 195 window_host->compositor()->RemoveObserver(this); |
| 172 desktop_window_->RemoveObserver(this); | 196 desktop_window_->RemoveObserver(this); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 } | 230 } |
| 207 | 231 |
| 208 void AuraWindowCaptureMachine::Capture(bool dirty) { | 232 void AuraWindowCaptureMachine::Capture(bool dirty) { |
| 209 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 233 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 210 | 234 |
| 211 // Do not capture if the desktop window is already destroyed. | 235 // Do not capture if the desktop window is already destroyed. |
| 212 if (!desktop_window_) | 236 if (!desktop_window_) |
| 213 return; | 237 return; |
| 214 | 238 |
| 215 scoped_refptr<media::VideoFrame> frame; | 239 scoped_refptr<media::VideoFrame> frame; |
| 216 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; | 240 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
| 217 | 241 |
| 218 // TODO(miu): Need to fix this so the compositor is providing the presentation | 242 // TODO(miu): Need to fix this so the compositor is providing the presentation |
| 219 // timestamps and damage regions, to leverage the frame timestamp rewriting | 243 // timestamps and damage regions, to leverage the frame timestamp rewriting |
| 220 // logic. http://crbug.com/492839 | 244 // logic. http://crbug.com/492839 |
| 221 const base::TimeTicks start_time = base::TimeTicks::Now(); | 245 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 222 const VideoCaptureOracle::Event event = | 246 const VideoCaptureOracle::Event event = |
| 223 dirty ? VideoCaptureOracle::kCompositorUpdate | 247 dirty ? VideoCaptureOracle::kCompositorUpdate |
| 224 : VideoCaptureOracle::kTimerPoll; | 248 : VideoCaptureOracle::kTimerPoll; |
| 225 if (oracle_proxy_->ObserveEventAndDecideCapture( | 249 if (oracle_proxy_->ObserveEventAndDecideCapture( |
| 226 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) { | 250 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) { |
| 227 scoped_ptr<cc::CopyOutputRequest> request = | 251 scoped_ptr<cc::CopyOutputRequest> request = |
| 228 cc::CopyOutputRequest::CreateRequest( | 252 cc::CopyOutputRequest::CreateRequest( |
| 229 base::Bind(&AuraWindowCaptureMachine::DidCopyOutput, | 253 base::Bind(&AuraWindowCaptureMachine::DidCopyOutput, |
| 230 AsWeakPtr(), frame, start_time, capture_frame_cb)); | 254 AsWeakPtr(), frame, start_time, capture_frame_cb)); |
| 231 gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), | 255 gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), |
| 232 desktop_window_->bounds().height()); | 256 desktop_window_->bounds().height()); |
| 233 request->set_area(window_rect); | 257 request->set_area(window_rect); |
| 234 desktop_window_->layer()->RequestCopyOfOutput(request.Pass()); | 258 desktop_window_->layer()->RequestCopyOfOutput(request.Pass()); |
| 235 } | 259 } |
| 236 } | 260 } |
| 237 | 261 |
| 238 void AuraWindowCaptureMachine::DidCopyOutput( | 262 void AuraWindowCaptureMachine::DidCopyOutput( |
| 239 scoped_refptr<media::VideoFrame> video_frame, | 263 scoped_refptr<media::VideoFrame> video_frame, |
| 240 base::TimeTicks start_time, | 264 base::TimeTicks start_time, |
| 241 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 265 const CaptureFrameCallback& capture_frame_cb, |
| 242 scoped_ptr<cc::CopyOutputResult> result) { | 266 scoped_ptr<cc::CopyOutputResult> result) { |
| 243 static bool first_call = true; | 267 static bool first_call = true; |
| 244 | 268 |
| 245 bool succeeded = ProcessCopyOutputResponse( | 269 bool succeeded = ProcessCopyOutputResponse( |
| 246 video_frame, start_time, capture_frame_cb, result.Pass()); | 270 video_frame, start_time, capture_frame_cb, result.Pass()); |
| 247 | 271 |
| 248 base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; | 272 base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; |
| 249 | 273 |
| 250 // The two UMA_ blocks must be put in its own scope since it creates a static | 274 // The two UMA_ blocks must be put in its own scope since it creates a static |
| 251 // variable which expected constant histogram name. | 275 // variable which expected constant histogram name. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 264 IncrementDesktopCaptureCounter(succeeded | 288 IncrementDesktopCaptureCounter(succeeded |
| 265 ? FIRST_WINDOW_CAPTURE_SUCCEEDED | 289 ? FIRST_WINDOW_CAPTURE_SUCCEEDED |
| 266 : FIRST_WINDOW_CAPTURE_FAILED); | 290 : FIRST_WINDOW_CAPTURE_FAILED); |
| 267 } | 291 } |
| 268 } | 292 } |
| 269 } | 293 } |
| 270 | 294 |
| 271 bool AuraWindowCaptureMachine::ProcessCopyOutputResponse( | 295 bool AuraWindowCaptureMachine::ProcessCopyOutputResponse( |
| 272 scoped_refptr<media::VideoFrame> video_frame, | 296 scoped_refptr<media::VideoFrame> video_frame, |
| 273 base::TimeTicks start_time, | 297 base::TimeTicks start_time, |
| 274 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 298 const CaptureFrameCallback& capture_frame_cb, |
| 275 scoped_ptr<cc::CopyOutputResult> result) { | 299 scoped_ptr<cc::CopyOutputResult> result) { |
| 276 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 300 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 277 | 301 |
| 278 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_) | 302 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_) |
| 279 return false; | 303 return false; |
| 280 | 304 |
| 281 if (capture_params_.requested_format.pixel_format == | 305 if (capture_params_.requested_format.pixel_format == |
| 282 media::PIXEL_FORMAT_TEXTURE) { | 306 media::PIXEL_FORMAT_TEXTURE) { |
| 283 DCHECK(!video_frame.get()); | 307 DCHECK(!video_frame.get()); |
| 284 cc::TextureMailbox texture_mailbox; | 308 cc::TextureMailbox texture_mailbox; |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 | 472 |
| 449 void AuraWindowCaptureMachine::OnCompositingEnded( | 473 void AuraWindowCaptureMachine::OnCompositingEnded( |
| 450 ui::Compositor* compositor) { | 474 ui::Compositor* compositor) { |
| 451 // TODO(miu): The CopyOutputRequest should be made earlier, at WillCommit(). | 475 // TODO(miu): The CopyOutputRequest should be made earlier, at WillCommit(). |
| 452 // http://crbug.com/492839 | 476 // http://crbug.com/492839 |
| 453 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 477 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 454 &AuraWindowCaptureMachine::Capture, AsWeakPtr(), true)); | 478 &AuraWindowCaptureMachine::Capture, AsWeakPtr(), true)); |
| 455 } | 479 } |
| 456 | 480 |
| 457 } // namespace content | 481 } // namespace content |
| OLD | NEW |