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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 } | 132 } |
133 | 133 |
134 // Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps | 134 // Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps |
135 // the VideoCaptureOracle, which decides which frames to capture, and a | 135 // the VideoCaptureOracle, which decides which frames to capture, and a |
136 // VideoCaptureDevice::Client, which allocates and receives the captured | 136 // VideoCaptureDevice::Client, which allocates and receives the captured |
137 // frames, in a lock to synchronize state between the two. | 137 // frames, in a lock to synchronize state between the two. |
138 class ThreadSafeCaptureOracle | 138 class ThreadSafeCaptureOracle |
139 : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> { | 139 : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> { |
140 public: | 140 public: |
141 ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client, | 141 ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client, |
142 scoped_ptr<VideoCaptureOracle> oracle); | 142 scoped_ptr<VideoCaptureOracle> oracle, |
| 143 const gfx::Size& capture_size); |
143 | 144 |
144 bool ObserveEventAndDecideCapture( | 145 bool ObserveEventAndDecideCapture( |
145 VideoCaptureOracle::Event event, | 146 VideoCaptureOracle::Event event, |
146 base::Time event_time, | 147 base::Time event_time, |
147 scoped_refptr<media::VideoFrame>* storage, | 148 scoped_refptr<media::VideoFrame>* storage, |
148 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback); | 149 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback); |
149 | 150 |
150 base::TimeDelta capture_period() const { | 151 base::TimeDelta capture_period() const { |
151 return oracle_->capture_period(); | 152 return oracle_->capture_period(); |
152 } | 153 } |
(...skipping 14 matching lines...) Expand all Loading... |
167 base::Time timestamp, | 168 base::Time timestamp, |
168 bool success); | 169 bool success); |
169 // Protects everything below it. | 170 // Protects everything below it. |
170 base::Lock lock_; | 171 base::Lock lock_; |
171 | 172 |
172 // Recipient of our capture activity. | 173 // Recipient of our capture activity. |
173 scoped_ptr<media::VideoCaptureDevice::Client> client_; | 174 scoped_ptr<media::VideoCaptureDevice::Client> client_; |
174 | 175 |
175 // Makes the decision to capture a frame. | 176 // Makes the decision to capture a frame. |
176 const scoped_ptr<VideoCaptureOracle> oracle_; | 177 const scoped_ptr<VideoCaptureOracle> oracle_; |
| 178 |
| 179 // The resolution at which we're capturing. |
| 180 const gfx::Size capture_size_; |
177 }; | 181 }; |
178 | 182 |
179 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible | 183 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible |
180 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. | 184 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. |
181 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { | 185 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
182 public: | 186 public: |
183 FrameSubscriber(VideoCaptureOracle::Event event_type, | 187 FrameSubscriber(VideoCaptureOracle::Event event_type, |
184 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) | 188 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) |
185 : event_type_(event_type), | 189 : event_type_(event_type), |
186 oracle_proxy_(oracle) {} | 190 oracle_proxy_(oracle) {} |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 // verbose logging is turned on. | 393 // verbose logging is turned on. |
390 base::Time last_frame_rate_log_time_; | 394 base::Time last_frame_rate_log_time_; |
391 int count_frames_rendered_; | 395 int count_frames_rendered_; |
392 int last_frame_number_; | 396 int last_frame_number_; |
393 | 397 |
394 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); | 398 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); |
395 }; | 399 }; |
396 | 400 |
397 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle( | 401 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle( |
398 scoped_ptr<media::VideoCaptureDevice::Client> client, | 402 scoped_ptr<media::VideoCaptureDevice::Client> client, |
399 scoped_ptr<VideoCaptureOracle> oracle) | 403 scoped_ptr<VideoCaptureOracle> oracle, |
400 : client_(client.Pass()), oracle_(oracle.Pass()) {} | 404 const gfx::Size& capture_size) |
| 405 : client_(client.Pass()), |
| 406 oracle_(oracle.Pass()), |
| 407 capture_size_(capture_size) { |
| 408 } |
401 | 409 |
402 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( | 410 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( |
403 VideoCaptureOracle::Event event, | 411 VideoCaptureOracle::Event event, |
404 base::Time event_time, | 412 base::Time event_time, |
405 scoped_refptr<media::VideoFrame>* storage, | 413 scoped_refptr<media::VideoFrame>* storage, |
406 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { | 414 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { |
407 base::AutoLock guard(lock_); | 415 base::AutoLock guard(lock_); |
408 | 416 |
409 if (!client_) | 417 if (!client_) |
410 return false; // Capture is stopped. | 418 return false; // Capture is stopped. |
411 | 419 |
412 scoped_refptr<media::VideoFrame> output_buffer = | 420 scoped_refptr<media::VideoFrame> output_buffer = |
413 client_->ReserveOutputBuffer(); | 421 client_->ReserveOutputBuffer(capture_size_); |
414 const bool should_capture = | 422 const bool should_capture = |
415 oracle_->ObserveEventAndDecideCapture(event, event_time); | 423 oracle_->ObserveEventAndDecideCapture(event, event_time); |
416 const bool content_is_dirty = | 424 const bool content_is_dirty = |
417 (event == VideoCaptureOracle::kCompositorUpdate || | 425 (event == VideoCaptureOracle::kCompositorUpdate || |
418 event == VideoCaptureOracle::kSoftwarePaint); | 426 event == VideoCaptureOracle::kSoftwarePaint); |
419 const char* event_name = | 427 const char* event_name = |
420 (event == VideoCaptureOracle::kTimerPoll ? "poll" : | 428 (event == VideoCaptureOracle::kTimerPoll ? "poll" : |
421 (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" : | 429 (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" : |
422 "paint")); | 430 "paint")); |
423 | 431 |
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 // wants (or will convert to) YUV420. | 1029 // wants (or will convert to) YUV420. |
1022 width = MakeEven(width); | 1030 width = MakeEven(width); |
1023 height = MakeEven(height); | 1031 height = MakeEven(height); |
1024 if (width < kMinFrameWidth || height < kMinFrameHeight) { | 1032 if (width < kMinFrameWidth || height < kMinFrameHeight) { |
1025 DVLOG(1) << "invalid width (" << width << ") and/or height (" | 1033 DVLOG(1) << "invalid width (" << width << ") and/or height (" |
1026 << height << ")"; | 1034 << height << ")"; |
1027 client->OnError(); | 1035 client->OnError(); |
1028 return; | 1036 return; |
1029 } | 1037 } |
1030 | 1038 |
1031 // Initialize capture settings which will be consistent for the | 1039 // Need to call OnFrameInfo just to set the frame rate. |
1032 // duration of the capture. | 1040 // TODO(nick): http://crbug.com/309907 The other parameters of this struct are |
| 1041 // ignored. Come up with a better way to communicate the frame rate. |
1033 media::VideoCaptureCapability settings; | 1042 media::VideoCaptureCapability settings; |
1034 | |
1035 settings.width = width; | |
1036 settings.height = height; | |
1037 settings.frame_rate = frame_rate; | 1043 settings.frame_rate = frame_rate; |
1038 // Note: the value of |settings.color| doesn't matter if we use only the | 1044 client->OnFrameInfo(settings); |
1039 // VideoFrame based methods on |client|. | |
1040 settings.color = media::PIXEL_FORMAT_I420; | |
1041 settings.expected_capture_delay = 0; | |
1042 settings.interlaced = false; | |
1043 | 1045 |
1044 base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds( | 1046 base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds( |
1045 1000000.0 / settings.frame_rate + 0.5); | 1047 1000000.0 / frame_rate + 0.5); |
1046 | 1048 |
1047 client->OnFrameInfo(settings); | |
1048 scoped_ptr<VideoCaptureOracle> oracle( | 1049 scoped_ptr<VideoCaptureOracle> oracle( |
1049 new VideoCaptureOracle(capture_period, | 1050 new VideoCaptureOracle(capture_period, |
1050 kAcceleratedSubscriberIsSupported)); | 1051 kAcceleratedSubscriberIsSupported)); |
1051 oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), oracle.Pass()); | 1052 oracle_proxy_ = new ThreadSafeCaptureOracle( |
| 1053 client.Pass(), oracle.Pass(), gfx::Size(width, height)); |
1052 | 1054 |
1053 // Allocates the CaptureMachine. The CaptureMachine will be tracking render | 1055 // Allocates the CaptureMachine. The CaptureMachine will be tracking render |
1054 // view swapping over its lifetime, and we don't want to lose our reference to | 1056 // view swapping over its lifetime, and we don't want to lose our reference to |
1055 // the current render view by starting over with the stale | 1057 // the current render view by starting over with the stale |
1056 // |initial_render_view_id_|. | 1058 // |initial_render_view_id_|. |
1057 DCHECK(!capture_machine_.get()); | 1059 DCHECK(!capture_machine_.get()); |
1058 BrowserThread::PostTaskAndReplyWithResult( | 1060 BrowserThread::PostTaskAndReplyWithResult( |
1059 BrowserThread::UI, FROM_HERE, | 1061 BrowserThread::UI, FROM_HERE, |
1060 base::Bind(&CaptureMachine::Create, | 1062 base::Bind(&CaptureMachine::Create, |
1061 initial_render_process_id_, | 1063 initial_render_process_id_, |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1179 capture_format.height, | 1181 capture_format.height, |
1180 capture_format.frame_rate, | 1182 capture_format.frame_rate, |
1181 client.Pass()); | 1183 client.Pass()); |
1182 } | 1184 } |
1183 | 1185 |
1184 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 1186 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
1185 impl_->StopAndDeAllocate(); | 1187 impl_->StopAndDeAllocate(); |
1186 } | 1188 } |
1187 | 1189 |
1188 } // namespace content | 1190 } // namespace content |
OLD | NEW |