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

Unified 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, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/media/web_contents_video_capture_device.cc
diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device.cc b/content/browser/renderer_host/media/web_contents_video_capture_device.cc
index 5a5efc2f055f9be290a09d0a35c754a6b2e0251b..15258a04523cf7d9b8c9e31cdd7e818b793d1802 100644
--- a/content/browser/renderer_host/media/web_contents_video_capture_device.cc
+++ b/content/browser/renderer_host/media/web_contents_video_capture_device.cc
@@ -50,26 +50,18 @@
#include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
-#include <algorithm>
-#include <list>
-#include <string>
-
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/callback_forward.h"
#include "base/callback_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
+#include "content/browser/renderer_host/media/video_capture_device_impl.h"
#include "content/browser/renderer_host/media/video_capture_oracle.h"
#include "content/browser/renderer_host/media/web_contents_capture_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -79,43 +71,19 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
-#include "media/base/bind_to_loop.h"
-#include "media/base/video_frame.h"
#include "media/base/video_util.h"
-#include "media/base/yuv_convert.h"
#include "media/video/capture/video_capture_types.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/skia_util.h"
namespace content {
namespace {
-const int kMinFrameWidth = 2;
-const int kMinFrameHeight = 2;
-
-// TODO(nick): Remove this once frame subscription is supported on Aura and
-// Linux.
-#if (defined(OS_WIN) || defined(OS_MACOSX)) || defined(USE_AURA)
-const bool kAcceleratedSubscriberIsSupported = true;
-#else
-const bool kAcceleratedSubscriberIsSupported = false;
-#endif
-
-// Returns the nearest even integer closer to zero.
-template<typename IntType>
-IntType MakeEven(IntType x) {
- return x & static_cast<IntType>(-2);
-}
-
// Compute a letterbox region, aligned to even coordinates.
gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
const gfx::Size& content_size) {
@@ -131,57 +99,14 @@ gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
return result;
}
-// Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps
-// the VideoCaptureOracle, which decides which frames to capture, and a
-// VideoCaptureDevice::Client, which allocates and receives the captured
-// frames, in a lock to synchronize state between the two.
-class ThreadSafeCaptureOracle
- : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> {
- public:
- ThreadSafeCaptureOracle(scoped_ptr<media::VideoCaptureDevice::Client> client,
- scoped_ptr<VideoCaptureOracle> oracle,
- const gfx::Size& capture_size,
- int frame_rate);
-
- bool ObserveEventAndDecideCapture(
- VideoCaptureOracle::Event event,
- base::Time event_time,
- scoped_refptr<media::VideoFrame>* storage,
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback);
-
- base::TimeDelta capture_period() const {
- return oracle_->capture_period();
- }
-
- // Stop new captures from happening (but doesn't forget the client).
- void Stop();
-
- // Signal an error to the client.
- void ReportError();
-
- private:
- friend class base::RefCountedThreadSafe<ThreadSafeCaptureOracle>;
- virtual ~ThreadSafeCaptureOracle() {}
-
- // Callback invoked on completion of all captures.
- void DidCaptureFrame(
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer,
- int frame_number,
- base::Time timestamp,
- bool success);
- // Protects everything below it.
- base::Lock lock_;
-
- // Recipient of our capture activity.
- scoped_ptr<media::VideoCaptureDevice::Client> client_;
-
- // Makes the decision to capture a frame.
- const scoped_ptr<VideoCaptureOracle> oracle_;
-
- // The current capturing resolution and frame rate.
- const gfx::Size capture_size_;
- const int frame_rate_;
-};
+// Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is
+// compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback.
+void InvokeCaptureFrameCallback(
+ const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
+ base::Time timestamp,
+ bool frame_captured) {
+ capture_frame_cb.Run(timestamp, frame_captured);
+}
// FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
// with RenderWidgetHostViewFrameSubscriber. We create one per event type.
@@ -275,18 +200,18 @@ void RenderVideoFrame(const SkBitmap& input,
// implementation is currently asynchronous -- in our case, the "rvh changed"
// notification would get posted back to the UI thread and processed later, and
// this seems disadvantageous.
-class CaptureMachine : public WebContentsObserver,
- public base::SupportsWeakPtr<CaptureMachine> {
+class WebContentsCaptureMachine
+ : public VideoCaptureMachine,
+ public WebContentsObserver,
+ public base::SupportsWeakPtr<WebContentsCaptureMachine> {
public:
- virtual ~CaptureMachine();
+ WebContentsCaptureMachine(int render_process_id, int render_view_id);
+ virtual ~WebContentsCaptureMachine();
- // Creates a CaptureMachine. Must be run on the UI BrowserThread. Returns
- // NULL if the indicated render view cannot be found.
- static scoped_ptr<CaptureMachine> Create(
- int render_process_id,
- int render_view_id,
- const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
+ // VideoCaptureMachine overrides.
+ virtual bool Start(
+ const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
+ virtual void Stop() OVERRIDE;
// Starts a copy from the backing store or the composited surface. Must be run
// on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
@@ -328,13 +253,8 @@ class CaptureMachine : public WebContentsObserver,
virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
private:
- CaptureMachine(
- const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
-
// Starts observing the web contents, returning false if lookup fails.
- bool StartObservingWebContents(int initial_render_process_id,
- int initial_render_view_id);
+ bool StartObservingWebContents();
// Helper function to determine the view that we are currently tracking.
RenderWidgetHost* GetTarget();
@@ -360,12 +280,16 @@ class CaptureMachine : public WebContentsObserver,
// attached views.
void RenewFrameSubscription();
- // The task runner of the thread on which SkBitmap->VideoFrame conversion will
+ // Parameters saved in constructor.
+ const int initial_render_process_id_;
+ const int initial_render_view_id_;
+
+ // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
// occur. Only used when this activity cannot be done on the GPU.
- const scoped_refptr<base::SequencedTaskRunner> render_task_runner_;
+ base::Thread render_thread_;
// Makes all the decisions about which frames to copy, and how.
- const scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
+ scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
// Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
// otherwise.
@@ -378,7 +302,7 @@ class CaptureMachine : public WebContentsObserver,
// oracle, and initiating captures accordingly.
scoped_ptr<ContentCaptureSubscription> subscription_;
- DISALLOW_COPY_AND_ASSIGN(CaptureMachine);
+ DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureMachine);
};
// Responsible for logging the effective frame rate.
@@ -401,121 +325,6 @@ class VideoFrameDeliveryLog {
DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog);
};
-ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
- scoped_ptr<media::VideoCaptureDevice::Client> client,
- scoped_ptr<VideoCaptureOracle> oracle,
- const gfx::Size& capture_size,
- int frame_rate)
- : client_(client.Pass()),
- oracle_(oracle.Pass()),
- capture_size_(capture_size),
- frame_rate_(frame_rate) {}
-
-bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
- VideoCaptureOracle::Event event,
- base::Time event_time,
- scoped_refptr<media::VideoFrame>* storage,
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) {
- base::AutoLock guard(lock_);
-
- if (!client_)
- return false; // Capture is stopped.
-
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer =
- client_->ReserveOutputBuffer(media::VideoFrame::I420, capture_size_);
- const bool should_capture =
- oracle_->ObserveEventAndDecideCapture(event, event_time);
- const bool content_is_dirty =
- (event == VideoCaptureOracle::kCompositorUpdate ||
- event == VideoCaptureOracle::kSoftwarePaint);
- const char* event_name =
- (event == VideoCaptureOracle::kTimerPoll ? "poll" :
- (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" :
- "paint"));
-
- // Consider the various reasons not to initiate a capture.
- if (should_capture && !output_buffer) {
- TRACE_EVENT_INSTANT1("mirroring",
- "EncodeLimited",
- TRACE_EVENT_SCOPE_THREAD,
- "trigger",
- event_name);
- return false;
- } else if (!should_capture && output_buffer) {
- if (content_is_dirty) {
- // This is a normal and acceptable way to drop a frame. We've hit our
- // capture rate limit: for example, the content is animating at 60fps but
- // we're capturing at 30fps.
- TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited",
- TRACE_EVENT_SCOPE_THREAD,
- "trigger", event_name);
- }
- return false;
- } else if (!should_capture && !output_buffer) {
- // We decided not to capture, but we wouldn't have been able to if we wanted
- // to because no output buffer was available.
- TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited",
- TRACE_EVENT_SCOPE_THREAD,
- "trigger", event_name);
- return false;
- }
- int frame_number = oracle_->RecordCapture();
- TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(),
- "frame_number", frame_number,
- "trigger", event_name);
-
- *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame,
- this,
- output_buffer,
- frame_number);
- *storage = media::VideoFrame::WrapExternalPackedMemory(
- media::VideoFrame::I420,
- capture_size_,
- gfx::Rect(capture_size_),
- capture_size_,
- static_cast<uint8*>(output_buffer->data()),
- output_buffer->size(),
- base::SharedMemory::NULLHandle(),
- base::TimeDelta(),
- base::Closure());
- return true;
-}
-
-void ThreadSafeCaptureOracle::Stop() {
- base::AutoLock guard(lock_);
- client_.reset();
-}
-
-void ThreadSafeCaptureOracle::ReportError() {
- base::AutoLock guard(lock_);
- if (client_)
- client_->OnError();
-}
-
-void ThreadSafeCaptureOracle::DidCaptureFrame(
- scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer,
- int frame_number,
- base::Time timestamp,
- bool success) {
- base::AutoLock guard(lock_);
- TRACE_EVENT_ASYNC_END2("mirroring", "Capture", buffer.get(),
- "success", success,
- "timestamp", timestamp.ToInternalValue());
-
- if (!client_)
- return; // Capture is stopped.
-
- if (success) {
- if (oracle_->CompleteCapture(frame_number, timestamp)) {
- client_->OnIncomingCapturedBuffer(buffer,
- media::VideoFrame::I420,
- capture_size_,
- timestamp,
- frame_rate_);
- }
- }
-}
-
bool FrameSubscriber::ShouldCaptureFrame(
base::Time present_time,
scoped_refptr<media::VideoFrame>* storage,
@@ -523,8 +332,12 @@ bool FrameSubscriber::ShouldCaptureFrame(
TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame",
"instance", this);
- return oracle_proxy_->ObserveEventAndDecideCapture(event_type_, present_time,
- storage, deliver_frame_cb);
+ ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
+ bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
+ event_type_, present_time, storage, &capture_frame_cb);
+
+ *deliver_frame_cb = base::Bind(&InvokeCaptureFrameCallback, capture_frame_cb);
+ return oracle_decision;
}
ContentCaptureSubscription::ContentCaptureSubscription(
@@ -552,7 +365,8 @@ ContentCaptureSubscription::ContentCaptureSubscription(
}
// Subscribe to software paint events. This instance will service these by
- // reflecting them back to the CaptureMachine via |capture_callback|.
+ // reflecting them back to the WebContentsCaptureMachine via
+ // |capture_callback|.
registrar_.Add(
this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
Source<RenderWidgetHost>(&source));
@@ -734,44 +548,47 @@ void VideoFrameDeliveryLog::ChronicleFrameDelivery(int frame_number) {
}
}
-// static
-scoped_ptr<CaptureMachine> CaptureMachine::Create(
- int render_process_id,
- int render_view_id,
- const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
+WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
+ int render_view_id)
+ : initial_render_process_id_(render_process_id),
+ initial_render_view_id_(render_view_id),
+ render_thread_("WebContentsVideo_RenderThread"),
+ fullscreen_widget_id_(MSG_ROUTING_NONE) {}
+
+WebContentsCaptureMachine::~WebContentsCaptureMachine() {}
+
+bool WebContentsCaptureMachine::Start(
const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(render_task_runner.get());
- DCHECK(oracle_proxy.get());
- scoped_ptr<CaptureMachine> machine(
- new CaptureMachine(render_task_runner, oracle_proxy));
+ DCHECK(!started_);
- if (!machine->StartObservingWebContents(render_process_id, render_view_id))
- machine.reset();
+ DCHECK(oracle_proxy.get());
+ oracle_proxy_ = oracle_proxy;
- return machine.Pass();
-}
+ if (!render_thread_.Start()) {
+ DVLOG(1) << "Failed to spawn render thread.";
+ return false;
+ }
-CaptureMachine::CaptureMachine(
- const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
- const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy)
- : render_task_runner_(render_task_runner),
- oracle_proxy_(oracle_proxy),
- fullscreen_widget_id_(MSG_ROUTING_NONE) {}
+ if (!StartObservingWebContents())
+ return false;
-CaptureMachine::~CaptureMachine() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
- !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
+ started_ = true;
+ return true;
+}
- // Stop observing the web contents.
+void WebContentsCaptureMachine::Stop() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
subscription_.reset();
if (web_contents()) {
web_contents()->DecrementCapturerCount();
Observe(NULL);
}
+ render_thread_.Stop();
+ started_ = false;
}
-void CaptureMachine::Capture(
+void WebContentsCaptureMachine::Capture(
const base::Time& start_time,
const scoped_refptr<media::VideoFrame>& target,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
@@ -806,27 +623,25 @@ void CaptureMachine::Capture(
// backing store are not accessible.
rwh->GetSnapshotFromRenderer(
gfx::Rect(),
- base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(),
- start_time, target, deliver_frame_cb));
+ base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore,
+ this->AsWeakPtr(), start_time, target, deliver_frame_cb));
} else if (view->CanCopyToVideoFrame()) {
view->CopyFromCompositingSurfaceToVideoFrame(
gfx::Rect(view_size),
target,
- base::Bind(&CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame,
+ base::Bind(&WebContentsCaptureMachine::
+ DidCopyFromCompositingSurfaceToVideoFrame,
this->AsWeakPtr(), start_time, deliver_frame_cb));
} else {
rwh->CopyFromBackingStore(
gfx::Rect(),
fitted_size, // Size here is a request not always honored.
- base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(),
- start_time, target, deliver_frame_cb));
+ base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore,
+ this->AsWeakPtr(), start_time, target, deliver_frame_cb));
}
}
-bool CaptureMachine::StartObservingWebContents(int initial_render_process_id,
- int initial_render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
+bool WebContentsCaptureMachine::StartObservingWebContents() {
// Look-up the RenderViewHost and, from that, the WebContents that wraps it.
// If successful, begin observing the WebContents instance.
//
@@ -837,11 +652,11 @@ bool CaptureMachine::StartObservingWebContents(int initial_render_process_id,
// a bit of indirection across threads. It's easily possible that, in the
// meantime, the original RenderView may have gone away.
RenderViewHost* const rvh =
- RenderViewHost::FromID(initial_render_process_id,
- initial_render_view_id);
+ RenderViewHost::FromID(initial_render_process_id_,
+ initial_render_view_id_);
DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
- << initial_render_process_id << ", "
- << initial_render_view_id << ") returned NULL.";
+ << initial_render_process_id_ << ", "
+ << initial_render_view_id_ << ") returned NULL.";
Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
@@ -856,7 +671,8 @@ bool CaptureMachine::StartObservingWebContents(int initial_render_process_id,
return false;
}
-void CaptureMachine::WebContentsDestroyed(WebContents* web_contents) {
+void WebContentsCaptureMachine::WebContentsDestroyed(
+ WebContents* web_contents) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
subscription_.reset();
@@ -864,7 +680,7 @@ void CaptureMachine::WebContentsDestroyed(WebContents* web_contents) {
oracle_proxy_->ReportError();
}
-RenderWidgetHost* CaptureMachine::GetTarget() {
+RenderWidgetHost* WebContentsCaptureMachine::GetTarget() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!web_contents())
return NULL;
@@ -881,7 +697,7 @@ RenderWidgetHost* CaptureMachine::GetTarget() {
return rwh;
}
-void CaptureMachine::DidCopyFromBackingStore(
+void WebContentsCaptureMachine::DidCopyFromBackingStore(
const base::Time& start_time,
const scoped_refptr<media::VideoFrame>& target,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
@@ -895,7 +711,7 @@ void CaptureMachine::DidCopyFromBackingStore(
UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
"Render");
- render_task_runner_->PostTask(FROM_HERE, base::Bind(
+ render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
&RenderVideoFrame, bitmap, target,
base::Bind(deliver_frame_cb, start_time)));
} else {
@@ -905,7 +721,7 @@ void CaptureMachine::DidCopyFromBackingStore(
}
}
-void CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
+void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
const base::Time& start_time,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb,
@@ -922,7 +738,7 @@ void CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
deliver_frame_cb.Run(start_time, success);
}
-void CaptureMachine::RenewFrameSubscription() {
+void WebContentsCaptureMachine::RenewFrameSubscription() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Always destroy the old subscription before creating a new one.
@@ -933,240 +749,15 @@ void CaptureMachine::RenewFrameSubscription() {
return;
subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
- base::Bind(&CaptureMachine::Capture, this->AsWeakPtr())));
-}
-
-void DeleteCaptureMachineOnUIThread(
- scoped_ptr<CaptureMachine> capture_machine) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- capture_machine.reset();
+ base::Bind(&WebContentsCaptureMachine::Capture, this->AsWeakPtr())));
}
} // namespace
-// The "meat" of the video capture implementation, which is a ref-counted class.
-// Separating this from the "shell class" WebContentsVideoCaptureDevice allows
-// safe destruction without needing to block any threads (e.g., the IO
-// BrowserThread).
-//
-// WebContentsVideoCaptureDevice::Impl manages a simple state machine and the
-// pipeline (see notes at top of this file). It times the start of successive
-// captures and facilitates the processing of each through the stages of the
-// pipeline.
-class WebContentsVideoCaptureDevice::Impl : public base::SupportsWeakPtr<Impl> {
- public:
-
- Impl(int render_process_id, int render_view_id);
- virtual ~Impl();
-
- // Asynchronous requests to change WebContentsVideoCaptureDevice::Impl state.
- void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<media::VideoCaptureDevice::Client> client);
- void StopAndDeAllocate();
-
- private:
-
- // Flag indicating current state.
- enum State {
- kIdle,
- kCapturing,
- kError
- };
-
- void TransitionStateTo(State next_state);
-
- // Stops capturing and notifies client_ of an error state.
- void Error();
-
- // Called in response to CaptureMachine::Create that runs on the UI thread.
- // It will assign the capture machine to the Impl class if it still exists
- // otherwise it will post a task to delete CaptureMachine on the UI thread.
- static void AssignCaptureMachine(
- base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
- scoped_ptr<CaptureMachine> capture_machine);
-
- // Tracks that all activity occurs on the media stream manager's thread.
- base::ThreadChecker thread_checker_;
-
- // These values identify the starting view that will be captured. After
- // capture starts, the target view IDs will change as navigation occurs, and
- // so these values are not relevant after the initial bootstrapping.
- const int initial_render_process_id_;
- const int initial_render_view_id_;
-
- // Current lifecycle state.
- State state_;
-
- // A dedicated worker thread for doing image operations. Started/joined here,
- // but used by the CaptureMachine.
- base::Thread render_thread_;
-
- // Tracks the CaptureMachine that's doing work on our behalf on the UI thread.
- // This value should never be dereferenced by this class, other than to
- // create and destroy it on the UI thread.
- scoped_ptr<CaptureMachine> capture_machine_;
-
- // Our thread-safe capture oracle which serves as the gateway to the video
- // capture pipeline. Besides the WCVCD itself, it is the only component of the
- // system with direct access to |client_|.
- scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(Impl);
-};
-
-WebContentsVideoCaptureDevice::Impl::Impl(int render_process_id,
- int render_view_id)
- : initial_render_process_id_(render_process_id),
- initial_render_view_id_(render_view_id),
- state_(kIdle),
- render_thread_("WebContentsVideo_RenderThread") {}
-
-void WebContentsVideoCaptureDevice::Impl::AllocateAndStart(
- const media::VideoCaptureParams& params,
- scoped_ptr<VideoCaptureDevice::Client> client) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (state_ != kIdle) {
- DVLOG(1) << "Allocate() invoked when not in state Idle.";
- return;
- }
-
- if (params.requested_format.frame_rate <= 0) {
- DVLOG(1) << "invalid frame_rate: " << params.requested_format.frame_rate;
- client->OnError();
- return;
- }
-
- if (!render_thread_.Start()) {
- DVLOG(1) << "Failed to spawn render thread.";
- client->OnError();
- return;
- }
-
- // Frame dimensions must each be a positive, even integer, since the client
- // wants (or will convert to) YUV420.
- gfx::Size frame_size(MakeEven(params.requested_format.frame_size.width()),
- MakeEven(params.requested_format.frame_size.height()));
- if (frame_size.width() < kMinFrameWidth ||
- frame_size.height() < kMinFrameHeight) {
- DVLOG(1) << "invalid frame size: " << frame_size.ToString();
- client->OnError();
- return;
- }
-
- base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds(
- 1000000.0 / params.requested_format.frame_rate + 0.5);
-
- scoped_ptr<VideoCaptureOracle> oracle(
- new VideoCaptureOracle(capture_period,
- kAcceleratedSubscriberIsSupported));
- oracle_proxy_ =
- new ThreadSafeCaptureOracle(client.Pass(),
- oracle.Pass(),
- frame_size,
- params.requested_format.frame_rate);
-
- // Allocates the CaptureMachine. The CaptureMachine will be tracking render
- // view swapping over its lifetime, and we don't want to lose our reference to
- // the current render view by starting over with the stale
- // |initial_render_view_id_|.
- DCHECK(!capture_machine_.get());
- BrowserThread::PostTaskAndReplyWithResult(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&CaptureMachine::Create,
- initial_render_process_id_,
- initial_render_view_id_,
- render_thread_.message_loop_proxy(), oracle_proxy_),
- base::Bind(&Impl::AssignCaptureMachine, AsWeakPtr()));
-
- TransitionStateTo(kCapturing);
-}
-
-// static
-void WebContentsVideoCaptureDevice::Impl::AssignCaptureMachine(
- base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
- scoped_ptr<CaptureMachine> capture_machine) {
- DCHECK(!impl.get() || impl->thread_checker_.CalledOnValidThread());
-
- if (!impl.get()) {
- // If WCVD::Impl was destroyed before we got back on it's thread and
- // capture_machine is not NULL, then we need to return to the UI thread to
- // safely cleanup the CaptureMachine.
- if (capture_machine) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, base::Bind(
- &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine)));
- return;
- }
- } else if (!capture_machine) {
- impl->Error();
- } else {
- impl->capture_machine_ = capture_machine.Pass();
- }
-}
-
-void WebContentsVideoCaptureDevice::Impl::StopAndDeAllocate() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (state_ != kCapturing) {
- return;
- }
- oracle_proxy_->Stop();
- oracle_proxy_ = NULL;
- render_thread_.Stop();
-
- TransitionStateTo(kIdle);
-
- // There is still a capture pipeline running that is checking in with the
- // oracle, and processing captures that are already started in flight. That
- // pipeline must be shut down asynchronously, on the UI thread.
- if (capture_machine_) {
- // The task that is posted to the UI thread might not run if we are shutting
- // down, so we transfer ownership of CaptureMachine to the closure so that
- // it is still cleaned up when the closure is deleted.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE, base::Bind(
- &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine_)));
- }
-}
-
-WebContentsVideoCaptureDevice::Impl::~Impl() {
- DCHECK(!capture_machine_) << "Cleanup on UI thread did not happen.";
- DVLOG(1) << "WebContentsVideoCaptureDevice::Impl@" << this << " destroying.";
-}
-
-void WebContentsVideoCaptureDevice::Impl::TransitionStateTo(State next_state) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
-#ifndef NDEBUG
- static const char* kStateNames[] = {
- "Idle", "Allocated", "Capturing", "Error"
- };
- DVLOG(1) << "State change: " << kStateNames[state_]
- << " --> " << kStateNames[next_state];
-#endif
-
- state_ = next_state;
-}
-
-void WebContentsVideoCaptureDevice::Impl::Error() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (state_ == kIdle)
- return;
-
- if (oracle_proxy_)
- oracle_proxy_->ReportError();
-
- StopAndDeAllocate();
- TransitionStateTo(kError);
-}
-
WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
- int render_process_id,
- int render_view_id)
- : impl_(new WebContentsVideoCaptureDevice::Impl(render_process_id,
- render_view_id)) {}
+ int render_process_id, int render_view_id)
+ : impl_(new VideoCaptureDeviceImpl(scoped_ptr<VideoCaptureMachine>(
+ new WebContentsCaptureMachine(render_process_id, render_view_id)))) {}
WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying.";
« 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