Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: content/browser/renderer_host/media/web_contents_video_capture_device.cc

Issue 93583003: Reland 237634 and 237645. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase at 237726. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 // 43 //
44 // In the above example, both capturing and rendering *each* take almost the 44 // In the above example, both capturing and rendering *each* take almost the
45 // full 33 ms available between frames, yet we see that the required throughput 45 // full 33 ms available between frames, yet we see that the required throughput
46 // is obtained. 46 // is obtained.
47 // 47 //
48 // Turning on verbose logging will cause the effective frame rate to be logged 48 // Turning on verbose logging will cause the effective frame rate to be logged
49 // at 5-second intervals. 49 // at 5-second intervals.
50 50
51 #include "content/browser/renderer_host/media/web_contents_video_capture_device. h" 51 #include "content/browser/renderer_host/media/web_contents_video_capture_device. h"
52 52
53 #include <algorithm>
54 #include <list>
55 #include <string>
56
57 #include "base/basictypes.h" 53 #include "base/basictypes.h"
58 #include "base/bind.h" 54 #include "base/bind.h"
59 #include "base/callback_forward.h"
60 #include "base/callback_helpers.h" 55 #include "base/callback_helpers.h"
61 #include "base/debug/trace_event.h"
62 #include "base/logging.h" 56 #include "base/logging.h"
63 #include "base/memory/scoped_ptr.h" 57 #include "base/memory/scoped_ptr.h"
64 #include "base/memory/weak_ptr.h"
65 #include "base/message_loop/message_loop_proxy.h" 58 #include "base/message_loop/message_loop_proxy.h"
66 #include "base/metrics/histogram.h" 59 #include "base/metrics/histogram.h"
67 #include "base/sequenced_task_runner.h" 60 #include "base/sequenced_task_runner.h"
68 #include "base/strings/stringprintf.h"
69 #include "base/synchronization/lock.h"
70 #include "base/threading/thread.h" 61 #include "base/threading/thread.h"
71 #include "base/threading/thread_checker.h" 62 #include "base/threading/thread_checker.h"
72 #include "base/time/time.h" 63 #include "base/time/time.h"
64 #include "content/browser/renderer_host/media/video_capture_device_impl.h"
73 #include "content/browser/renderer_host/media/video_capture_oracle.h" 65 #include "content/browser/renderer_host/media/video_capture_oracle.h"
74 #include "content/browser/renderer_host/media/web_contents_capture_util.h" 66 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
75 #include "content/browser/renderer_host/render_widget_host_impl.h" 67 #include "content/browser/renderer_host/render_widget_host_impl.h"
76 #include "content/browser/web_contents/web_contents_impl.h" 68 #include "content/browser/web_contents/web_contents_impl.h"
77 #include "content/port/browser/render_widget_host_view_frame_subscriber.h" 69 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
78 #include "content/port/browser/render_widget_host_view_port.h" 70 #include "content/port/browser/render_widget_host_view_port.h"
79 #include "content/public/browser/browser_thread.h" 71 #include "content/public/browser/browser_thread.h"
80 #include "content/public/browser/notification_source.h" 72 #include "content/public/browser/notification_source.h"
81 #include "content/public/browser/notification_types.h" 73 #include "content/public/browser/notification_types.h"
82 #include "content/public/browser/render_process_host.h"
83 #include "content/public/browser/render_view_host.h" 74 #include "content/public/browser/render_view_host.h"
84 #include "content/public/browser/render_widget_host_view.h" 75 #include "content/public/browser/render_widget_host_view.h"
85 #include "content/public/browser/web_contents.h"
86 #include "content/public/browser/web_contents_observer.h" 76 #include "content/public/browser/web_contents_observer.h"
87 #include "media/base/bind_to_loop.h"
88 #include "media/base/video_frame.h"
89 #include "media/base/video_util.h" 77 #include "media/base/video_util.h"
90 #include "media/base/yuv_convert.h"
91 #include "media/video/capture/video_capture_types.h" 78 #include "media/video/capture/video_capture_types.h"
92 #include "skia/ext/image_operations.h" 79 #include "skia/ext/image_operations.h"
93 #include "third_party/skia/include/core/SkBitmap.h" 80 #include "third_party/skia/include/core/SkBitmap.h"
94 #include "third_party/skia/include/core/SkColor.h" 81 #include "third_party/skia/include/core/SkColor.h"
95 #include "ui/gfx/rect.h"
96 #include "ui/gfx/skia_util.h"
97 82
98 namespace content { 83 namespace content {
99 84
100 namespace { 85 namespace {
101 86
102 const int kMinFrameWidth = 2;
103 const int kMinFrameHeight = 2;
104
105 // TODO(nick): Remove this once frame subscription is supported on Aura and
106 // Linux.
107 #if (defined(OS_WIN) || defined(OS_MACOSX)) || defined(USE_AURA)
108 const bool kAcceleratedSubscriberIsSupported = true;
109 #else
110 const bool kAcceleratedSubscriberIsSupported = false;
111 #endif
112
113 // Returns the nearest even integer closer to zero.
114 template<typename IntType>
115 IntType MakeEven(IntType x) {
116 return x & static_cast<IntType>(-2);
117 }
118
119 // Compute a letterbox region, aligned to even coordinates. 87 // Compute a letterbox region, aligned to even coordinates.
120 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, 88 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
121 const gfx::Size& content_size) { 89 const gfx::Size& content_size) {
122 90
123 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), 91 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size),
124 content_size); 92 content_size);
125 93
126 result.set_x(MakeEven(result.x())); 94 result.set_x(MakeEven(result.x()));
127 result.set_y(MakeEven(result.y())); 95 result.set_y(MakeEven(result.y()));
128 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); 96 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width())));
129 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); 97 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height())));
130 98
131 return result; 99 return result;
132 } 100 }
133 101
134 // Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps 102 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is
135 // the VideoCaptureOracle, which decides which frames to capture, and a 103 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback.
136 // VideoCaptureDevice::Client, which allocates and receives the captured 104 void InvokeCaptureFrameCallback(
137 // frames, in a lock to synchronize state between the two. 105 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
138 class ThreadSafeCaptureOracle 106 base::Time timestamp,
139 : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> { 107 bool frame_captured) {
140 public: 108 capture_frame_cb.Run(timestamp, frame_captured);
141 ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client, 109 }
142 scoped_ptr<VideoCaptureOracle> oracle,
143 const gfx::Size& capture_size,
144 int frame_rate);
145
146 bool ObserveEventAndDecideCapture(
147 VideoCaptureOracle::Event event,
148 base::Time event_time,
149 scoped_refptr<media::VideoFrame>* storage,
150 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback);
151
152 base::TimeDelta capture_period() const {
153 return oracle_->capture_period();
154 }
155
156 // Stop new captures from happening (but doesn't forget the client).
157 void Stop();
158
159 // Signal an error to the client.
160 void ReportError();
161
162 private:
163 friend class base::RefCountedThreadSafe<ThreadSafeCaptureOracle>;
164 virtual ~ThreadSafeCaptureOracle() {}
165
166 // Callback invoked on completion of all captures.
167 void DidCaptureFrame(
168 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer,
169 int frame_number,
170 base::Time timestamp,
171 bool success);
172 // Protects everything below it.
173 base::Lock lock_;
174
175 // Recipient of our capture activity.
176 scoped_ptr<media::VideoCaptureDevice::Client> client_;
177
178 // Makes the decision to capture a frame.
179 const scoped_ptr<VideoCaptureOracle> oracle_;
180
181 // The current capturing resolution and frame rate.
182 const gfx::Size capture_size_;
183 const int frame_rate_;
184 };
185 110
186 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 111 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
187 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 112 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
188 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 113 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
189 public: 114 public:
190 FrameSubscriber(VideoCaptureOracle::Event event_type, 115 FrameSubscriber(VideoCaptureOracle::Event event_type,
191 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) 116 const scoped_refptr<ThreadSafeCaptureOracle>& oracle)
192 : event_type_(event_type), 117 : event_type_(event_type),
193 oracle_proxy_(oracle) {} 118 oracle_proxy_(oracle) {}
194 119
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 const scoped_refptr<media::VideoFrame>& output, 193 const scoped_refptr<media::VideoFrame>& output,
269 const base::Callback<void(bool)>& done_cb); 194 const base::Callback<void(bool)>& done_cb);
270 195
271 // Keeps track of the RenderView to be sourced, and executes copying of the 196 // Keeps track of the RenderView to be sourced, and executes copying of the
272 // backing store on the UI BrowserThread. 197 // backing store on the UI BrowserThread.
273 // 198 //
274 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its 199 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its
275 // implementation is currently asynchronous -- in our case, the "rvh changed" 200 // implementation is currently asynchronous -- in our case, the "rvh changed"
276 // notification would get posted back to the UI thread and processed later, and 201 // notification would get posted back to the UI thread and processed later, and
277 // this seems disadvantageous. 202 // this seems disadvantageous.
278 class CaptureMachine : public WebContentsObserver, 203 class WebContentsCaptureMachine
279 public base::SupportsWeakPtr<CaptureMachine> { 204 : public VideoCaptureMachine,
205 public WebContentsObserver,
206 public base::SupportsWeakPtr<WebContentsCaptureMachine> {
280 public: 207 public:
281 virtual ~CaptureMachine(); 208 WebContentsCaptureMachine(int render_process_id, int render_view_id);
209 virtual ~WebContentsCaptureMachine();
282 210
283 // Creates a CaptureMachine. Must be run on the UI BrowserThread. Returns 211 // VideoCaptureMachine overrides.
284 // NULL if the indicated render view cannot be found. 212 virtual bool Start(
285 static scoped_ptr<CaptureMachine> Create( 213 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
286 int render_process_id, 214 virtual void Stop() OVERRIDE;
287 int render_view_id,
288 const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
289 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
290 215
291 // Starts a copy from the backing store or the composited surface. Must be run 216 // Starts a copy from the backing store or the composited surface. Must be run
292 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation 217 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
293 // completes. The copy will occur to |target|. 218 // completes. The copy will occur to |target|.
294 // 219 //
295 // This may be used as a ContentCaptureSubscription::CaptureCallback. 220 // This may be used as a ContentCaptureSubscription::CaptureCallback.
296 void Capture( 221 void Capture(
297 const base::Time& start_time, 222 const base::Time& start_time,
298 const scoped_refptr<media::VideoFrame>& target, 223 const scoped_refptr<media::VideoFrame>& target,
299 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 224 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
(...skipping 21 matching lines...) Expand all
321 246
322 virtual void DidNavigateMainFrame( 247 virtual void DidNavigateMainFrame(
323 const LoadCommittedDetails& details, 248 const LoadCommittedDetails& details,
324 const FrameNavigateParams& params) OVERRIDE { 249 const FrameNavigateParams& params) OVERRIDE {
325 RenewFrameSubscription(); 250 RenewFrameSubscription();
326 } 251 }
327 252
328 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; 253 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
329 254
330 private: 255 private:
331 CaptureMachine(
332 const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
333 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
334
335 // Starts observing the web contents, returning false if lookup fails. 256 // Starts observing the web contents, returning false if lookup fails.
336 bool StartObservingWebContents(int initial_render_process_id, 257 bool StartObservingWebContents();
337 int initial_render_view_id);
338 258
339 // Helper function to determine the view that we are currently tracking. 259 // Helper function to determine the view that we are currently tracking.
340 RenderWidgetHost* GetTarget(); 260 RenderWidgetHost* GetTarget();
341 261
342 // Response callback for RenderWidgetHost::CopyFromBackingStore(). 262 // Response callback for RenderWidgetHost::CopyFromBackingStore().
343 void DidCopyFromBackingStore( 263 void DidCopyFromBackingStore(
344 const base::Time& start_time, 264 const base::Time& start_time,
345 const scoped_refptr<media::VideoFrame>& target, 265 const scoped_refptr<media::VideoFrame>& target,
346 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 266 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
347 deliver_frame_cb, 267 deliver_frame_cb,
348 bool success, 268 bool success,
349 const SkBitmap& bitmap); 269 const SkBitmap& bitmap);
350 270
351 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame(). 271 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
352 void DidCopyFromCompositingSurfaceToVideoFrame( 272 void DidCopyFromCompositingSurfaceToVideoFrame(
353 const base::Time& start_time, 273 const base::Time& start_time,
354 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 274 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
355 deliver_frame_cb, 275 deliver_frame_cb,
356 bool success); 276 bool success);
357 277
358 // Remove the old subscription, and start a new one. This should be called 278 // Remove the old subscription, and start a new one. This should be called
359 // after any change to the WebContents that affects the RenderWidgetHost or 279 // after any change to the WebContents that affects the RenderWidgetHost or
360 // attached views. 280 // attached views.
361 void RenewFrameSubscription(); 281 void RenewFrameSubscription();
362 282
363 // The task runner of the thread on which SkBitmap->VideoFrame conversion will 283 // Parameters saved in constructor.
284 const int initial_render_process_id_;
285 const int initial_render_view_id_;
286
287 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
364 // occur. Only used when this activity cannot be done on the GPU. 288 // occur. Only used when this activity cannot be done on the GPU.
365 const scoped_refptr<base::SequencedTaskRunner> render_task_runner_; 289 base::Thread render_thread_;
366 290
367 // Makes all the decisions about which frames to copy, and how. 291 // Makes all the decisions about which frames to copy, and how.
368 const scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 292 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
369 293
370 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE 294 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
371 // otherwise. 295 // otherwise.
372 int fullscreen_widget_id_; 296 int fullscreen_widget_id_;
373 297
374 // Last known RenderView size. 298 // Last known RenderView size.
375 gfx::Size last_view_size_; 299 gfx::Size last_view_size_;
376 300
377 // Responsible for forwarding events from the active RenderWidgetHost to the 301 // Responsible for forwarding events from the active RenderWidgetHost to the
378 // oracle, and initiating captures accordingly. 302 // oracle, and initiating captures accordingly.
379 scoped_ptr<ContentCaptureSubscription> subscription_; 303 scoped_ptr<ContentCaptureSubscription> subscription_;
380 304
381 DISALLOW_COPY_AND_ASSIGN(CaptureMachine); 305 DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureMachine);
382 }; 306 };
383 307
384 // Responsible for logging the effective frame rate. 308 // Responsible for logging the effective frame rate.
385 // TODO(nick): Make this compatible with the push model and hook it back up. 309 // TODO(nick): Make this compatible with the push model and hook it back up.
386 class VideoFrameDeliveryLog { 310 class VideoFrameDeliveryLog {
387 public: 311 public:
388 VideoFrameDeliveryLog(); 312 VideoFrameDeliveryLog();
389 313
390 // Treat |frame_number| as having been delivered, and update the 314 // Treat |frame_number| as having been delivered, and update the
391 // frame rate statistics accordingly. 315 // frame rate statistics accordingly.
392 void ChronicleFrameDelivery(int frame_number); 316 void ChronicleFrameDelivery(int frame_number);
393 317
394 private: 318 private:
395 // The following keep track of and log the effective frame rate whenever 319 // The following keep track of and log the effective frame rate whenever
396 // verbose logging is turned on. 320 // verbose logging is turned on.
397 base::Time last_frame_rate_log_time_; 321 base::Time last_frame_rate_log_time_;
398 int count_frames_rendered_; 322 int count_frames_rendered_;
399 int last_frame_number_; 323 int last_frame_number_;
400 324
401 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); 325 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog);
402 }; 326 };
403 327
404 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
405 scoped_ptr<media::VideoCaptureDevice::Client> client,
406 scoped_ptr<VideoCaptureOracle> oracle,
407 const gfx::Size& capture_size,
408 int frame_rate)
409 : client_(client.Pass()),
410 oracle_(oracle.Pass()),
411 capture_size_(capture_size),
412 frame_rate_(frame_rate) {}
413
414 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
415 VideoCaptureOracle::Event event,
416 base::Time event_time,
417 scoped_refptr<media::VideoFrame>* storage,
418 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) {
419 base::AutoLock guard(lock_);
420
421 if (!client_)
422 return false; // Capture is stopped.
423
424 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer =
425 client_->ReserveOutputBuffer(media::VideoFrame::I420, capture_size_);
426 const bool should_capture =
427 oracle_->ObserveEventAndDecideCapture(event, event_time);
428 const bool content_is_dirty =
429 (event == VideoCaptureOracle::kCompositorUpdate ||
430 event == VideoCaptureOracle::kSoftwarePaint);
431 const char* event_name =
432 (event == VideoCaptureOracle::kTimerPoll ? "poll" :
433 (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" :
434 "paint"));
435
436 // Consider the various reasons not to initiate a capture.
437 if (should_capture && !output_buffer) {
438 TRACE_EVENT_INSTANT1("mirroring",
439 "EncodeLimited",
440 TRACE_EVENT_SCOPE_THREAD,
441 "trigger",
442 event_name);
443 return false;
444 } else if (!should_capture && output_buffer) {
445 if (content_is_dirty) {
446 // This is a normal and acceptable way to drop a frame. We've hit our
447 // capture rate limit: for example, the content is animating at 60fps but
448 // we're capturing at 30fps.
449 TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited",
450 TRACE_EVENT_SCOPE_THREAD,
451 "trigger", event_name);
452 }
453 return false;
454 } else if (!should_capture && !output_buffer) {
455 // We decided not to capture, but we wouldn't have been able to if we wanted
456 // to because no output buffer was available.
457 TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited",
458 TRACE_EVENT_SCOPE_THREAD,
459 "trigger", event_name);
460 return false;
461 }
462 int frame_number = oracle_->RecordCapture();
463 TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(),
464 "frame_number", frame_number,
465 "trigger", event_name);
466
467 *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame,
468 this,
469 output_buffer,
470 frame_number);
471 *storage = media::VideoFrame::WrapExternalPackedMemory(
472 media::VideoFrame::I420,
473 capture_size_,
474 gfx::Rect(capture_size_),
475 capture_size_,
476 static_cast<uint8*>(output_buffer->data()),
477 output_buffer->size(),
478 base::SharedMemory::NULLHandle(),
479 base::TimeDelta(),
480 base::Closure());
481 return true;
482 }
483
484 void ThreadSafeCaptureOracle::Stop() {
485 base::AutoLock guard(lock_);
486 client_.reset();
487 }
488
489 void ThreadSafeCaptureOracle::ReportError() {
490 base::AutoLock guard(lock_);
491 if (client_)
492 client_->OnError();
493 }
494
495 void ThreadSafeCaptureOracle::DidCaptureFrame(
496 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer,
497 int frame_number,
498 base::Time timestamp,
499 bool success) {
500 base::AutoLock guard(lock_);
501 TRACE_EVENT_ASYNC_END2("mirroring", "Capture", buffer.get(),
502 "success", success,
503 "timestamp", timestamp.ToInternalValue());
504
505 if (!client_)
506 return; // Capture is stopped.
507
508 if (success) {
509 if (oracle_->CompleteCapture(frame_number, timestamp)) {
510 client_->OnIncomingCapturedBuffer(buffer,
511 media::VideoFrame::I420,
512 capture_size_,
513 timestamp,
514 frame_rate_);
515 }
516 }
517 }
518
519 bool FrameSubscriber::ShouldCaptureFrame( 328 bool FrameSubscriber::ShouldCaptureFrame(
520 base::Time present_time, 329 base::Time present_time,
521 scoped_refptr<media::VideoFrame>* storage, 330 scoped_refptr<media::VideoFrame>* storage,
522 DeliverFrameCallback* deliver_frame_cb) { 331 DeliverFrameCallback* deliver_frame_cb) {
523 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", 332 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame",
524 "instance", this); 333 "instance", this);
525 334
526 return oracle_proxy_->ObserveEventAndDecideCapture(event_type_, present_time, 335 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
527 storage, deliver_frame_cb); 336 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
337 event_type_, present_time, storage, &capture_frame_cb);
338
339 *deliver_frame_cb = base::Bind(&InvokeCaptureFrameCallback, capture_frame_cb);
340 return oracle_decision;
528 } 341 }
529 342
530 ContentCaptureSubscription::ContentCaptureSubscription( 343 ContentCaptureSubscription::ContentCaptureSubscription(
531 const RenderWidgetHost& source, 344 const RenderWidgetHost& source,
532 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 345 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
533 const CaptureCallback& capture_callback) 346 const CaptureCallback& capture_callback)
534 : render_process_id_(source.GetProcess()->GetID()), 347 : render_process_id_(source.GetProcess()->GetID()),
535 render_view_id_(source.GetRoutingID()), 348 render_view_id_(source.GetRoutingID()),
536 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy), 349 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy),
537 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy), 350 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy),
538 capture_callback_(capture_callback), 351 capture_callback_(capture_callback),
539 timer_(true, true) { 352 timer_(true, true) {
540 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
541 354
542 RenderWidgetHostViewPort* view = 355 RenderWidgetHostViewPort* view =
543 RenderWidgetHostViewPort::FromRWHV(source.GetView()); 356 RenderWidgetHostViewPort::FromRWHV(source.GetView());
544 357
545 // Subscribe to accelerated presents. These will be serviced directly by the 358 // Subscribe to accelerated presents. These will be serviced directly by the
546 // oracle. 359 // oracle.
547 if (view && kAcceleratedSubscriberIsSupported) { 360 if (view && kAcceleratedSubscriberIsSupported) {
548 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 361 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
549 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, 362 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate,
550 oracle_proxy)); 363 oracle_proxy));
551 view->BeginFrameSubscription(subscriber.Pass()); 364 view->BeginFrameSubscription(subscriber.Pass());
552 } 365 }
553 366
554 // Subscribe to software paint events. This instance will service these by 367 // Subscribe to software paint events. This instance will service these by
555 // reflecting them back to the CaptureMachine via |capture_callback|. 368 // reflecting them back to the WebContentsCaptureMachine via
369 // |capture_callback|.
556 registrar_.Add( 370 registrar_.Add(
557 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, 371 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
558 Source<RenderWidgetHost>(&source)); 372 Source<RenderWidgetHost>(&source));
559 373
560 // Subscribe to timer events. This instance will service these as well. 374 // Subscribe to timer events. This instance will service these as well.
561 timer_.Start(FROM_HERE, oracle_proxy->capture_period(), 375 timer_.Start(FROM_HERE, oracle_proxy->capture_period(),
562 base::Bind(&ContentCaptureSubscription::OnTimer, 376 base::Bind(&ContentCaptureSubscription::OnTimer,
563 base::Unretained(this))); 377 base::Unretained(this)));
564 } 378 }
565 379
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 static_cast<int>(measured_fps)); 541 static_cast<int>(measured_fps));
728 VLOG(1) << "Current measured frame rate for " 542 VLOG(1) << "Current measured frame rate for "
729 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; 543 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS.";
730 last_frame_rate_log_time_ = now; 544 last_frame_rate_log_time_ = now;
731 count_frames_rendered_ = 0; 545 count_frames_rendered_ = 0;
732 last_frame_number_ = frame_number; 546 last_frame_number_ = frame_number;
733 } 547 }
734 } 548 }
735 } 549 }
736 550
737 // static 551 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
738 scoped_ptr<CaptureMachine> CaptureMachine::Create( 552 int render_view_id)
739 int render_process_id, 553 : initial_render_process_id_(render_process_id),
740 int render_view_id, 554 initial_render_view_id_(render_view_id),
741 const scoped_refptr<base::SequencedTaskRunner>& render_task_runner, 555 render_thread_("WebContentsVideo_RenderThread"),
556 fullscreen_widget_id_(MSG_ROUTING_NONE) {}
557
558 WebContentsCaptureMachine::~WebContentsCaptureMachine() {}
559
560 bool WebContentsCaptureMachine::Start(
742 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { 561 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
743 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
744 DCHECK(render_task_runner.get()); 563 DCHECK(!started_);
564
745 DCHECK(oracle_proxy.get()); 565 DCHECK(oracle_proxy.get());
746 scoped_ptr<CaptureMachine> machine( 566 oracle_proxy_ = oracle_proxy;
747 new CaptureMachine(render_task_runner, oracle_proxy));
748 567
749 if (!machine->StartObservingWebContents(render_process_id, render_view_id)) 568 if (!render_thread_.Start()) {
750 machine.reset(); 569 DVLOG(1) << "Failed to spawn render thread.";
570 return false;
571 }
751 572
752 return machine.Pass(); 573 if (!StartObservingWebContents())
574 return false;
575
576 started_ = true;
577 return true;
753 } 578 }
754 579
755 CaptureMachine::CaptureMachine( 580 void WebContentsCaptureMachine::Stop() {
756 const scoped_refptr<base::SequencedTaskRunner>& render_task_runner, 581 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
757 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy)
758 : render_task_runner_(render_task_runner),
759 oracle_proxy_(oracle_proxy),
760 fullscreen_widget_id_(MSG_ROUTING_NONE) {}
761
762 CaptureMachine::~CaptureMachine() {
763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
764 !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
765
766 // Stop observing the web contents.
767 subscription_.reset(); 582 subscription_.reset();
768 if (web_contents()) { 583 if (web_contents()) {
769 web_contents()->DecrementCapturerCount(); 584 web_contents()->DecrementCapturerCount();
770 Observe(NULL); 585 Observe(NULL);
771 } 586 }
587 render_thread_.Stop();
588 started_ = false;
772 } 589 }
773 590
774 void CaptureMachine::Capture( 591 void WebContentsCaptureMachine::Capture(
775 const base::Time& start_time, 592 const base::Time& start_time,
776 const scoped_refptr<media::VideoFrame>& target, 593 const scoped_refptr<media::VideoFrame>& target,
777 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 594 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
778 deliver_frame_cb) { 595 deliver_frame_cb) {
779 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
780 597
781 RenderWidgetHost* rwh = GetTarget(); 598 RenderWidgetHost* rwh = GetTarget();
782 RenderWidgetHostViewPort* view = 599 RenderWidgetHostViewPort* view =
783 rwh ? RenderWidgetHostViewPort::FromRWHV(rwh->GetView()) : NULL; 600 rwh ? RenderWidgetHostViewPort::FromRWHV(rwh->GetView()) : NULL;
784 if (!view || !rwh) { 601 if (!view || !rwh) {
(...skipping 14 matching lines...) Expand all
799 UMA_HISTOGRAM_COUNTS_10000( 616 UMA_HISTOGRAM_COUNTS_10000(
800 "TabCapture.ViewChangeKiloPixels", 617 "TabCapture.ViewChangeKiloPixels",
801 view_size.width() * view_size.height() / 1024); 618 view_size.width() * view_size.height() / 1024);
802 } 619 }
803 620
804 if (!view->IsSurfaceAvailableForCopy()) { 621 if (!view->IsSurfaceAvailableForCopy()) {
805 // Fallback to the more expensive renderer-side copy if the surface and 622 // Fallback to the more expensive renderer-side copy if the surface and
806 // backing store are not accessible. 623 // backing store are not accessible.
807 rwh->GetSnapshotFromRenderer( 624 rwh->GetSnapshotFromRenderer(
808 gfx::Rect(), 625 gfx::Rect(),
809 base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(), 626 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore,
810 start_time, target, deliver_frame_cb)); 627 this->AsWeakPtr(), start_time, target, deliver_frame_cb));
811 } else if (view->CanCopyToVideoFrame()) { 628 } else if (view->CanCopyToVideoFrame()) {
812 view->CopyFromCompositingSurfaceToVideoFrame( 629 view->CopyFromCompositingSurfaceToVideoFrame(
813 gfx::Rect(view_size), 630 gfx::Rect(view_size),
814 target, 631 target,
815 base::Bind(&CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame, 632 base::Bind(&WebContentsCaptureMachine::
633 DidCopyFromCompositingSurfaceToVideoFrame,
816 this->AsWeakPtr(), start_time, deliver_frame_cb)); 634 this->AsWeakPtr(), start_time, deliver_frame_cb));
817 } else { 635 } else {
818 rwh->CopyFromBackingStore( 636 rwh->CopyFromBackingStore(
819 gfx::Rect(), 637 gfx::Rect(),
820 fitted_size, // Size here is a request not always honored. 638 fitted_size, // Size here is a request not always honored.
821 base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(), 639 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore,
822 start_time, target, deliver_frame_cb)); 640 this->AsWeakPtr(), start_time, target, deliver_frame_cb));
823 } 641 }
824 } 642 }
825 643
826 bool CaptureMachine::StartObservingWebContents(int initial_render_process_id, 644 bool WebContentsCaptureMachine::StartObservingWebContents() {
827 int initial_render_view_id) {
828 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
829
830 // Look-up the RenderViewHost and, from that, the WebContents that wraps it. 645 // Look-up the RenderViewHost and, from that, the WebContents that wraps it.
831 // If successful, begin observing the WebContents instance. 646 // If successful, begin observing the WebContents instance.
832 // 647 //
833 // Why this can be unsuccessful: The request for mirroring originates in a 648 // Why this can be unsuccessful: The request for mirroring originates in a
834 // render process, and this request is based on the current RenderView 649 // render process, and this request is based on the current RenderView
835 // associated with a tab. However, by the time we get up-and-running here, 650 // associated with a tab. However, by the time we get up-and-running here,
836 // there have been multiple back-and-forth IPCs between processes, as well as 651 // there have been multiple back-and-forth IPCs between processes, as well as
837 // a bit of indirection across threads. It's easily possible that, in the 652 // a bit of indirection across threads. It's easily possible that, in the
838 // meantime, the original RenderView may have gone away. 653 // meantime, the original RenderView may have gone away.
839 RenderViewHost* const rvh = 654 RenderViewHost* const rvh =
840 RenderViewHost::FromID(initial_render_process_id, 655 RenderViewHost::FromID(initial_render_process_id_,
841 initial_render_view_id); 656 initial_render_view_id_);
842 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID(" 657 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
843 << initial_render_process_id << ", " 658 << initial_render_process_id_ << ", "
844 << initial_render_view_id << ") returned NULL."; 659 << initial_render_view_id_ << ") returned NULL.";
845 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); 660 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
846 661
847 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); 662 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
848 if (contents) { 663 if (contents) {
849 contents->IncrementCapturerCount(); 664 contents->IncrementCapturerCount();
850 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); 665 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID();
851 RenewFrameSubscription(); 666 RenewFrameSubscription();
852 return true; 667 return true;
853 } 668 }
854 669
855 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; 670 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL.";
856 return false; 671 return false;
857 } 672 }
858 673
859 void CaptureMachine::WebContentsDestroyed(WebContents* web_contents) { 674 void WebContentsCaptureMachine::WebContentsDestroyed(
675 WebContents* web_contents) {
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 676 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
861 677
862 subscription_.reset(); 678 subscription_.reset();
863 web_contents->DecrementCapturerCount(); 679 web_contents->DecrementCapturerCount();
864 oracle_proxy_->ReportError(); 680 oracle_proxy_->ReportError();
865 } 681 }
866 682
867 RenderWidgetHost* CaptureMachine::GetTarget() { 683 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() {
868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 684 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
869 if (!web_contents()) 685 if (!web_contents())
870 return NULL; 686 return NULL;
871 687
872 RenderWidgetHost* rwh = NULL; 688 RenderWidgetHost* rwh = NULL;
873 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { 689 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) {
874 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); 690 RenderProcessHost* process = web_contents()->GetRenderProcessHost();
875 if (process) 691 if (process)
876 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_); 692 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_);
877 } else { 693 } else {
878 rwh = web_contents()->GetRenderViewHost(); 694 rwh = web_contents()->GetRenderViewHost();
879 } 695 }
880 696
881 return rwh; 697 return rwh;
882 } 698 }
883 699
884 void CaptureMachine::DidCopyFromBackingStore( 700 void WebContentsCaptureMachine::DidCopyFromBackingStore(
885 const base::Time& start_time, 701 const base::Time& start_time,
886 const scoped_refptr<media::VideoFrame>& target, 702 const scoped_refptr<media::VideoFrame>& target,
887 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 703 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
888 deliver_frame_cb, 704 deliver_frame_cb,
889 bool success, 705 bool success,
890 const SkBitmap& bitmap) { 706 const SkBitmap& bitmap) {
891 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 707 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
892 708
893 base::Time now = base::Time::Now(); 709 base::Time now = base::Time::Now();
894 if (success) { 710 if (success) {
895 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 711 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
896 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), 712 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
897 "Render"); 713 "Render");
898 render_task_runner_->PostTask(FROM_HERE, base::Bind( 714 render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
899 &RenderVideoFrame, bitmap, target, 715 &RenderVideoFrame, bitmap, target,
900 base::Bind(deliver_frame_cb, start_time))); 716 base::Bind(deliver_frame_cb, start_time)));
901 } else { 717 } else {
902 // Capture can fail due to transient issues, so just skip this frame. 718 // Capture can fail due to transient issues, so just skip this frame.
903 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 719 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
904 deliver_frame_cb.Run(start_time, false); 720 deliver_frame_cb.Run(start_time, false);
905 } 721 }
906 } 722 }
907 723
908 void CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 724 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
909 const base::Time& start_time, 725 const base::Time& start_time,
910 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 726 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
911 deliver_frame_cb, 727 deliver_frame_cb,
912 bool success) { 728 bool success) {
913 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 729 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
914 base::Time now = base::Time::Now(); 730 base::Time now = base::Time::Now();
915 731
916 if (success) { 732 if (success) {
917 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 733 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
918 } else { 734 } else {
919 // Capture can fail due to transient issues, so just skip this frame. 735 // Capture can fail due to transient issues, so just skip this frame.
920 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 736 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
921 } 737 }
922 deliver_frame_cb.Run(start_time, success); 738 deliver_frame_cb.Run(start_time, success);
923 } 739 }
924 740
925 void CaptureMachine::RenewFrameSubscription() { 741 void WebContentsCaptureMachine::RenewFrameSubscription() {
926 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 742 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
927 743
928 // Always destroy the old subscription before creating a new one. 744 // Always destroy the old subscription before creating a new one.
929 subscription_.reset(); 745 subscription_.reset();
930 746
931 RenderWidgetHost* rwh = GetTarget(); 747 RenderWidgetHost* rwh = GetTarget();
932 if (!rwh || !rwh->GetView()) 748 if (!rwh || !rwh->GetView())
933 return; 749 return;
934 750
935 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, 751 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
936 base::Bind(&CaptureMachine::Capture, this->AsWeakPtr()))); 752 base::Bind(&WebContentsCaptureMachine::Capture, this->AsWeakPtr())));
937 }
938
939 void DeleteCaptureMachineOnUIThread(
940 scoped_ptr<CaptureMachine> capture_machine) {
941 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
942 capture_machine.reset();
943 } 753 }
944 754
945 } // namespace 755 } // namespace
946 756
947 // The "meat" of the video capture implementation, which is a ref-counted class.
948 // Separating this from the "shell class" WebContentsVideoCaptureDevice allows
949 // safe destruction without needing to block any threads (e.g., the IO
950 // BrowserThread).
951 //
952 // WebContentsVideoCaptureDevice::Impl manages a simple state machine and the
953 // pipeline (see notes at top of this file). It times the start of successive
954 // captures and facilitates the processing of each through the stages of the
955 // pipeline.
956 class WebContentsVideoCaptureDevice::Impl : public base::SupportsWeakPtr<Impl> {
957 public:
958
959 Impl(int render_process_id, int render_view_id);
960 virtual ~Impl();
961
962 // Asynchronous requests to change WebContentsVideoCaptureDevice::Impl state.
963 void AllocateAndStart(const media::VideoCaptureParams& params,
964 scoped_ptr<media::VideoCaptureDevice::Client> client);
965 void StopAndDeAllocate();
966
967 private:
968
969 // Flag indicating current state.
970 enum State {
971 kIdle,
972 kCapturing,
973 kError
974 };
975
976 void TransitionStateTo(State next_state);
977
978 // Stops capturing and notifies client_ of an error state.
979 void Error();
980
981 // Called in response to CaptureMachine::Create that runs on the UI thread.
982 // It will assign the capture machine to the Impl class if it still exists
983 // otherwise it will post a task to delete CaptureMachine on the UI thread.
984 static void AssignCaptureMachine(
985 base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
986 scoped_ptr<CaptureMachine> capture_machine);
987
988 // Tracks that all activity occurs on the media stream manager's thread.
989 base::ThreadChecker thread_checker_;
990
991 // These values identify the starting view that will be captured. After
992 // capture starts, the target view IDs will change as navigation occurs, and
993 // so these values are not relevant after the initial bootstrapping.
994 const int initial_render_process_id_;
995 const int initial_render_view_id_;
996
997 // Current lifecycle state.
998 State state_;
999
1000 // A dedicated worker thread for doing image operations. Started/joined here,
1001 // but used by the CaptureMachine.
1002 base::Thread render_thread_;
1003
1004 // Tracks the CaptureMachine that's doing work on our behalf on the UI thread.
1005 // This value should never be dereferenced by this class, other than to
1006 // create and destroy it on the UI thread.
1007 scoped_ptr<CaptureMachine> capture_machine_;
1008
1009 // Our thread-safe capture oracle which serves as the gateway to the video
1010 // capture pipeline. Besides the WCVCD itself, it is the only component of the
1011 // system with direct access to |client_|.
1012 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
1013
1014 DISALLOW_COPY_AND_ASSIGN(Impl);
1015 };
1016
1017 WebContentsVideoCaptureDevice::Impl::Impl(int render_process_id,
1018 int render_view_id)
1019 : initial_render_process_id_(render_process_id),
1020 initial_render_view_id_(render_view_id),
1021 state_(kIdle),
1022 render_thread_("WebContentsVideo_RenderThread") {}
1023
1024 void WebContentsVideoCaptureDevice::Impl::AllocateAndStart(
1025 const media::VideoCaptureParams& params,
1026 scoped_ptr<VideoCaptureDevice::Client> client) {
1027 DCHECK(thread_checker_.CalledOnValidThread());
1028
1029 if (state_ != kIdle) {
1030 DVLOG(1) << "Allocate() invoked when not in state Idle.";
1031 return;
1032 }
1033
1034 if (params.requested_format.frame_rate <= 0) {
1035 DVLOG(1) << "invalid frame_rate: " << params.requested_format.frame_rate;
1036 client->OnError();
1037 return;
1038 }
1039
1040 if (!render_thread_.Start()) {
1041 DVLOG(1) << "Failed to spawn render thread.";
1042 client->OnError();
1043 return;
1044 }
1045
1046 // Frame dimensions must each be a positive, even integer, since the client
1047 // wants (or will convert to) YUV420.
1048 gfx::Size frame_size(MakeEven(params.requested_format.frame_size.width()),
1049 MakeEven(params.requested_format.frame_size.height()));
1050 if (frame_size.width() < kMinFrameWidth ||
1051 frame_size.height() < kMinFrameHeight) {
1052 DVLOG(1) << "invalid frame size: " << frame_size.ToString();
1053 client->OnError();
1054 return;
1055 }
1056
1057 base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds(
1058 1000000.0 / params.requested_format.frame_rate + 0.5);
1059
1060 scoped_ptr<VideoCaptureOracle> oracle(
1061 new VideoCaptureOracle(capture_period,
1062 kAcceleratedSubscriberIsSupported));
1063 oracle_proxy_ =
1064 new ThreadSafeCaptureOracle(client.Pass(),
1065 oracle.Pass(),
1066 frame_size,
1067 params.requested_format.frame_rate);
1068
1069 // Allocates the CaptureMachine. The CaptureMachine will be tracking render
1070 // view swapping over its lifetime, and we don't want to lose our reference to
1071 // the current render view by starting over with the stale
1072 // |initial_render_view_id_|.
1073 DCHECK(!capture_machine_.get());
1074 BrowserThread::PostTaskAndReplyWithResult(
1075 BrowserThread::UI, FROM_HERE,
1076 base::Bind(&CaptureMachine::Create,
1077 initial_render_process_id_,
1078 initial_render_view_id_,
1079 render_thread_.message_loop_proxy(), oracle_proxy_),
1080 base::Bind(&Impl::AssignCaptureMachine, AsWeakPtr()));
1081
1082 TransitionStateTo(kCapturing);
1083 }
1084
1085 // static
1086 void WebContentsVideoCaptureDevice::Impl::AssignCaptureMachine(
1087 base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
1088 scoped_ptr<CaptureMachine> capture_machine) {
1089 DCHECK(!impl.get() || impl->thread_checker_.CalledOnValidThread());
1090
1091 if (!impl.get()) {
1092 // If WCVD::Impl was destroyed before we got back on it's thread and
1093 // capture_machine is not NULL, then we need to return to the UI thread to
1094 // safely cleanup the CaptureMachine.
1095 if (capture_machine) {
1096 BrowserThread::PostTask(
1097 BrowserThread::UI, FROM_HERE, base::Bind(
1098 &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine)));
1099 return;
1100 }
1101 } else if (!capture_machine) {
1102 impl->Error();
1103 } else {
1104 impl->capture_machine_ = capture_machine.Pass();
1105 }
1106 }
1107
1108 void WebContentsVideoCaptureDevice::Impl::StopAndDeAllocate() {
1109 DCHECK(thread_checker_.CalledOnValidThread());
1110
1111 if (state_ != kCapturing) {
1112 return;
1113 }
1114 oracle_proxy_->Stop();
1115 oracle_proxy_ = NULL;
1116 render_thread_.Stop();
1117
1118 TransitionStateTo(kIdle);
1119
1120 // There is still a capture pipeline running that is checking in with the
1121 // oracle, and processing captures that are already started in flight. That
1122 // pipeline must be shut down asynchronously, on the UI thread.
1123 if (capture_machine_) {
1124 // The task that is posted to the UI thread might not run if we are shutting
1125 // down, so we transfer ownership of CaptureMachine to the closure so that
1126 // it is still cleaned up when the closure is deleted.
1127 BrowserThread::PostTask(
1128 BrowserThread::UI, FROM_HERE, base::Bind(
1129 &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine_)));
1130 }
1131 }
1132
1133 WebContentsVideoCaptureDevice::Impl::~Impl() {
1134 DCHECK(!capture_machine_) << "Cleanup on UI thread did not happen.";
1135 DVLOG(1) << "WebContentsVideoCaptureDevice::Impl@" << this << " destroying.";
1136 }
1137
1138 void WebContentsVideoCaptureDevice::Impl::TransitionStateTo(State next_state) {
1139 DCHECK(thread_checker_.CalledOnValidThread());
1140
1141 #ifndef NDEBUG
1142 static const char* kStateNames[] = {
1143 "Idle", "Allocated", "Capturing", "Error"
1144 };
1145 DVLOG(1) << "State change: " << kStateNames[state_]
1146 << " --> " << kStateNames[next_state];
1147 #endif
1148
1149 state_ = next_state;
1150 }
1151
1152 void WebContentsVideoCaptureDevice::Impl::Error() {
1153 DCHECK(thread_checker_.CalledOnValidThread());
1154
1155 if (state_ == kIdle)
1156 return;
1157
1158 if (oracle_proxy_)
1159 oracle_proxy_->ReportError();
1160
1161 StopAndDeAllocate();
1162 TransitionStateTo(kError);
1163 }
1164
1165 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( 757 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
1166 int render_process_id, 758 int render_process_id, int render_view_id)
1167 int render_view_id) 759 : impl_(new VideoCaptureDeviceImpl(scoped_ptr<VideoCaptureMachine>(
1168 : impl_(new WebContentsVideoCaptureDevice::Impl(render_process_id, 760 new WebContentsCaptureMachine(render_process_id, render_view_id)))) {}
1169 render_view_id)) {}
1170 761
1171 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { 762 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
1172 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; 763 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying.";
1173 } 764 }
1174 765
1175 // static 766 // static
1176 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( 767 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create(
1177 const std::string& device_id) { 768 const std::string& device_id) {
1178 // Parse device_id into render_process_id and render_view_id. 769 // Parse device_id into render_process_id and render_view_id.
1179 int render_process_id = -1; 770 int render_process_id = -1;
(...skipping 11 matching lines...) Expand all
1191 scoped_ptr<Client> client) { 782 scoped_ptr<Client> client) {
1192 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 783 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
1193 impl_->AllocateAndStart(params, client.Pass()); 784 impl_->AllocateAndStart(params, client.Pass());
1194 } 785 }
1195 786
1196 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 787 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
1197 impl_->StopAndDeAllocate(); 788 impl_->StopAndDeAllocate();
1198 } 789 }
1199 790
1200 } // namespace content 791 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/media/web_contents_video_capture_device.h ('k') | content/content_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698