| Index: content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
|
| diff --git a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
|
| index 4f41283b1ac6791562bafbfd7cbf43f1feeca7d3..6d74199f78c632dee1628d03e53524aa6dacd251 100644
|
| --- a/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
|
| +++ b/content/browser/renderer_host/media/web_contents_video_capture_device_unittest.cc
|
| @@ -5,14 +5,20 @@
|
| #include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
|
|
|
| #include "base/bind_helpers.h"
|
| -#include "base/synchronization/condition_variable.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| +#include "base/debug/debugger.h"
|
| +#include "base/run_loop.h"
|
| #include "base/time.h"
|
| +#include "base/timer.h"
|
| #include "content/browser/browser_thread_impl.h"
|
| -#include "content/browser/renderer_host/render_widget_host_delegate.h"
|
| +#include "content/browser/renderer_host/media/web_contents_capture_util.h"
|
| +#include "content/browser/renderer_host/render_view_host_factory.h"
|
| #include "content/browser/renderer_host/render_widget_host_impl.h"
|
| +#include "content/browser/renderer_host/test_render_view_host.h"
|
| #include "content/public/test/mock_render_process_host.h"
|
| #include "content/public/test/test_browser_context.h"
|
| +#include "content/public/test/test_browser_thread.h"
|
| +#include "content/public/test/test_utils.h"
|
| +#include "content/test/test_web_contents.h"
|
| #include "media/base/video_util.h"
|
| #include "media/video/capture/video_capture_types.h"
|
| #include "skia/ext/platform_canvas.h"
|
| @@ -24,106 +30,269 @@ namespace {
|
| const int kTestWidth = 1280;
|
| const int kTestHeight = 720;
|
| const int kBytesPerPixel = 4;
|
| -const int kTestFramesPerSecond = 8;
|
| -const base::TimeDelta kWaitTimeout =
|
| - base::TimeDelta::FromMilliseconds(2000);
|
| +const int kTestFramesPerSecond = 20;
|
| +const base::TimeDelta kWaitTimeout = base::TimeDelta::FromMilliseconds(2000);
|
| const SkColor kNothingYet = 0xdeadbeef;
|
| const SkColor kNotInterested = ~kNothingYet;
|
| +
|
| +void DeadlineExceeded(base::Closure quit_closure) {
|
| + if (!base::debug::BeingDebugged()) {
|
| + FAIL() << "Deadline exceeded while waiting, quitting";
|
| + quit_closure.Run();
|
| + } else {
|
| + LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
|
| + << "attached.";
|
| + }
|
| }
|
|
|
| -// A stub implementation which returns solid-color bitmaps in calls to
|
| -// CopyFromBackingStore(). The unit tests can change the color for successive
|
| -// captures.
|
| -class StubRenderWidgetHost : public RenderWidgetHostImpl {
|
| +void RunCurrentLoopWithDeadline() {
|
| + base::Timer deadline(false, false);
|
| + deadline.Start(FROM_HERE, kWaitTimeout, base::Bind(
|
| + &DeadlineExceeded, MessageLoop::current()->QuitClosure()));
|
| + MessageLoop::current()->Run();
|
| + deadline.Stop();
|
| +}
|
| +
|
| +// Thread-safe class that controls the source pattern to be captured by the
|
| +// system under test. The lifetime of this class is greater than the lifetime
|
| +// of all objects that reference it, so it does not need to be reference
|
| +// counted.
|
| +class CaptureTestSourceController {
|
| public:
|
| - StubRenderWidgetHost(RenderProcessHost* process, int routing_id)
|
| - : RenderWidgetHostImpl(&delegate_, process, routing_id),
|
| - color_(kNothingYet),
|
| + CaptureTestSourceController()
|
| + : color_(SK_ColorMAGENTA),
|
| copy_result_size_(kTestWidth, kTestHeight),
|
| - copy_event_(false, false) {}
|
| + can_copy_to_video_frame_(false) {}
|
|
|
| void SetSolidColor(SkColor color) {
|
| base::AutoLock guard(lock_);
|
| color_ = color;
|
| }
|
|
|
| + SkColor GetSolidColor() {
|
| + base::AutoLock guard(lock_);
|
| + return color_;
|
| + }
|
| +
|
| void SetCopyResultSize(int width, int height) {
|
| base::AutoLock guard(lock_);
|
| copy_result_size_ = gfx::Size(width, height);
|
| }
|
|
|
| - bool WaitForNextBackingStoreCopy() {
|
| - if (!copy_event_.TimedWait(kWaitTimeout)) {
|
| - ADD_FAILURE() << "WaitForNextBackingStoreCopy: wait deadline exceeded";
|
| - return false;
|
| + gfx::Size GetCopyResultSize() {
|
| + base::AutoLock guard(lock_);
|
| + return copy_result_size_;
|
| + }
|
| +
|
| + void SignalBackingStoreCopy() {
|
| + // TODO(nick): This actually should always be happening on the UI thread.
|
| + base::AutoLock guard(lock_);
|
| + if (!copy_done_.is_null()) {
|
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, copy_done_);
|
| + copy_done_.Reset();
|
| + }
|
| + }
|
| +
|
| + void SetCanCopyToVideoFrame(bool value) {
|
| + base::AutoLock guard(lock_);
|
| + can_copy_to_video_frame_ = value;
|
| + }
|
| +
|
| + bool CanCopyToVideoFrame() {
|
| + base::AutoLock guard(lock_);
|
| + return can_copy_to_video_frame_;
|
| + }
|
| +
|
| + void WaitForNextBackingStoreCopy() {
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + copy_done_ = MessageLoop::current()->QuitClosure();
|
| }
|
| - return true;
|
| + RunCurrentLoopWithDeadline();
|
| }
|
|
|
| - // RenderWidgetHostImpl overrides.
|
| + void OnShutdown() {
|
| + base::AutoLock guard(lock_);
|
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, shutdown_hook_);
|
| + }
|
| +
|
| + void SetShutdownHook(base::Closure shutdown_hook) {
|
| + base::AutoLock guard(lock_);
|
| + shutdown_hook_ = shutdown_hook;
|
| + }
|
| +
|
| + private:
|
| + base::Lock lock_; // Guards changes to all members.
|
| + SkColor color_;
|
| + gfx::Size copy_result_size_;
|
| + bool can_copy_to_video_frame_;
|
| + base::Closure copy_done_;
|
| + base::Closure shutdown_hook_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
|
| +};
|
| +
|
| +// A stub implementation which returns solid-color bitmaps in calls to
|
| +// CopyFromCompositingSurfaceToVideoFrame(), and which allows the video-frame
|
| +// readback path to be switched on and off. The behavior is controlled by a
|
| +// CaptureTestSourceController.
|
| +class CaptureTestView : public TestRenderWidgetHostView {
|
| + public:
|
| + explicit CaptureTestView(RenderWidgetHostImpl* rwh,
|
| + CaptureTestSourceController* controller)
|
| + : TestRenderWidgetHostView(rwh),
|
| + controller_(controller) {}
|
| + virtual ~CaptureTestView() {}
|
| +
|
| + // TestRenderWidgetHostView overrides.
|
| + virtual gfx::Rect GetViewBounds() const OVERRIDE {
|
| + return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
|
| + }
|
| +
|
| + virtual bool CanCopyToVideoFrame() const OVERRIDE {
|
| + return controller_->CanCopyToVideoFrame();
|
| + }
|
| +
|
| + virtual void CopyFromCompositingSurfaceToVideoFrame(
|
| + const gfx::Rect& src_subrect,
|
| + const scoped_refptr<media::VideoFrame>& target,
|
| + const base::Callback<void(bool)>& callback) OVERRIDE {
|
| + SkColor c = controller_->GetSolidColor();
|
| + media::FillYUV(target, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
|
| + callback.Run(true);
|
| + controller_->SignalBackingStoreCopy();
|
| + }
|
| +
|
| + private:
|
| + CaptureTestSourceController* const controller_;
|
| +
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView);
|
| +};
|
| +
|
| +#if defined(COMPILER_MSVC)
|
| +// MSVC warns on diamond inheritance. See comment for same warning on
|
| +// RenderViewHostImpl.
|
| +#pragma warning(push)
|
| +#pragma warning(disable: 4250)
|
| +#endif
|
| +
|
| +// A stub implementation which returns solid-color bitmaps in calls to
|
| +// CopyFromBackingStore(). The behavior is controlled by a
|
| +// CaptureTestSourceController.
|
| +class CaptureTestRenderViewHost : public TestRenderViewHost {
|
| + public:
|
| + CaptureTestRenderViewHost(SiteInstance* instance,
|
| + RenderViewHostDelegate* delegate,
|
| + RenderWidgetHostDelegate* widget_delegate,
|
| + int routing_id,
|
| + bool swapped_out,
|
| + CaptureTestSourceController* controller)
|
| + : TestRenderViewHost(instance, delegate, widget_delegate, routing_id,
|
| + swapped_out),
|
| + controller_(controller) {
|
| + // Override the default view installed by TestRenderViewHost; we need
|
| + // our special subclass which has mocked-out tab capture support.
|
| + RenderWidgetHostView* old_view = GetView();
|
| + SetView(new CaptureTestView(this, controller));
|
| + delete old_view;
|
| + }
|
| +
|
| + // TestRenderViewHost overrides.
|
| virtual void CopyFromBackingStore(
|
| const gfx::Rect& src_rect,
|
| const gfx::Size& accelerated_dst_size,
|
| const base::Callback<void(bool, const SkBitmap&)>& callback) OVERRIDE {
|
| + gfx::Size size = controller_->GetCopyResultSize();
|
| + SkColor color = controller_->GetSolidColor();
|
| +
|
| // Although it's not necessary, use a PlatformBitmap here (instead of a
|
| // regular SkBitmap) to exercise possible threading issues.
|
| - scoped_ptr<skia::PlatformBitmap> platform_bitmap(new skia::PlatformBitmap);
|
| - EXPECT_TRUE(platform_bitmap->Allocate(
|
| - copy_result_size_.width(), copy_result_size_.height(), false));
|
| + skia::PlatformBitmap output;
|
| + EXPECT_TRUE(output.Allocate(size.width(), size.height(), false));
|
| {
|
| - SkAutoLockPixels locker(platform_bitmap->GetBitmap());
|
| - base::AutoLock guard(lock_);
|
| - platform_bitmap->GetBitmap().eraseColor(color_);
|
| + SkAutoLockPixels locker(output.GetBitmap());
|
| + output.GetBitmap().eraseColor(color);
|
| }
|
| -
|
| - callback.Run(true, platform_bitmap->GetBitmap());
|
| - copy_event_.Signal();
|
| + callback.Run(true, output.GetBitmap());
|
| + controller_->SignalBackingStoreCopy();
|
| }
|
|
|
| private:
|
| - class StubRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
|
| - public:
|
| - StubRenderWidgetHostDelegate() {}
|
| - virtual ~StubRenderWidgetHostDelegate() {}
|
| + CaptureTestSourceController* controller_;
|
|
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(StubRenderWidgetHostDelegate);
|
| - };
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHost);
|
| +};
|
|
|
| - StubRenderWidgetHostDelegate delegate_;
|
| - base::Lock lock_; // Guards changes to color_.
|
| - SkColor color_;
|
| - gfx::Size copy_result_size_;
|
| - base::WaitableEvent copy_event_;
|
| +#if defined(COMPILER_MSVC)
|
| +// Re-enable warning 4250
|
| +#pragma warning(pop)
|
| +#endif
|
|
|
| - DISALLOW_IMPLICIT_CONSTRUCTORS(StubRenderWidgetHost);
|
| +class CaptureTestRenderViewHostFactory : public RenderViewHostFactory {
|
| + public:
|
| + explicit CaptureTestRenderViewHostFactory(
|
| + CaptureTestSourceController* controller) : controller_(controller) {
|
| + RegisterFactory(this);
|
| + }
|
| +
|
| + virtual ~CaptureTestRenderViewHostFactory() {
|
| + UnregisterFactory();
|
| + }
|
| +
|
| + // RenderViewHostFactory implementation.
|
| + virtual RenderViewHost* CreateRenderViewHost(
|
| + SiteInstance* instance,
|
| + RenderViewHostDelegate* delegate,
|
| + RenderWidgetHostDelegate* widget_delegate,
|
| + int routing_id,
|
| + bool swapped_out,
|
| + SessionStorageNamespace* session_storage_namespace) {
|
| + return new CaptureTestRenderViewHost(instance, delegate, widget_delegate,
|
| + routing_id, swapped_out, controller_);
|
| + }
|
| + private:
|
| + CaptureTestSourceController* controller_;
|
| +
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHostFactory);
|
| };
|
|
|
| // A stub consumer of captured video frames, which checks the output of
|
| // WebContentsVideoCaptureDevice.
|
| class StubConsumer : public media::VideoCaptureDevice::EventHandler {
|
| public:
|
| - StubConsumer() : output_changed_(&lock_),
|
| - picture_color_(kNothingYet),
|
| - error_encountered_(false) {}
|
| + StubConsumer() : error_encountered_(false), wait_color_(0xcafe1950) {}
|
| virtual ~StubConsumer() {}
|
|
|
| - // Returns false if an error was encountered.
|
| - bool WaitForNextColorOrError(SkColor expected_color) {
|
| - base::TimeTicks deadline = base::TimeTicks::Now() + kWaitTimeout;
|
| + void QuitIfConditionMet(SkColor color) {
|
| base::AutoLock guard(lock_);
|
| - while (picture_color_ != expected_color && !error_encountered_) {
|
| - output_changed_.TimedWait(kWaitTimeout);
|
| - if (base::TimeTicks::Now() >= deadline) {
|
| - ADD_FAILURE() << "WaitForNextColorOrError: wait deadline exceeded";
|
| - return false;
|
| - }
|
| +
|
| + if (wait_color_ == color || error_encountered_)
|
| + MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + void WaitForNextColor(SkColor expected_color) {
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + wait_color_ = expected_color;
|
| + error_encountered_ = false;
|
| }
|
| - if (!error_encountered_) {
|
| - EXPECT_EQ(expected_color, picture_color_);
|
| - return true;
|
| - } else {
|
| - return false;
|
| + RunCurrentLoopWithDeadline();
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + ASSERT_FALSE(error_encountered_);
|
| + }
|
| + }
|
| +
|
| + void WaitForError() {
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + wait_color_ = kNotInterested;
|
| + error_encountered_ = false;
|
| + }
|
| + RunCurrentLoopWithDeadline();
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + ASSERT_TRUE(error_encountered_);
|
| }
|
| }
|
|
|
| @@ -143,49 +312,34 @@ class StubConsumer : public media::VideoCaptureDevice::EventHandler {
|
| }
|
| }
|
| EXPECT_TRUE(all_pixels_are_the_same_color);
|
| -
|
| - {
|
| - base::AutoLock guard(lock_);
|
| - if (color != picture_color_) {
|
| - picture_color_ = color;
|
| - output_changed_.Signal();
|
| - }
|
| - }
|
| + PostColorOrError(color);
|
| }
|
|
|
| virtual void OnIncomingCapturedVideoFrame(media::VideoFrame* frame,
|
| base::Time timestamp) OVERRIDE {
|
| EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->coded_size());
|
| EXPECT_EQ(media::VideoFrame::YV12, frame->format());
|
| - bool all_pixels_are_the_same_color = true;
|
| uint8 yuv[3] = {0};
|
| for (int plane = 0; plane < 3; ++plane) {
|
| yuv[plane] = frame->data(plane)[0];
|
| - for (int y = 0; y < frame->rows(plane); ++y) {
|
| - for (int x = 0; x < frame->row_bytes(plane); ++x) {
|
| - if (yuv[plane] != frame->data(plane)[x + y * frame->stride(plane)]) {
|
| - all_pixels_are_the_same_color = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| }
|
| - EXPECT_TRUE(all_pixels_are_the_same_color);
|
| - const SkColor color = SkColorSetRGB(yuv[0], yuv[1], yuv[2]);
|
| + // TODO(nick): We just look at the first pixel presently, because if
|
| + // the analysis is too slow, the backlog of frames will grow without bound
|
| + // and trouble erupts. http://crbug.com/174519
|
| + PostColorOrError(SkColorSetRGB(yuv[0], yuv[1], yuv[2]));
|
| + }
|
|
|
| - {
|
| - base::AutoLock guard(lock_);
|
| - if (color != picture_color_) {
|
| - picture_color_ = color;
|
| - output_changed_.Signal();
|
| - }
|
| - }
|
| + void PostColorOrError(SkColor new_color) {
|
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
| + &StubConsumer::QuitIfConditionMet, base::Unretained(this), new_color));
|
| }
|
|
|
| virtual void OnError() OVERRIDE {
|
| - base::AutoLock guard(lock_);
|
| - error_encountered_ = true;
|
| - output_changed_.Signal();
|
| + {
|
| + base::AutoLock guard(lock_);
|
| + error_encountered_ = true;
|
| + }
|
| + PostColorOrError(kNothingYet);
|
| }
|
|
|
| virtual void OnFrameInfo(const media::VideoCaptureCapability& info) OVERRIDE {
|
| @@ -197,13 +351,14 @@ class StubConsumer : public media::VideoCaptureDevice::EventHandler {
|
|
|
| private:
|
| base::Lock lock_;
|
| - base::ConditionVariable output_changed_;
|
| - SkColor picture_color_;
|
| bool error_encountered_;
|
| + SkColor wait_color_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(StubConsumer);
|
| };
|
|
|
| +} // namespace
|
| +
|
| // Test harness that sets up a minimal environment with necessary stubs.
|
| class WebContentsVideoCaptureDeviceTest : public testing::Test {
|
| public:
|
| @@ -211,55 +366,101 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
|
|
|
| protected:
|
| virtual void SetUp() {
|
| - // This is a MessageLoop for the current thread. The MockRenderProcessHost
|
| - // will schedule its destruction in this MessageLoop during TearDown().
|
| - message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
|
| + // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
|
| + // eliminated here, if only we could use RenderViewHostTestHarness. The
|
| + // catch is that we need our TestRenderViewHost to support a
|
| + // CopyFromBackingStore operation that we control. To accomplish that,
|
| + // either RenderViewHostTestHarness would have to support installing a
|
| + // custom RenderViewHostFactory, or else we implant some kind of delegated
|
| + // CopyFromBackingStore functionality into TestRenderViewHost itself.
|
| +
|
| + // The main thread will serve as the UI thread as well as the test thread.
|
| + // We'll manually pump the run loop at appropriate times in the test.
|
| + ui_thread_.reset(new TestBrowserThread(BrowserThread::UI, &message_loop_));
|
| +
|
| + render_process_host_factory_.reset(new MockRenderProcessHostFactory());
|
| + // Create our (self-registering) RVH factory, so that when we create a
|
| + // WebContents, it in turn creates CaptureTestRenderViewHosts.
|
| + render_view_host_factory_.reset(
|
| + new CaptureTestRenderViewHostFactory(&controller_));
|
|
|
| - // The CopyFromBackingStore and WebContents tracking occur on the UI thread.
|
| - ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI));
|
| - ui_thread_->Start();
|
| -
|
| - // And the rest...
|
| browser_context_.reset(new TestBrowserContext());
|
| - source_.reset(new StubRenderWidgetHost(
|
| - new MockRenderProcessHost(browser_context_.get()), MSG_ROUTING_NONE));
|
| - destroyed_.reset(new base::WaitableEvent(true, false));
|
| - device_.reset(WebContentsVideoCaptureDevice::CreateForTesting(
|
| - source_.get(),
|
| - base::Bind(&base::WaitableEvent::Signal,
|
| - base::Unretained(destroyed_.get()))));
|
| - consumer_.reset(new StubConsumer);
|
| +
|
| + scoped_refptr<SiteInstance> site_instance =
|
| + SiteInstance::Create(browser_context_.get());
|
| + static_cast<SiteInstanceImpl*>(site_instance.get())->
|
| + set_render_process_host_factory(render_process_host_factory_.get());
|
| + web_contents_.reset(
|
| + TestWebContents::Create(browser_context_.get(), site_instance));
|
| +
|
| + // This is actually a CaptureTestRenderViewHost.
|
| + RenderWidgetHostImpl* rwh =
|
| + RenderWidgetHostImpl::From(web_contents_->GetRenderViewHost());
|
| +
|
| + std::string device_id =
|
| + WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
|
| + base::StringPrintf("%d:%d", rwh->GetProcess()->GetID(),
|
| + rwh->GetRoutingID()));
|
| +
|
| + base::Closure destroy_cb = base::Bind(
|
| + &CaptureTestSourceController::OnShutdown,
|
| + base::Unretained(&controller_));
|
| +
|
| + device_.reset(WebContentsVideoCaptureDevice::Create(device_id, destroy_cb));
|
| }
|
|
|
| virtual void TearDown() {
|
| // Tear down in opposite order of set-up.
|
| - device_->DeAllocate(); // Guarantees no more use of consumer_.
|
| - consumer_.reset();
|
| - device_.reset(); // Release reference to internal CaptureMachine.
|
| - message_loop_->RunUntilIdle(); // Just in case.
|
| - destroyed_->Wait(); // Wait until CaptureMachine is fully destroyed.
|
| - destroyed_.reset();
|
| - source_.reset();
|
| +
|
| + // The device is destroyed asynchronously, and will notify the
|
| + // CaptureTestSourceController when it finishes destruction.
|
| + // Trigger this, and wait.
|
| + base::RunLoop shutdown_loop;
|
| + controller_.SetShutdownHook(shutdown_loop.QuitClosure());
|
| + device_->DeAllocate();
|
| + device_.reset();
|
| + shutdown_loop.Run();
|
| +
|
| + // Destroy the browser objects.
|
| + web_contents_.reset();
|
| browser_context_.reset();
|
| - ui_thread_->Stop();
|
| - ui_thread_.reset();
|
| - message_loop_->RunUntilIdle(); // Deletes MockRenderProcessHost.
|
| - message_loop_.reset();
|
| +
|
| + content::RunAllPendingInMessageLoop();
|
| +
|
| + render_view_host_factory_.reset();
|
| + render_process_host_factory_.reset();
|
| }
|
|
|
| // Accessors.
|
| - StubRenderWidgetHost* source() const { return source_.get(); }
|
| - media::VideoCaptureDevice* device() const { return device_.get(); }
|
| - StubConsumer* consumer() const { return consumer_.get(); }
|
| + CaptureTestSourceController* source() { return &controller_; }
|
| + media::VideoCaptureDevice* device() { return device_.get(); }
|
| + StubConsumer* consumer() { return &consumer_; }
|
|
|
| private:
|
| - scoped_ptr<MessageLoop> message_loop_;
|
| - scoped_ptr<BrowserThreadImpl> ui_thread_;
|
| + // The consumer is the ultimate recipient of captured pixel data.
|
| + StubConsumer consumer_;
|
| +
|
| + // The controller controls which pixel patterns to produce.
|
| + CaptureTestSourceController controller_;
|
| +
|
| + // We run the UI message loop on the main thread. The capture device
|
| + // will also spin up its own threads.
|
| + MessageLoopForUI message_loop_;
|
| + scoped_ptr<TestBrowserThread> ui_thread_;
|
| +
|
| + // Self-registering RenderProcessHostFactory.
|
| + scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
|
| +
|
| + // Creates capture-capable RenderViewHosts whose pixel content production is
|
| + // under the control of |controller_|.
|
| + scoped_ptr<CaptureTestRenderViewHostFactory> render_view_host_factory_;
|
| +
|
| + // A mocked-out browser and tab.
|
| scoped_ptr<TestBrowserContext> browser_context_;
|
| - scoped_ptr<StubRenderWidgetHost> source_;
|
| - scoped_ptr<base::WaitableEvent> destroyed_;
|
| + scoped_ptr<WebContents> web_contents_;
|
| +
|
| + // Finally, the WebContentsVideoCaptureDevice under test.
|
| scoped_ptr<media::VideoCaptureDevice> device_;
|
| - scoped_ptr<StubConsumer> consumer_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(WebContentsVideoCaptureDeviceTest);
|
| };
|
| @@ -270,28 +471,24 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
|
| // paths, just as RenderWidgetHost might if the content falls in and out of
|
| // accelerated compositing.
|
| TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
|
| - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond,
|
| - consumer());
|
| + device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer());
|
|
|
| device()->Start();
|
|
|
| bool use_video_frames = false;
|
| for (int i = 0; i < 4; i++, use_video_frames = !use_video_frames) {
|
| - SCOPED_TRACE(
|
| - testing::Message() << "Using "
|
| - << (use_video_frames ? "VideoFrame" : "SkBitmap")
|
| - << " path, iteration #" << i);
|
| - // TODO(nick): Implement this.
|
| - // source()->SetUseVideoFrames(use_video_frames);
|
| + SCOPED_TRACE(StringPrintf("Using %s path, iteration #%d",
|
| + use_video_frames ? "VideoFrame" : "SkBitmap", i));
|
| + source()->SetCanCopyToVideoFrame(use_video_frames);
|
| source()->SetSolidColor(SK_ColorRED);
|
| - source()->WaitForNextBackingStoreCopy();
|
| - ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorRED));
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
|
| source()->SetSolidColor(SK_ColorGREEN);
|
| - ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorGREEN));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
|
| source()->SetSolidColor(SK_ColorBLUE);
|
| - ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorBLUE));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLUE));
|
| source()->SetSolidColor(SK_ColorBLACK);
|
| - ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorBLACK));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLACK));
|
| }
|
|
|
| device()->DeAllocate();
|
| @@ -299,13 +496,11 @@ TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
|
|
|
| TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) {
|
| device()->Allocate(1280, 720, -2, consumer());
|
| - EXPECT_FALSE(consumer()->WaitForNextColorOrError(kNotInterested));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError());
|
| }
|
|
|
| TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
|
| - device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond,
|
| - consumer());
|
| -
|
| + device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer());
|
|
|
| // 1x1 is too small to process; we intend for this to result in an error.
|
| source()->SetCopyResultSize(1, 1);
|
| @@ -314,18 +509,20 @@ TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
|
|
|
| // These frames ought to be dropped during the Render stage. Let
|
| // several captures to happen.
|
| - ASSERT_TRUE(source()->WaitForNextBackingStoreCopy());
|
| - ASSERT_TRUE(source()->WaitForNextBackingStoreCopy());
|
| - ASSERT_TRUE(source()->WaitForNextBackingStoreCopy());
|
| - ASSERT_TRUE(source()->WaitForNextBackingStoreCopy());
|
| - ASSERT_TRUE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
| + ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
|
|
|
| // Now push some good frames through; they should be processed normally.
|
| source()->SetCopyResultSize(kTestWidth, kTestHeight);
|
| source()->SetSolidColor(SK_ColorGREEN);
|
| - EXPECT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorGREEN));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
|
| source()->SetSolidColor(SK_ColorRED);
|
| - EXPECT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorRED));
|
| + ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
|
| +
|
| + device()->Stop();
|
| device()->DeAllocate();
|
| }
|
|
|
|
|