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/aura_window_capture_machine.h" | 5 #include "content/browser/media/capture/aura_window_capture_machine.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 return false; | 73 return false; |
| 74 | 74 |
| 75 DCHECK(oracle_proxy); | 75 DCHECK(oracle_proxy); |
| 76 oracle_proxy_ = oracle_proxy; | 76 oracle_proxy_ = oracle_proxy; |
| 77 capture_params_ = params; | 77 capture_params_ = params; |
| 78 | 78 |
| 79 // Update capture size. | 79 // Update capture size. |
| 80 UpdateCaptureSize(); | 80 UpdateCaptureSize(); |
| 81 | 81 |
| 82 // Start observing compositor updates. | 82 // Start observing compositor updates. |
| 83 if (desktop_window_->GetHost()) | 83 if (aura::WindowTreeHost* host = desktop_window_->GetHost()) { |
| 84 desktop_window_->GetHost()->compositor()->AddObserver(this); | 84 if (ui::Compositor* compositor = host->compositor()) |
| 85 compositor->AddAnimationObserver(this); | |
| 86 } | |
|
GeorgeZ
2016/04/27 16:44:34
The function may return false if host or composito
miu
2016/04/27 19:01:24
Done.
| |
| 85 | 87 |
| 86 power_save_blocker_.reset( | 88 power_save_blocker_.reset( |
| 87 PowerSaveBlocker::Create( | 89 PowerSaveBlocker::Create( |
| 88 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, | 90 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, |
| 89 PowerSaveBlocker::kReasonOther, | 91 PowerSaveBlocker::kReasonOther, |
| 90 "DesktopCaptureDevice is running").release()); | 92 "DesktopCaptureDevice is running").release()); |
| 91 | 93 |
| 92 return true; | 94 return true; |
| 93 } | 95 } |
| 94 | 96 |
| 95 void AuraWindowCaptureMachine::Stop(const base::Closure& callback) { | 97 void AuraWindowCaptureMachine::Stop(const base::Closure& callback) { |
| 96 // Stops the capture machine asynchronously. | 98 // Stops the capture machine asynchronously. |
| 97 BrowserThread::PostTask( | 99 BrowserThread::PostTask( |
| 98 BrowserThread::UI, FROM_HERE, base::Bind( | 100 BrowserThread::UI, FROM_HERE, base::Bind( |
| 99 &AuraWindowCaptureMachine::InternalStop, | 101 &AuraWindowCaptureMachine::InternalStop, |
| 100 base::Unretained(this), | 102 base::Unretained(this), |
| 101 callback)); | 103 callback)); |
| 102 } | 104 } |
| 103 | 105 |
| 104 void AuraWindowCaptureMachine::InternalStop(const base::Closure& callback) { | 106 void AuraWindowCaptureMachine::InternalStop(const base::Closure& callback) { |
| 105 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 107 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 106 | 108 |
| 107 // Cancel any and all outstanding callbacks owned by external modules. | 109 // Cancel any and all outstanding callbacks owned by external modules. |
| 108 weak_factory_.InvalidateWeakPtrs(); | 110 weak_factory_.InvalidateWeakPtrs(); |
| 109 | 111 |
| 110 power_save_blocker_.reset(); | 112 power_save_blocker_.reset(); |
| 111 | 113 |
| 112 // Stop observing compositor and window events. | 114 // Stop observing compositor and window events. |
| 113 if (desktop_window_) { | 115 if (desktop_window_) { |
| 114 aura::WindowTreeHost* window_host = desktop_window_->GetHost(); | 116 if (aura::WindowTreeHost* host = desktop_window_->GetHost()) { |
| 115 // In the host destructor the compositor is destroyed before the window. | 117 if (ui::Compositor* compositor = host->compositor()) |
| 116 if (window_host && window_host->compositor()) | 118 compositor->RemoveAnimationObserver(this); |
| 117 window_host->compositor()->RemoveObserver(this); | 119 } |
| 118 desktop_window_->RemoveObserver(this); | 120 desktop_window_->RemoveObserver(this); |
| 119 desktop_window_ = NULL; | 121 desktop_window_ = NULL; |
| 120 cursor_renderer_.reset(); | 122 cursor_renderer_.reset(); |
| 121 } | 123 } |
| 122 | 124 |
| 123 callback.Run(); | 125 callback.Run(); |
| 124 } | 126 } |
| 125 | 127 |
| 126 void AuraWindowCaptureMachine::MaybeCaptureForRefresh() { | 128 void AuraWindowCaptureMachine::MaybeCaptureForRefresh() { |
| 127 BrowserThread::PostTask( | 129 BrowserThread::PostTask( |
| 128 BrowserThread::UI, FROM_HERE, | 130 BrowserThread::UI, FROM_HERE, |
| 129 base::Bind(&AuraWindowCaptureMachine::Capture, | 131 base::Bind(&AuraWindowCaptureMachine::Capture, |
| 130 // Use of Unretained() is safe here since this task must run | 132 // Use of Unretained() is safe here since this task must run |
| 131 // before InternalStop(). | 133 // before InternalStop(). |
| 132 base::Unretained(this), | 134 base::Unretained(this), |
| 133 false)); | 135 base::TimeTicks())); |
| 134 } | 136 } |
| 135 | 137 |
| 136 void AuraWindowCaptureMachine::SetWindow(aura::Window* window) { | 138 void AuraWindowCaptureMachine::SetWindow(aura::Window* window) { |
| 137 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 139 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 138 | 140 |
| 139 DCHECK(!desktop_window_); | 141 DCHECK(!desktop_window_); |
| 140 desktop_window_ = window; | 142 desktop_window_ = window; |
| 141 cursor_renderer_.reset(new CursorRendererAura(window, kCursorAlwaysEnabled)); | 143 cursor_renderer_.reset(new CursorRendererAura(window, kCursorAlwaysEnabled)); |
| 142 | 144 |
| 143 // Start observing window events. | 145 // Start observing window events. |
| 144 desktop_window_->AddObserver(this); | 146 desktop_window_->AddObserver(this); |
| 145 | 147 |
| 146 // We must store this for the UMA reporting in DidCopyOutput() as | 148 // We must store this for the UMA reporting in DidCopyOutput() as |
| 147 // desktop_window_ might be destroyed at that point. | 149 // desktop_window_ might be destroyed at that point. |
| 148 screen_capture_ = window->IsRootWindow(); | 150 screen_capture_ = window->IsRootWindow(); |
| 149 IncrementDesktopCaptureCounter(screen_capture_ ? SCREEN_CAPTURER_CREATED | 151 IncrementDesktopCaptureCounter(screen_capture_ ? SCREEN_CAPTURER_CREATED |
| 150 : WINDOW_CAPTURER_CREATED); | 152 : WINDOW_CAPTURER_CREATED); |
| 151 } | 153 } |
| 152 | 154 |
| 153 void AuraWindowCaptureMachine::UpdateCaptureSize() { | 155 void AuraWindowCaptureMachine::UpdateCaptureSize() { |
| 154 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 156 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 155 if (oracle_proxy_ && desktop_window_) { | 157 if (oracle_proxy_ && desktop_window_) { |
| 156 ui::Layer* layer = desktop_window_->layer(); | 158 ui::Layer* layer = desktop_window_->layer(); |
| 157 oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel( | 159 oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel( |
| 158 layer, layer->bounds().size())); | 160 layer, layer->bounds().size())); |
| 159 } | 161 } |
| 160 cursor_renderer_->Clear(); | 162 cursor_renderer_->Clear(); |
| 161 } | 163 } |
| 162 | 164 |
| 163 void AuraWindowCaptureMachine::Capture(bool dirty) { | 165 void AuraWindowCaptureMachine::Capture(base::TimeTicks event_time) { |
| 164 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 166 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 165 | 167 |
| 166 // Do not capture if the desktop window is already destroyed. | 168 // Do not capture if the desktop window is already destroyed. |
| 167 if (!desktop_window_) | 169 if (!desktop_window_) |
| 168 return; | 170 return; |
| 169 | 171 |
| 170 scoped_refptr<media::VideoFrame> frame; | 172 scoped_refptr<media::VideoFrame> frame; |
| 171 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; | 173 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
| 172 | 174 |
| 173 // TODO(miu): Need to fix this so the compositor is providing the presentation | 175 // TODO(miu): Need to fix this so the compositor is providing the presentation |
| 174 // timestamps and damage regions, to leverage the frame timestamp rewriting | 176 // timestamps and damage regions, to leverage the frame timestamp rewriting |
| 175 // logic. http://crbug.com/492839 | 177 // logic. http://crbug.com/492839 |
| 176 const base::TimeTicks start_time = base::TimeTicks::Now(); | 178 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 177 const media::VideoCaptureOracle::Event event = | 179 media::VideoCaptureOracle::Event event; |
| 178 dirty ? media::VideoCaptureOracle::kCompositorUpdate | 180 if (event_time.is_null()) { |
| 179 : media::VideoCaptureOracle::kActiveRefreshRequest; | 181 event = media::VideoCaptureOracle::kActiveRefreshRequest; |
| 182 event_time = start_time; | |
| 183 } else { | |
| 184 event = media::VideoCaptureOracle::kCompositorUpdate; | |
| 185 } | |
| 180 if (oracle_proxy_->ObserveEventAndDecideCapture( | 186 if (oracle_proxy_->ObserveEventAndDecideCapture( |
| 181 event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) { | 187 event, gfx::Rect(), event_time, &frame, &capture_frame_cb)) { |
| 182 std::unique_ptr<cc::CopyOutputRequest> request = | 188 std::unique_ptr<cc::CopyOutputRequest> request = |
| 183 cc::CopyOutputRequest::CreateRequest(base::Bind( | 189 cc::CopyOutputRequest::CreateRequest(base::Bind( |
| 184 &AuraWindowCaptureMachine::DidCopyOutput, | 190 &AuraWindowCaptureMachine::DidCopyOutput, |
| 185 weak_factory_.GetWeakPtr(), frame, start_time, capture_frame_cb)); | 191 weak_factory_.GetWeakPtr(), frame, event_time, start_time, |
| 192 capture_frame_cb)); | |
| 186 gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), | 193 gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), |
| 187 desktop_window_->bounds().height()); | 194 desktop_window_->bounds().height()); |
| 188 request->set_area(window_rect); | 195 request->set_area(window_rect); |
| 189 desktop_window_->layer()->RequestCopyOfOutput(std::move(request)); | 196 desktop_window_->layer()->RequestCopyOfOutput(std::move(request)); |
| 190 } | 197 } |
| 191 } | 198 } |
| 192 | 199 |
| 193 void AuraWindowCaptureMachine::DidCopyOutput( | 200 void AuraWindowCaptureMachine::DidCopyOutput( |
| 194 scoped_refptr<media::VideoFrame> video_frame, | 201 scoped_refptr<media::VideoFrame> video_frame, |
| 202 base::TimeTicks event_time, | |
| 195 base::TimeTicks start_time, | 203 base::TimeTicks start_time, |
| 196 const CaptureFrameCallback& capture_frame_cb, | 204 const CaptureFrameCallback& capture_frame_cb, |
| 197 std::unique_ptr<cc::CopyOutputResult> result) { | 205 std::unique_ptr<cc::CopyOutputResult> result) { |
| 198 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 206 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 199 | 207 |
| 200 static bool first_call = true; | 208 static bool first_call = true; |
| 201 | 209 |
| 202 const bool succeeded = ProcessCopyOutputResponse( | 210 const bool succeeded = ProcessCopyOutputResponse( |
| 203 video_frame, start_time, capture_frame_cb, std::move(result)); | 211 video_frame, event_time, capture_frame_cb, std::move(result)); |
| 204 | 212 |
| 205 base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; | 213 const base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; |
| 206 | 214 |
| 207 // The two UMA_ blocks must be put in its own scope since it creates a static | 215 // The two UMA_ blocks must be put in its own scope since it creates a static |
| 208 // variable which expected constant histogram name. | 216 // variable which expected constant histogram name. |
| 209 if (screen_capture_) { | 217 if (screen_capture_) { |
| 210 UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time); | 218 UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time); |
| 211 } else { | 219 } else { |
| 212 UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time); | 220 UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time); |
| 213 } | 221 } |
| 214 | 222 |
| 215 if (first_call) { | 223 if (first_call) { |
| 216 first_call = false; | 224 first_call = false; |
| 217 if (screen_capture_) { | 225 if (screen_capture_) { |
| 218 IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED | 226 IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED |
| 219 : FIRST_SCREEN_CAPTURE_FAILED); | 227 : FIRST_SCREEN_CAPTURE_FAILED); |
| 220 } else { | 228 } else { |
| 221 IncrementDesktopCaptureCounter(succeeded | 229 IncrementDesktopCaptureCounter(succeeded |
| 222 ? FIRST_WINDOW_CAPTURE_SUCCEEDED | 230 ? FIRST_WINDOW_CAPTURE_SUCCEEDED |
| 223 : FIRST_WINDOW_CAPTURE_FAILED); | 231 : FIRST_WINDOW_CAPTURE_FAILED); |
| 224 } | 232 } |
| 225 } | 233 } |
| 226 | 234 |
| 227 // If ProcessCopyOutputResponse() failed, it will not run |capture_frame_cb|, | 235 // If ProcessCopyOutputResponse() failed, it will not run |capture_frame_cb|, |
| 228 // so do that now. | 236 // so do that now. |
| 229 if (!succeeded) | 237 if (!succeeded) |
| 230 capture_frame_cb.Run(video_frame, start_time, false); | 238 capture_frame_cb.Run(video_frame, event_time, false); |
| 231 } | 239 } |
| 232 | 240 |
| 233 bool AuraWindowCaptureMachine::ProcessCopyOutputResponse( | 241 bool AuraWindowCaptureMachine::ProcessCopyOutputResponse( |
| 234 scoped_refptr<media::VideoFrame> video_frame, | 242 scoped_refptr<media::VideoFrame> video_frame, |
| 235 base::TimeTicks start_time, | 243 base::TimeTicks event_time, |
| 236 const CaptureFrameCallback& capture_frame_cb, | 244 const CaptureFrameCallback& capture_frame_cb, |
| 237 std::unique_ptr<cc::CopyOutputResult> result) { | 245 std::unique_ptr<cc::CopyOutputResult> result) { |
| 238 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 246 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 239 | 247 |
| 240 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_window_) | 248 if (!desktop_window_) { |
| 249 VLOG(1) << "Ignoring CopyOutputResult: Capture target has gone away."; | |
| 241 return false; | 250 return false; |
| 251 } | |
| 252 if (result->IsEmpty()) { | |
| 253 VLOG(1) << "CopyOutputRequest failed: No texture or bitmap in result."; | |
| 254 return false; | |
| 255 } | |
| 256 if (result->size().IsEmpty()) { | |
| 257 VLOG(1) << "CopyOutputRequest failed: Zero-area texture/bitmap result."; | |
| 258 return false; | |
| 259 } | |
| 242 DCHECK(video_frame); | 260 DCHECK(video_frame); |
| 243 | 261 |
| 244 // Compute the dest size we want after the letterboxing resize. Make the | 262 // Compute the dest size we want after the letterboxing resize. Make the |
| 245 // coordinates and sizes even because we letterbox in YUV space | 263 // coordinates and sizes even because we letterbox in YUV space |
| 246 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to | 264 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to |
| 247 // line up correctly. | 265 // line up correctly. |
| 248 // The video frame's visible_rect() and the result's size() are both physical | 266 // The video frame's visible_rect() and the result's size() are both physical |
| 249 // pixels. | 267 // pixels. |
| 250 gfx::Rect region_in_frame = media::ComputeLetterboxRegion( | 268 gfx::Rect region_in_frame = media::ComputeLetterboxRegion( |
| 251 video_frame->visible_rect(), result->size()); | 269 video_frame->visible_rect(), result->size()); |
| 252 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, | 270 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, |
| 253 region_in_frame.y() & ~1, | 271 region_in_frame.y() & ~1, |
| 254 region_in_frame.width() & ~1, | 272 region_in_frame.width() & ~1, |
| 255 region_in_frame.height() & ~1); | 273 region_in_frame.height() & ~1); |
| 256 if (region_in_frame.IsEmpty()) | 274 if (region_in_frame.IsEmpty()) { |
| 275 VLOG(1) << "Aborting capture: Computed empty letterboxed content region."; | |
| 257 return false; | 276 return false; |
| 277 } | |
| 258 | 278 |
| 259 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); | 279 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
| 260 display_compositor::GLHelper* gl_helper = factory->GetGLHelper(); | 280 display_compositor::GLHelper* gl_helper = factory->GetGLHelper(); |
| 261 if (!gl_helper) | 281 if (!gl_helper) { |
| 282 VLOG(1) << "Aborting capture: No GLHelper available for YUV readback."; | |
| 262 return false; | 283 return false; |
| 284 } | |
| 263 | 285 |
| 264 cc::TextureMailbox texture_mailbox; | 286 cc::TextureMailbox texture_mailbox; |
| 265 std::unique_ptr<cc::SingleReleaseCallback> release_callback; | 287 std::unique_ptr<cc::SingleReleaseCallback> release_callback; |
| 266 result->TakeTexture(&texture_mailbox, &release_callback); | 288 result->TakeTexture(&texture_mailbox, &release_callback); |
| 267 DCHECK(texture_mailbox.IsTexture()); | 289 DCHECK(texture_mailbox.IsTexture()); |
| 268 if (!texture_mailbox.IsTexture()) | 290 if (!texture_mailbox.IsTexture()) { |
| 291 VLOG(1) << "Aborting capture: Failed to take texture from mailbox."; | |
| 269 return false; | 292 return false; |
| 293 } | |
| 270 | 294 |
| 271 gfx::Rect result_rect(result->size()); | 295 gfx::Rect result_rect(result->size()); |
| 272 if (!yuv_readback_pipeline_ || | 296 if (!yuv_readback_pipeline_ || |
| 273 yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() || | 297 yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() || |
| 274 yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect || | 298 yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect || |
| 275 yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) { | 299 yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) { |
| 276 yuv_readback_pipeline_.reset(gl_helper->CreateReadbackPipelineYUV( | 300 yuv_readback_pipeline_.reset(gl_helper->CreateReadbackPipelineYUV( |
| 277 display_compositor::GLHelper::SCALER_QUALITY_FAST, result_rect.size(), | 301 display_compositor::GLHelper::SCALER_QUALITY_FAST, result_rect.size(), |
| 278 result_rect, region_in_frame.size(), true, true)); | 302 result_rect, region_in_frame.size(), true, true)); |
| 279 } | 303 } |
| 280 | 304 |
| 281 cursor_renderer_->SnapshotCursorState(region_in_frame); | 305 cursor_renderer_->SnapshotCursorState(region_in_frame); |
| 282 yuv_readback_pipeline_->ReadbackYUV( | 306 yuv_readback_pipeline_->ReadbackYUV( |
| 283 texture_mailbox.mailbox(), texture_mailbox.sync_token(), | 307 texture_mailbox.mailbox(), texture_mailbox.sync_token(), |
| 284 video_frame->visible_rect(), | 308 video_frame->visible_rect(), |
| 285 video_frame->stride(media::VideoFrame::kYPlane), | 309 video_frame->stride(media::VideoFrame::kYPlane), |
| 286 video_frame->data(media::VideoFrame::kYPlane), | 310 video_frame->data(media::VideoFrame::kYPlane), |
| 287 video_frame->stride(media::VideoFrame::kUPlane), | 311 video_frame->stride(media::VideoFrame::kUPlane), |
| 288 video_frame->data(media::VideoFrame::kUPlane), | 312 video_frame->data(media::VideoFrame::kUPlane), |
| 289 video_frame->stride(media::VideoFrame::kVPlane), | 313 video_frame->stride(media::VideoFrame::kVPlane), |
| 290 video_frame->data(media::VideoFrame::kVPlane), region_in_frame.origin(), | 314 video_frame->data(media::VideoFrame::kVPlane), region_in_frame.origin(), |
| 291 base::Bind(&CopyOutputFinishedForVideo, weak_factory_.GetWeakPtr(), | 315 base::Bind(&CopyOutputFinishedForVideo, weak_factory_.GetWeakPtr(), |
| 292 start_time, capture_frame_cb, video_frame, | 316 event_time, capture_frame_cb, video_frame, |
| 293 base::Passed(&release_callback))); | 317 base::Passed(&release_callback))); |
| 294 media::LetterboxYUV(video_frame.get(), region_in_frame); | 318 media::LetterboxYUV(video_frame.get(), region_in_frame); |
| 295 return true; | 319 return true; |
| 296 } | 320 } |
| 297 | 321 |
| 298 using CaptureFrameCallback = | 322 using CaptureFrameCallback = |
| 299 media::ThreadSafeCaptureOracle::CaptureFrameCallback; | 323 media::ThreadSafeCaptureOracle::CaptureFrameCallback; |
| 300 | 324 |
| 301 void AuraWindowCaptureMachine::CopyOutputFinishedForVideo( | 325 void AuraWindowCaptureMachine::CopyOutputFinishedForVideo( |
| 302 base::WeakPtr<AuraWindowCaptureMachine> machine, | 326 base::WeakPtr<AuraWindowCaptureMachine> machine, |
| 303 base::TimeTicks start_time, | 327 base::TimeTicks event_time, |
| 304 const CaptureFrameCallback& capture_frame_cb, | 328 const CaptureFrameCallback& capture_frame_cb, |
| 305 const scoped_refptr<media::VideoFrame>& target, | 329 const scoped_refptr<media::VideoFrame>& target, |
| 306 std::unique_ptr<cc::SingleReleaseCallback> release_callback, | 330 std::unique_ptr<cc::SingleReleaseCallback> release_callback, |
| 307 bool result) { | 331 bool result) { |
| 308 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 332 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 309 | 333 |
| 310 release_callback->Run(gpu::SyncToken(), false); | 334 release_callback->Run(gpu::SyncToken(), false); |
| 311 | 335 |
| 312 // Render the cursor and deliver the captured frame if the | 336 // Render the cursor and deliver the captured frame if the |
| 313 // AuraWindowCaptureMachine has not been stopped (i.e., the WeakPtr is | 337 // AuraWindowCaptureMachine has not been stopped (i.e., the WeakPtr is |
| 314 // still valid). | 338 // still valid). |
| 315 if (machine) { | 339 if (machine) { |
| 316 if (machine->cursor_renderer_ && result) | 340 if (machine->cursor_renderer_ && result) |
| 317 machine->cursor_renderer_->RenderOnVideoFrame(target); | 341 machine->cursor_renderer_->RenderOnVideoFrame(target); |
| 318 } else { | 342 } else { |
| 343 VLOG(1) << "Aborting capture: AuraWindowCaptureMachine has gone away."; | |
| 319 result = false; | 344 result = false; |
| 320 } | 345 } |
| 321 | 346 |
| 322 capture_frame_cb.Run(target, start_time, result); | 347 capture_frame_cb.Run(target, event_time, result); |
| 323 } | 348 } |
| 324 | 349 |
| 325 void AuraWindowCaptureMachine::OnWindowBoundsChanged( | 350 void AuraWindowCaptureMachine::OnWindowBoundsChanged( |
| 326 aura::Window* window, | 351 aura::Window* window, |
| 327 const gfx::Rect& old_bounds, | 352 const gfx::Rect& old_bounds, |
| 328 const gfx::Rect& new_bounds) { | 353 const gfx::Rect& new_bounds) { |
| 329 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 354 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 330 DCHECK(desktop_window_ && window == desktop_window_); | 355 DCHECK(desktop_window_ && window == desktop_window_); |
| 331 | 356 |
| 332 // Post a task to update capture size after first returning to the event loop. | 357 // Post a task to update capture size after first returning to the event loop. |
| 333 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 358 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
| 334 &AuraWindowCaptureMachine::UpdateCaptureSize, | 359 &AuraWindowCaptureMachine::UpdateCaptureSize, |
| 335 weak_factory_.GetWeakPtr())); | 360 weak_factory_.GetWeakPtr())); |
| 336 } | 361 } |
| 337 | 362 |
| 338 void AuraWindowCaptureMachine::OnWindowDestroying(aura::Window* window) { | 363 void AuraWindowCaptureMachine::OnWindowDestroying(aura::Window* window) { |
| 339 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 364 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 340 | 365 |
| 341 InternalStop(base::Bind(&base::DoNothing)); | 366 InternalStop(base::Bind(&base::DoNothing)); |
| 342 | 367 |
| 343 oracle_proxy_->ReportError(FROM_HERE, "OnWindowDestroying()"); | 368 oracle_proxy_->ReportError(FROM_HERE, "OnWindowDestroying()"); |
| 344 } | 369 } |
| 345 | 370 |
| 346 void AuraWindowCaptureMachine::OnWindowAddedToRootWindow( | 371 void AuraWindowCaptureMachine::OnWindowAddedToRootWindow( |
| 347 aura::Window* window) { | 372 aura::Window* window) { |
| 348 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 373 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 349 DCHECK(window == desktop_window_); | 374 DCHECK(window == desktop_window_); |
| 350 | 375 |
| 351 window->GetHost()->compositor()->AddObserver(this); | 376 if (aura::WindowTreeHost* host = window->GetHost()) { |
| 377 if (ui::Compositor* compositor = host->compositor()) | |
| 378 compositor->AddAnimationObserver(this); | |
| 379 } | |
| 352 } | 380 } |
| 353 | 381 |
| 354 void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow( | 382 void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow( |
| 355 aura::Window* window, | 383 aura::Window* window, |
| 356 aura::Window* new_root) { | 384 aura::Window* new_root) { |
| 357 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 385 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 358 DCHECK(window == desktop_window_); | 386 DCHECK(window == desktop_window_); |
| 359 | 387 |
| 360 window->GetHost()->compositor()->RemoveObserver(this); | 388 if (aura::WindowTreeHost* host = window->GetHost()) { |
| 389 if (ui::Compositor* compositor = host->compositor()) | |
| 390 compositor->RemoveAnimationObserver(this); | |
| 391 } | |
| 361 } | 392 } |
| 362 | 393 |
| 363 void AuraWindowCaptureMachine::OnCompositingEnded( | 394 void AuraWindowCaptureMachine::OnAnimationStep(base::TimeTicks timestamp) { |
| 395 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 396 DCHECK(!timestamp.is_null()); | |
| 397 | |
| 398 // HACK: The compositor invokes this observer method to step layer animation | |
| 399 // forward. Scheduling frame capture was not the intention, and so invoking | |
| 400 // this method does not actually indicate the content has changed. However, | |
| 401 // this is the only reliable way to ensure all screen changes are captured, as | |
| 402 // of this writing. | |
| 403 // http://crbug.com/600031 | |
| 404 // | |
| 405 // TODO(miu): Need a better observer callback interface from the compositor | |
| 406 // for this use case. The solution here will always capture frames at the | |
| 407 // maximum framerate, which means CPU/GPU is being wasted on redundant | |
| 408 // captures and quality/smoothness of animating content will suffer | |
| 409 // significantly. | |
| 410 // http://crbug.com/492839 | |
| 411 Capture(timestamp); | |
| 412 } | |
| 413 | |
| 414 void AuraWindowCaptureMachine::OnCompositingShuttingDown( | |
| 364 ui::Compositor* compositor) { | 415 ui::Compositor* compositor) { |
| 365 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 416 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 366 | 417 compositor->RemoveAnimationObserver(this); |
| 367 // TODO(miu): The CopyOutputRequest should be made earlier, at WillCommit(). | |
| 368 // http://crbug.com/492839 | |
| 369 BrowserThread::PostTask( | |
| 370 BrowserThread::UI, | |
| 371 FROM_HERE, | |
| 372 base::Bind(&AuraWindowCaptureMachine::Capture, weak_factory_.GetWeakPtr(), | |
| 373 true)); | |
| 374 } | 418 } |
| 375 | 419 |
| 376 } // namespace content | 420 } // namespace content |
| OLD | NEW |