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 |