Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // Implementation notes: This needs to work on a variety of hardware | 5 // Implementation notes: This needs to work on a variety of hardware |
| 6 // configurations where the speed of the CPU and GPU greatly affect overall | 6 // configurations where the speed of the CPU and GPU greatly affect overall |
| 7 // performance. Spanning several threads, the process of capturing has been | 7 // performance. Spanning several threads, the process of capturing has been |
| 8 // split up into four conceptual stages: | 8 // split up into four conceptual stages: |
| 9 // | 9 // |
| 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's | 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 156 void Stop(); | 156 void Stop(); |
| 157 | 157 |
| 158 // Signal an error to the client. | 158 // Signal an error to the client. |
| 159 void ReportError(); | 159 void ReportError(); |
| 160 | 160 |
| 161 private: | 161 private: |
| 162 friend class base::RefCountedThreadSafe<ThreadSafeCaptureOracle>; | 162 friend class base::RefCountedThreadSafe<ThreadSafeCaptureOracle>; |
| 163 virtual ~ThreadSafeCaptureOracle() {} | 163 virtual ~ThreadSafeCaptureOracle() {} |
| 164 | 164 |
| 165 // Callback invoked on completion of all captures. | 165 // Callback invoked on completion of all captures. |
| 166 void DidCaptureFrame(const scoped_refptr<media::VideoFrame>& frame, | 166 void DidCaptureFrame( |
| 167 int frame_number, | 167 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, |
| 168 base::Time timestamp, | 168 int frame_number, |
| 169 bool success); | 169 base::Time timestamp, |
| 170 bool success); | |
| 170 // Protects everything below it. | 171 // Protects everything below it. |
| 171 base::Lock lock_; | 172 base::Lock lock_; |
| 172 | 173 |
| 173 // Recipient of our capture activity. | 174 // Recipient of our capture activity. |
| 174 scoped_ptr<media::VideoCaptureDevice::Client> client_; | 175 scoped_ptr<media::VideoCaptureDevice::Client> client_; |
| 175 | 176 |
| 176 // Makes the decision to capture a frame. | 177 // Makes the decision to capture a frame. |
| 177 const scoped_ptr<VideoCaptureOracle> oracle_; | 178 const scoped_ptr<VideoCaptureOracle> oracle_; |
| 178 | 179 |
| 179 // The resolution at which we're capturing. | 180 // The resolution at which we're capturing. |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 410 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( | 411 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( |
| 411 VideoCaptureOracle::Event event, | 412 VideoCaptureOracle::Event event, |
| 412 base::Time event_time, | 413 base::Time event_time, |
| 413 scoped_refptr<media::VideoFrame>* storage, | 414 scoped_refptr<media::VideoFrame>* storage, |
| 414 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { | 415 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { |
| 415 base::AutoLock guard(lock_); | 416 base::AutoLock guard(lock_); |
| 416 | 417 |
| 417 if (!client_) | 418 if (!client_) |
| 418 return false; // Capture is stopped. | 419 return false; // Capture is stopped. |
| 419 | 420 |
| 420 scoped_refptr<media::VideoFrame> output_buffer = | 421 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer = |
| 421 client_->ReserveOutputBuffer(capture_size_); | 422 client_->ReserveOutputBuffer(media::VideoFrame::I420, capture_size_); |
| 422 const bool should_capture = | 423 const bool should_capture = |
| 423 oracle_->ObserveEventAndDecideCapture(event, event_time); | 424 oracle_->ObserveEventAndDecideCapture(event, event_time); |
| 424 const bool content_is_dirty = | 425 const bool content_is_dirty = |
| 425 (event == VideoCaptureOracle::kCompositorUpdate || | 426 (event == VideoCaptureOracle::kCompositorUpdate || |
| 426 event == VideoCaptureOracle::kSoftwarePaint); | 427 event == VideoCaptureOracle::kSoftwarePaint); |
| 427 const char* event_name = | 428 const char* event_name = |
| 428 (event == VideoCaptureOracle::kTimerPoll ? "poll" : | 429 (event == VideoCaptureOracle::kTimerPoll ? "poll" : |
| 429 (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" : | 430 (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" : |
| 430 "paint")); | 431 "paint")); |
| 431 | 432 |
| 432 // Consider the various reasons not to initiate a capture. | 433 // Consider the various reasons not to initiate a capture. |
| 433 if (should_capture && !output_buffer.get()) { | 434 if (should_capture && !output_buffer) { |
| 434 TRACE_EVENT_INSTANT1("mirroring", | 435 TRACE_EVENT_INSTANT1("mirroring", |
| 435 "EncodeLimited", | 436 "EncodeLimited", |
| 436 TRACE_EVENT_SCOPE_THREAD, | 437 TRACE_EVENT_SCOPE_THREAD, |
| 437 "trigger", | 438 "trigger", |
| 438 event_name); | 439 event_name); |
| 439 return false; | 440 return false; |
| 440 } else if (!should_capture && output_buffer.get()) { | 441 } else if (!should_capture && output_buffer) { |
| 441 if (content_is_dirty) { | 442 if (content_is_dirty) { |
| 442 // This is a normal and acceptable way to drop a frame. We've hit our | 443 // This is a normal and acceptable way to drop a frame. We've hit our |
| 443 // capture rate limit: for example, the content is animating at 60fps but | 444 // capture rate limit: for example, the content is animating at 60fps but |
| 444 // we're capturing at 30fps. | 445 // we're capturing at 30fps. |
| 445 TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited", | 446 TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited", |
| 446 TRACE_EVENT_SCOPE_THREAD, | 447 TRACE_EVENT_SCOPE_THREAD, |
| 447 "trigger", event_name); | 448 "trigger", event_name); |
| 448 } | 449 } |
| 449 return false; | 450 return false; |
| 450 } else if (!should_capture && !output_buffer.get()) { | 451 } else if (!should_capture && !output_buffer) { |
| 451 // We decided not to capture, but we wouldn't have been able to if we wanted | 452 // We decided not to capture, but we wouldn't have been able to if we wanted |
| 452 // to because no output buffer was available. | 453 // to because no output buffer was available. |
| 453 TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited", | 454 TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited", |
| 454 TRACE_EVENT_SCOPE_THREAD, | 455 TRACE_EVENT_SCOPE_THREAD, |
| 455 "trigger", event_name); | 456 "trigger", event_name); |
| 456 return false; | 457 return false; |
| 457 } | 458 } |
| 458 int frame_number = oracle_->RecordCapture(); | 459 int frame_number = oracle_->RecordCapture(); |
| 459 TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(), | 460 TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(), |
| 460 "frame_number", frame_number, | 461 "frame_number", frame_number, |
| 461 "trigger", event_name); | 462 "trigger", event_name); |
| 462 *storage = output_buffer; | 463 |
| 464 *storage = media::VideoFrame::WrapExternalPackedMemory( | |
| 465 media::VideoFrame::I420, | |
| 466 capture_size_, | |
| 467 gfx::Rect(capture_size_), | |
| 468 capture_size_, | |
| 469 static_cast<uint8*>(output_buffer->data()), | |
| 470 output_buffer->size(), | |
| 471 base::SharedMemory::NULLHandle(), | |
| 472 base::TimeDelta(), | |
| 473 base::Closure()); | |
| 463 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, | 474 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, |
| 464 this, output_buffer, frame_number); | 475 this, |
| 476 base::Passed(&output_buffer), | |
|
ncarter (slow)
2013/10/29 18:42:17
I think this ownership scheme will work today, but
sheu
2013/11/05 20:02:10
That actually blew this whole thing wide open. Lo
| |
| 477 frame_number); | |
| 465 return true; | 478 return true; |
| 466 } | 479 } |
| 467 | 480 |
| 468 void ThreadSafeCaptureOracle::Stop() { | 481 void ThreadSafeCaptureOracle::Stop() { |
| 469 base::AutoLock guard(lock_); | 482 base::AutoLock guard(lock_); |
| 470 client_.reset(); | 483 client_.reset(); |
| 471 } | 484 } |
| 472 | 485 |
| 473 void ThreadSafeCaptureOracle::ReportError() { | 486 void ThreadSafeCaptureOracle::ReportError() { |
| 474 base::AutoLock guard(lock_); | 487 base::AutoLock guard(lock_); |
| 475 if (client_) | 488 if (client_) |
| 476 client_->OnError(); | 489 client_->OnError(); |
| 477 } | 490 } |
| 478 | 491 |
| 479 void ThreadSafeCaptureOracle::DidCaptureFrame( | 492 void ThreadSafeCaptureOracle::DidCaptureFrame( |
| 480 const scoped_refptr<media::VideoFrame>& frame, | 493 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, |
| 481 int frame_number, | 494 int frame_number, |
| 482 base::Time timestamp, | 495 base::Time timestamp, |
| 483 bool success) { | 496 bool success) { |
| 484 base::AutoLock guard(lock_); | 497 base::AutoLock guard(lock_); |
| 485 TRACE_EVENT_ASYNC_END2("mirroring", "Capture", frame.get(), | 498 TRACE_EVENT_ASYNC_END2("mirroring", "Capture", buffer.get(), |
| 486 "success", success, | 499 "success", success, |
| 487 "timestamp", timestamp.ToInternalValue()); | 500 "timestamp", timestamp.ToInternalValue()); |
| 488 | 501 |
| 489 if (!client_) | 502 if (!client_) |
| 490 return; // Capture is stopped. | 503 return; // Capture is stopped. |
| 491 | 504 |
| 492 if (success) { | 505 if (success) { |
| 493 if (oracle_->CompleteCapture(frame_number, timestamp)) | 506 if (oracle_->CompleteCapture(frame_number, timestamp)) { |
| 494 client_->OnIncomingCapturedVideoFrame(frame, timestamp); | 507 client_->OnIncomingCapturedBuffer( |
| 508 buffer.Pass(), media::VideoFrame::I420, capture_size_, timestamp); | |
| 509 } | |
| 495 } | 510 } |
| 496 } | 511 } |
| 497 | 512 |
| 498 bool FrameSubscriber::ShouldCaptureFrame( | 513 bool FrameSubscriber::ShouldCaptureFrame( |
| 499 base::Time present_time, | 514 base::Time present_time, |
| 500 scoped_refptr<media::VideoFrame>* storage, | 515 scoped_refptr<media::VideoFrame>* storage, |
| 501 DeliverFrameCallback* deliver_frame_cb) { | 516 DeliverFrameCallback* deliver_frame_cb) { |
| 502 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", | 517 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", |
| 503 "instance", this); | 518 "instance", this); |
| 504 | 519 |
| (...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1182 capture_format.height, | 1197 capture_format.height, |
| 1183 capture_format.frame_rate, | 1198 capture_format.frame_rate, |
| 1184 client.Pass()); | 1199 client.Pass()); |
| 1185 } | 1200 } |
| 1186 | 1201 |
| 1187 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 1202 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 1188 impl_->StopAndDeAllocate(); | 1203 impl_->StopAndDeAllocate(); |
| 1189 } | 1204 } |
| 1190 | 1205 |
| 1191 } // namespace content | 1206 } // namespace content |
| OLD | NEW |