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

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

Issue 12258042: Rewrite WebContentsVideoCaptureDeviceTest. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Refiddle test exclusions. Created 7 years, 9 months 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 #include "content/browser/renderer_host/media/web_contents_video_capture_device. h" 5 #include "content/browser/renderer_host/media/web_contents_video_capture_device. h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/synchronization/condition_variable.h" 8 #include "base/debug/debugger.h"
9 #include "base/synchronization/waitable_event.h" 9 #include "base/run_loop.h"
10 #include "base/time.h" 10 #include "base/time.h"
11 #include "base/timer.h"
11 #include "content/browser/browser_thread_impl.h" 12 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/renderer_host/render_widget_host_delegate.h" 13 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
14 #include "content/browser/renderer_host/render_view_host_factory.h"
13 #include "content/browser/renderer_host/render_widget_host_impl.h" 15 #include "content/browser/renderer_host/render_widget_host_impl.h"
16 #include "content/browser/renderer_host/test_render_view_host.h"
14 #include "content/public/test/mock_render_process_host.h" 17 #include "content/public/test/mock_render_process_host.h"
15 #include "content/public/test/test_browser_context.h" 18 #include "content/public/test/test_browser_context.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "content/public/test/test_utils.h"
21 #include "content/test/test_web_contents.h"
16 #include "media/base/video_util.h" 22 #include "media/base/video_util.h"
17 #include "media/video/capture/video_capture_types.h" 23 #include "media/video/capture/video_capture_types.h"
18 #include "skia/ext/platform_canvas.h" 24 #include "skia/ext/platform_canvas.h"
19 #include "testing/gtest/include/gtest/gtest.h" 25 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/skia/include/core/SkColor.h" 26 #include "third_party/skia/include/core/SkColor.h"
21 27
22 namespace content { 28 namespace content {
23 namespace { 29 namespace {
24 const int kTestWidth = 1280; 30 const int kTestWidth = 1280;
25 const int kTestHeight = 720; 31 const int kTestHeight = 720;
26 const int kBytesPerPixel = 4; 32 const int kBytesPerPixel = 4;
27 const int kTestFramesPerSecond = 8; 33 const int kTestFramesPerSecond = 20;
28 const base::TimeDelta kWaitTimeout = 34 const base::TimeDelta kWaitTimeout = base::TimeDelta::FromMilliseconds(2000);
29 base::TimeDelta::FromMilliseconds(2000);
30 const SkColor kNothingYet = 0xdeadbeef; 35 const SkColor kNothingYet = 0xdeadbeef;
31 const SkColor kNotInterested = ~kNothingYet; 36 const SkColor kNotInterested = ~kNothingYet;
37
38 void DeadlineExceeded(base::Closure quit_closure) {
39 if (!base::debug::BeingDebugged()) {
40 FAIL() << "Deadline exceeded while waiting, quitting";
41 quit_closure.Run();
42 } else {
43 LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
44 << "attached.";
45 }
32 } 46 }
33 47
48 void RunCurrentLoopWithDeadline() {
49 base::Timer deadline(false, false);
50 deadline.Start(FROM_HERE, kWaitTimeout, base::Bind(
51 &DeadlineExceeded, MessageLoop::current()->QuitClosure()));
52 MessageLoop::current()->Run();
53 deadline.Stop();
54 }
55
56 // Thread-safe class that controls the source pattern to be captured by the
57 // system under test. The lifetime of this class is greater than the lifetime
58 // of all objects that reference it, so it does not need to be reference
59 // counted.
60 class CaptureTestSourceController {
61 public:
62 CaptureTestSourceController()
63 : color_(SK_ColorMAGENTA),
64 copy_result_size_(kTestWidth, kTestHeight),
65 can_copy_to_video_frame_(false) {}
66
67 void SetSolidColor(SkColor color) {
68 base::AutoLock guard(lock_);
69 color_ = color;
70 }
71
72 SkColor GetSolidColor() {
73 base::AutoLock guard(lock_);
74 return color_;
75 }
76
77 void SetCopyResultSize(int width, int height) {
78 base::AutoLock guard(lock_);
79 copy_result_size_ = gfx::Size(width, height);
80 }
81
82 gfx::Size GetCopyResultSize() {
83 base::AutoLock guard(lock_);
84 return copy_result_size_;
85 }
86
87 void SignalBackingStoreCopy() {
88 // TODO(nick): This actually should always be happening on the UI thread.
89 base::AutoLock guard(lock_);
90 if (!copy_done_.is_null()) {
91 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, copy_done_);
92 copy_done_.Reset();
93 }
94 }
95
96 void SetCanCopyToVideoFrame(bool value) {
97 base::AutoLock guard(lock_);
98 can_copy_to_video_frame_ = value;
99 }
100
101 bool CanCopyToVideoFrame() {
102 base::AutoLock guard(lock_);
103 return can_copy_to_video_frame_;
104 }
105
106 void WaitForNextBackingStoreCopy() {
107 {
108 base::AutoLock guard(lock_);
109 copy_done_ = MessageLoop::current()->QuitClosure();
110 }
111 RunCurrentLoopWithDeadline();
112 }
113
114 void OnShutdown() {
115 base::AutoLock guard(lock_);
116 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, shutdown_hook_);
117 }
118
119 void SetShutdownHook(base::Closure shutdown_hook) {
120 base::AutoLock guard(lock_);
121 shutdown_hook_ = shutdown_hook;
122 }
123
124 private:
125 base::Lock lock_; // Guards changes to all members.
126 SkColor color_;
127 gfx::Size copy_result_size_;
128 bool can_copy_to_video_frame_;
129 base::Closure copy_done_;
130 base::Closure shutdown_hook_;
131
132 DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
133 };
134
34 // A stub implementation which returns solid-color bitmaps in calls to 135 // A stub implementation which returns solid-color bitmaps in calls to
35 // CopyFromBackingStore(). The unit tests can change the color for successive 136 // CopyFromCompositingSurfaceToVideoFrame(), and which allows the video-frame
36 // captures. 137 // readback path to be switched on and off. The behavior is controlled by a
37 class StubRenderWidgetHost : public RenderWidgetHostImpl { 138 // CaptureTestSourceController.
38 public: 139 class CaptureTestView : public TestRenderWidgetHostView {
39 StubRenderWidgetHost(RenderProcessHost* process, int routing_id) 140 public:
40 : RenderWidgetHostImpl(&delegate_, process, routing_id), 141 explicit CaptureTestView(RenderWidgetHostImpl* rwh,
41 color_(kNothingYet), 142 CaptureTestSourceController* controller)
42 copy_result_size_(kTestWidth, kTestHeight), 143 : TestRenderWidgetHostView(rwh),
43 copy_event_(false, false) {} 144 controller_(controller) {}
44 145 virtual ~CaptureTestView() {}
45 void SetSolidColor(SkColor color) { 146
46 base::AutoLock guard(lock_); 147 // TestRenderWidgetHostView overrides.
47 color_ = color; 148 virtual gfx::Rect GetViewBounds() const OVERRIDE {
48 } 149 return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
49 150 }
50 void SetCopyResultSize(int width, int height) { 151
51 base::AutoLock guard(lock_); 152 virtual bool CanCopyToVideoFrame() const OVERRIDE {
52 copy_result_size_ = gfx::Size(width, height); 153 return controller_->CanCopyToVideoFrame();
53 } 154 }
54 155
55 bool WaitForNextBackingStoreCopy() { 156 virtual void CopyFromCompositingSurfaceToVideoFrame(
56 if (!copy_event_.TimedWait(kWaitTimeout)) { 157 const gfx::Rect& src_subrect,
57 ADD_FAILURE() << "WaitForNextBackingStoreCopy: wait deadline exceeded"; 158 const scoped_refptr<media::VideoFrame>& target,
58 return false; 159 const base::Callback<void(bool)>& callback) OVERRIDE {
59 } 160 SkColor c = controller_->GetSolidColor();
60 return true; 161 media::FillYUV(target, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
61 } 162 callback.Run(true);
62 163 controller_->SignalBackingStoreCopy();
63 // RenderWidgetHostImpl overrides. 164 }
165
166 private:
167 CaptureTestSourceController* const controller_;
168
169 DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView);
170 };
171
172 #if defined(COMPILER_MSVC)
173 // MSVC warns on diamond inheritance. See comment for same warning on
174 // RenderViewHostImpl.
175 #pragma warning(push)
176 #pragma warning(disable: 4250)
177 #endif
178
179 // A stub implementation which returns solid-color bitmaps in calls to
180 // CopyFromBackingStore(). The behavior is controlled by a
181 // CaptureTestSourceController.
182 class CaptureTestRenderViewHost : public TestRenderViewHost {
183 public:
184 CaptureTestRenderViewHost(SiteInstance* instance,
185 RenderViewHostDelegate* delegate,
186 RenderWidgetHostDelegate* widget_delegate,
187 int routing_id,
188 bool swapped_out,
189 CaptureTestSourceController* controller)
190 : TestRenderViewHost(instance, delegate, widget_delegate, routing_id,
191 swapped_out),
192 controller_(controller) {
193 // Override the default view installed by TestRenderViewHost; we need
194 // our special subclass which has mocked-out tab capture support.
195 RenderWidgetHostView* old_view = GetView();
196 SetView(new CaptureTestView(this, controller));
197 delete old_view;
198 }
199
200 // TestRenderViewHost overrides.
64 virtual void CopyFromBackingStore( 201 virtual void CopyFromBackingStore(
65 const gfx::Rect& src_rect, 202 const gfx::Rect& src_rect,
66 const gfx::Size& accelerated_dst_size, 203 const gfx::Size& accelerated_dst_size,
67 const base::Callback<void(bool, const SkBitmap&)>& callback) OVERRIDE { 204 const base::Callback<void(bool, const SkBitmap&)>& callback) OVERRIDE {
205 gfx::Size size = controller_->GetCopyResultSize();
206 SkColor color = controller_->GetSolidColor();
207
68 // Although it's not necessary, use a PlatformBitmap here (instead of a 208 // Although it's not necessary, use a PlatformBitmap here (instead of a
69 // regular SkBitmap) to exercise possible threading issues. 209 // regular SkBitmap) to exercise possible threading issues.
70 scoped_ptr<skia::PlatformBitmap> platform_bitmap(new skia::PlatformBitmap); 210 skia::PlatformBitmap output;
71 EXPECT_TRUE(platform_bitmap->Allocate( 211 EXPECT_TRUE(output.Allocate(size.width(), size.height(), false));
72 copy_result_size_.width(), copy_result_size_.height(), false)); 212 {
73 { 213 SkAutoLockPixels locker(output.GetBitmap());
74 SkAutoLockPixels locker(platform_bitmap->GetBitmap()); 214 output.GetBitmap().eraseColor(color);
75 base::AutoLock guard(lock_); 215 }
76 platform_bitmap->GetBitmap().eraseColor(color_); 216 callback.Run(true, output.GetBitmap());
77 } 217 controller_->SignalBackingStoreCopy();
78 218 }
79 callback.Run(true, platform_bitmap->GetBitmap()); 219
80 copy_event_.Signal(); 220 private:
81 } 221 CaptureTestSourceController* controller_;
82 222
83 private: 223 DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHost);
84 class StubRenderWidgetHostDelegate : public RenderWidgetHostDelegate { 224 };
85 public: 225
86 StubRenderWidgetHostDelegate() {} 226 #if defined(COMPILER_MSVC)
87 virtual ~StubRenderWidgetHostDelegate() {} 227 // Re-enable warning 4250
88 228 #pragma warning(pop)
89 private: 229 #endif
90 DISALLOW_COPY_AND_ASSIGN(StubRenderWidgetHostDelegate); 230
91 }; 231 class CaptureTestRenderViewHostFactory : public RenderViewHostFactory {
92 232 public:
93 StubRenderWidgetHostDelegate delegate_; 233 explicit CaptureTestRenderViewHostFactory(
94 base::Lock lock_; // Guards changes to color_. 234 CaptureTestSourceController* controller) : controller_(controller) {
95 SkColor color_; 235 RegisterFactory(this);
96 gfx::Size copy_result_size_; 236 }
97 base::WaitableEvent copy_event_; 237
98 238 virtual ~CaptureTestRenderViewHostFactory() {
99 DISALLOW_IMPLICIT_CONSTRUCTORS(StubRenderWidgetHost); 239 UnregisterFactory();
240 }
241
242 // RenderViewHostFactory implementation.
243 virtual RenderViewHost* CreateRenderViewHost(
244 SiteInstance* instance,
245 RenderViewHostDelegate* delegate,
246 RenderWidgetHostDelegate* widget_delegate,
247 int routing_id,
248 bool swapped_out,
249 SessionStorageNamespace* session_storage_namespace) {
250 return new CaptureTestRenderViewHost(instance, delegate, widget_delegate,
251 routing_id, swapped_out, controller_);
252 }
253 private:
254 CaptureTestSourceController* controller_;
255
256 DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHostFactory);
100 }; 257 };
101 258
102 // A stub consumer of captured video frames, which checks the output of 259 // A stub consumer of captured video frames, which checks the output of
103 // WebContentsVideoCaptureDevice. 260 // WebContentsVideoCaptureDevice.
104 class StubConsumer : public media::VideoCaptureDevice::EventHandler { 261 class StubConsumer : public media::VideoCaptureDevice::EventHandler {
105 public: 262 public:
106 StubConsumer() : output_changed_(&lock_), 263 StubConsumer() : error_encountered_(false), wait_color_(0xcafe1950) {}
107 picture_color_(kNothingYet),
108 error_encountered_(false) {}
109 virtual ~StubConsumer() {} 264 virtual ~StubConsumer() {}
110 265
111 // Returns false if an error was encountered. 266 void QuitIfConditionMet(SkColor color) {
112 bool WaitForNextColorOrError(SkColor expected_color) { 267 base::AutoLock guard(lock_);
113 base::TimeTicks deadline = base::TimeTicks::Now() + kWaitTimeout; 268
114 base::AutoLock guard(lock_); 269 if (wait_color_ == color || error_encountered_)
115 while (picture_color_ != expected_color && !error_encountered_) { 270 MessageLoop::current()->Quit();
116 output_changed_.TimedWait(kWaitTimeout); 271 }
117 if (base::TimeTicks::Now() >= deadline) { 272
118 ADD_FAILURE() << "WaitForNextColorOrError: wait deadline exceeded"; 273 void WaitForNextColor(SkColor expected_color) {
119 return false; 274 {
120 } 275 base::AutoLock guard(lock_);
121 } 276 wait_color_ = expected_color;
122 if (!error_encountered_) { 277 error_encountered_ = false;
123 EXPECT_EQ(expected_color, picture_color_); 278 }
124 return true; 279 RunCurrentLoopWithDeadline();
125 } else { 280 {
126 return false; 281 base::AutoLock guard(lock_);
127 } 282 ASSERT_FALSE(error_encountered_);
128 } 283 }
129 284 }
285
286 void WaitForError() {
287 {
288 base::AutoLock guard(lock_);
289 wait_color_ = kNotInterested;
290 error_encountered_ = false;
291 }
292 RunCurrentLoopWithDeadline();
293 {
294 base::AutoLock guard(lock_);
295 ASSERT_TRUE(error_encountered_);
296 }
297 }
298
130 virtual void OnIncomingCapturedFrame(const uint8* data, int length, 299 virtual void OnIncomingCapturedFrame(const uint8* data, int length,
131 base::Time timestamp) OVERRIDE { 300 base::Time timestamp) OVERRIDE {
132 DCHECK(data); 301 DCHECK(data);
133 static const int kNumPixels = kTestWidth * kTestHeight; 302 static const int kNumPixels = kTestWidth * kTestHeight;
134 EXPECT_EQ(kNumPixels * kBytesPerPixel, length); 303 EXPECT_EQ(kNumPixels * kBytesPerPixel, length);
135 const uint32* p = reinterpret_cast<const uint32*>(data); 304 const uint32* p = reinterpret_cast<const uint32*>(data);
136 const uint32* const p_end = p + kNumPixels; 305 const uint32* const p_end = p + kNumPixels;
137 const SkColor color = *p; 306 const SkColor color = *p;
138 bool all_pixels_are_the_same_color = true; 307 bool all_pixels_are_the_same_color = true;
139 for (++p; p < p_end; ++p) { 308 for (++p; p < p_end; ++p) {
140 if (*p != color) { 309 if (*p != color) {
141 all_pixels_are_the_same_color = false; 310 all_pixels_are_the_same_color = false;
142 break; 311 break;
143 } 312 }
144 } 313 }
145 EXPECT_TRUE(all_pixels_are_the_same_color); 314 EXPECT_TRUE(all_pixels_are_the_same_color);
146 315 PostColorOrError(color);
147 {
148 base::AutoLock guard(lock_);
149 if (color != picture_color_) {
150 picture_color_ = color;
151 output_changed_.Signal();
152 }
153 }
154 } 316 }
155 317
156 virtual void OnIncomingCapturedVideoFrame(media::VideoFrame* frame, 318 virtual void OnIncomingCapturedVideoFrame(media::VideoFrame* frame,
157 base::Time timestamp) OVERRIDE { 319 base::Time timestamp) OVERRIDE {
158 EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->coded_size()); 320 EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), frame->coded_size());
159 EXPECT_EQ(media::VideoFrame::YV12, frame->format()); 321 EXPECT_EQ(media::VideoFrame::YV12, frame->format());
160 bool all_pixels_are_the_same_color = true;
161 uint8 yuv[3] = {0}; 322 uint8 yuv[3] = {0};
162 for (int plane = 0; plane < 3; ++plane) { 323 for (int plane = 0; plane < 3; ++plane) {
163 yuv[plane] = frame->data(plane)[0]; 324 yuv[plane] = frame->data(plane)[0];
164 for (int y = 0; y < frame->rows(plane); ++y) {
165 for (int x = 0; x < frame->row_bytes(plane); ++x) {
166 if (yuv[plane] != frame->data(plane)[x + y * frame->stride(plane)]) {
167 all_pixels_are_the_same_color = false;
168 break;
169 }
170 }
171 }
172 } 325 }
173 EXPECT_TRUE(all_pixels_are_the_same_color); 326 // TODO(nick): We just look at the first pixel presently, because if
174 const SkColor color = SkColorSetRGB(yuv[0], yuv[1], yuv[2]); 327 // the analysis is too slow, the backlog of frames will grow without bound
328 // and trouble erupts. http://crbug.com/174519
329 PostColorOrError(SkColorSetRGB(yuv[0], yuv[1], yuv[2]));
330 }
175 331
176 { 332 void PostColorOrError(SkColor new_color) {
177 base::AutoLock guard(lock_); 333 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
178 if (color != picture_color_) { 334 &StubConsumer::QuitIfConditionMet, base::Unretained(this), new_color));
179 picture_color_ = color;
180 output_changed_.Signal();
181 }
182 }
183 } 335 }
184 336
185 virtual void OnError() OVERRIDE { 337 virtual void OnError() OVERRIDE {
186 base::AutoLock guard(lock_); 338 {
187 error_encountered_ = true; 339 base::AutoLock guard(lock_);
188 output_changed_.Signal(); 340 error_encountered_ = true;
341 }
342 PostColorOrError(kNothingYet);
189 } 343 }
190 344
191 virtual void OnFrameInfo(const media::VideoCaptureCapability& info) OVERRIDE { 345 virtual void OnFrameInfo(const media::VideoCaptureCapability& info) OVERRIDE {
192 EXPECT_EQ(kTestWidth, info.width); 346 EXPECT_EQ(kTestWidth, info.width);
193 EXPECT_EQ(kTestHeight, info.height); 347 EXPECT_EQ(kTestHeight, info.height);
194 EXPECT_EQ(kTestFramesPerSecond, info.frame_rate); 348 EXPECT_EQ(kTestFramesPerSecond, info.frame_rate);
195 EXPECT_EQ(media::VideoCaptureCapability::kARGB, info.color); 349 EXPECT_EQ(media::VideoCaptureCapability::kARGB, info.color);
196 } 350 }
197 351
198 private: 352 private:
199 base::Lock lock_; 353 base::Lock lock_;
200 base::ConditionVariable output_changed_;
201 SkColor picture_color_;
202 bool error_encountered_; 354 bool error_encountered_;
355 SkColor wait_color_;
203 356
204 DISALLOW_COPY_AND_ASSIGN(StubConsumer); 357 DISALLOW_COPY_AND_ASSIGN(StubConsumer);
205 }; 358 };
206 359
360 } // namespace
361
207 // Test harness that sets up a minimal environment with necessary stubs. 362 // Test harness that sets up a minimal environment with necessary stubs.
208 class WebContentsVideoCaptureDeviceTest : public testing::Test { 363 class WebContentsVideoCaptureDeviceTest : public testing::Test {
209 public: 364 public:
210 WebContentsVideoCaptureDeviceTest() {} 365 WebContentsVideoCaptureDeviceTest() {}
211 366
212 protected: 367 protected:
213 virtual void SetUp() { 368 virtual void SetUp() {
214 // This is a MessageLoop for the current thread. The MockRenderProcessHost 369 // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
215 // will schedule its destruction in this MessageLoop during TearDown(). 370 // eliminated here, if only we could use RenderViewHostTestHarness. The
216 message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO)); 371 // catch is that we need our TestRenderViewHost to support a
372 // CopyFromBackingStore operation that we control. To accomplish that,
373 // either RenderViewHostTestHarness would have to support installing a
374 // custom RenderViewHostFactory, or else we implant some kind of delegated
375 // CopyFromBackingStore functionality into TestRenderViewHost itself.
217 376
218 // The CopyFromBackingStore and WebContents tracking occur on the UI thread. 377 // The main thread will serve as the UI thread as well as the test thread.
219 ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI)); 378 // We'll manually pump the run loop at appropriate times in the test.
220 ui_thread_->Start(); 379 ui_thread_.reset(new TestBrowserThread(BrowserThread::UI, &message_loop_));
221 380
222 // And the rest... 381 render_process_host_factory_.reset(new MockRenderProcessHostFactory());
382 // Create our (self-registering) RVH factory, so that when we create a
383 // WebContents, it in turn creates CaptureTestRenderViewHosts.
384 render_view_host_factory_.reset(
385 new CaptureTestRenderViewHostFactory(&controller_));
386
223 browser_context_.reset(new TestBrowserContext()); 387 browser_context_.reset(new TestBrowserContext());
224 source_.reset(new StubRenderWidgetHost( 388
225 new MockRenderProcessHost(browser_context_.get()), MSG_ROUTING_NONE)); 389 scoped_refptr<SiteInstance> site_instance =
226 destroyed_.reset(new base::WaitableEvent(true, false)); 390 SiteInstance::Create(browser_context_.get());
227 device_.reset(WebContentsVideoCaptureDevice::CreateForTesting( 391 static_cast<SiteInstanceImpl*>(site_instance.get())->
228 source_.get(), 392 set_render_process_host_factory(render_process_host_factory_.get());
229 base::Bind(&base::WaitableEvent::Signal, 393 web_contents_.reset(
230 base::Unretained(destroyed_.get())))); 394 TestWebContents::Create(browser_context_.get(), site_instance));
231 consumer_.reset(new StubConsumer); 395
396 // This is actually a CaptureTestRenderViewHost.
397 RenderWidgetHostImpl* rwh =
398 RenderWidgetHostImpl::From(web_contents_->GetRenderViewHost());
399
400 std::string device_id =
401 WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
402 base::StringPrintf("%d:%d", rwh->GetProcess()->GetID(),
403 rwh->GetRoutingID()));
404
405 base::Closure destroy_cb = base::Bind(
406 &CaptureTestSourceController::OnShutdown,
407 base::Unretained(&controller_));
408
409 device_.reset(WebContentsVideoCaptureDevice::Create(device_id, destroy_cb));
232 } 410 }
233 411
234 virtual void TearDown() { 412 virtual void TearDown() {
235 // Tear down in opposite order of set-up. 413 // Tear down in opposite order of set-up.
236 device_->DeAllocate(); // Guarantees no more use of consumer_. 414
237 consumer_.reset(); 415 // The device is destroyed asynchronously, and will notify the
238 device_.reset(); // Release reference to internal CaptureMachine. 416 // CaptureTestSourceController when it finishes destruction.
239 message_loop_->RunUntilIdle(); // Just in case. 417 // Trigger this, and wait.
240 destroyed_->Wait(); // Wait until CaptureMachine is fully destroyed. 418 base::RunLoop shutdown_loop;
241 destroyed_.reset(); 419 controller_.SetShutdownHook(shutdown_loop.QuitClosure());
242 source_.reset(); 420 device_->DeAllocate();
421 device_.reset();
422 shutdown_loop.Run();
423
424 // Destroy the browser objects.
425 web_contents_.reset();
243 browser_context_.reset(); 426 browser_context_.reset();
244 ui_thread_->Stop(); 427
245 ui_thread_.reset(); 428 content::RunAllPendingInMessageLoop();
246 message_loop_->RunUntilIdle(); // Deletes MockRenderProcessHost. 429
247 message_loop_.reset(); 430 render_view_host_factory_.reset();
431 render_process_host_factory_.reset();
248 } 432 }
249 433
250 // Accessors. 434 // Accessors.
251 StubRenderWidgetHost* source() const { return source_.get(); } 435 CaptureTestSourceController* source() { return &controller_; }
252 media::VideoCaptureDevice* device() const { return device_.get(); } 436 media::VideoCaptureDevice* device() { return device_.get(); }
253 StubConsumer* consumer() const { return consumer_.get(); } 437 StubConsumer* consumer() { return &consumer_; }
254 438
255 private: 439 private:
256 scoped_ptr<MessageLoop> message_loop_; 440 // The consumer is the ultimate recipient of captured pixel data.
257 scoped_ptr<BrowserThreadImpl> ui_thread_; 441 StubConsumer consumer_;
442
443 // The controller controls which pixel patterns to produce.
444 CaptureTestSourceController controller_;
445
446 // We run the UI message loop on the main thread. The capture device
447 // will also spin up its own threads.
448 MessageLoopForUI message_loop_;
449 scoped_ptr<TestBrowserThread> ui_thread_;
450
451 // Self-registering RenderProcessHostFactory.
452 scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
453
454 // Creates capture-capable RenderViewHosts whose pixel content production is
455 // under the control of |controller_|.
456 scoped_ptr<CaptureTestRenderViewHostFactory> render_view_host_factory_;
457
458 // A mocked-out browser and tab.
258 scoped_ptr<TestBrowserContext> browser_context_; 459 scoped_ptr<TestBrowserContext> browser_context_;
259 scoped_ptr<StubRenderWidgetHost> source_; 460 scoped_ptr<WebContents> web_contents_;
260 scoped_ptr<base::WaitableEvent> destroyed_; 461
462 // Finally, the WebContentsVideoCaptureDevice under test.
261 scoped_ptr<media::VideoCaptureDevice> device_; 463 scoped_ptr<media::VideoCaptureDevice> device_;
262 scoped_ptr<StubConsumer> consumer_;
263 464
264 DISALLOW_COPY_AND_ASSIGN(WebContentsVideoCaptureDeviceTest); 465 DISALLOW_COPY_AND_ASSIGN(WebContentsVideoCaptureDeviceTest);
265 }; 466 };
266 467
267 // The "happy case" test. No scaling is needed, so we should be able to change 468 // The "happy case" test. No scaling is needed, so we should be able to change
268 // the picture emitted from the source and expect to see each delivered to the 469 // the picture emitted from the source and expect to see each delivered to the
269 // consumer. The test will alternate between the SkBitmap and the VideoFrame 470 // consumer. The test will alternate between the SkBitmap and the VideoFrame
270 // paths, just as RenderWidgetHost might if the content falls in and out of 471 // paths, just as RenderWidgetHost might if the content falls in and out of
271 // accelerated compositing. 472 // accelerated compositing.
272 TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) { 473 TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
273 device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, 474 device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer());
274 consumer());
275 475
276 device()->Start(); 476 device()->Start();
277 477
278 bool use_video_frames = false; 478 bool use_video_frames = false;
279 for (int i = 0; i < 4; i++, use_video_frames = !use_video_frames) { 479 for (int i = 0; i < 4; i++, use_video_frames = !use_video_frames) {
280 SCOPED_TRACE( 480 SCOPED_TRACE(StringPrintf("Using %s path, iteration #%d",
281 testing::Message() << "Using " 481 use_video_frames ? "VideoFrame" : "SkBitmap", i));
282 << (use_video_frames ? "VideoFrame" : "SkBitmap") 482 source()->SetCanCopyToVideoFrame(use_video_frames);
283 << " path, iteration #" << i);
284 // TODO(nick): Implement this.
285 // source()->SetUseVideoFrames(use_video_frames);
286 source()->SetSolidColor(SK_ColorRED); 483 source()->SetSolidColor(SK_ColorRED);
287 source()->WaitForNextBackingStoreCopy(); 484 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
288 ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorRED)); 485 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
289 source()->SetSolidColor(SK_ColorGREEN); 486 source()->SetSolidColor(SK_ColorGREEN);
290 ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorGREEN)); 487 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
291 source()->SetSolidColor(SK_ColorBLUE); 488 source()->SetSolidColor(SK_ColorBLUE);
292 ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorBLUE)); 489 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLUE));
293 source()->SetSolidColor(SK_ColorBLACK); 490 source()->SetSolidColor(SK_ColorBLACK);
294 ASSERT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorBLACK)); 491 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorBLACK));
295 } 492 }
296 493
297 device()->DeAllocate(); 494 device()->DeAllocate();
298 } 495 }
299 496
300 TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) { 497 TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) {
301 device()->Allocate(1280, 720, -2, consumer()); 498 device()->Allocate(1280, 720, -2, consumer());
302 EXPECT_FALSE(consumer()->WaitForNextColorOrError(kNotInterested)); 499 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForError());
303 } 500 }
304 501
305 TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) { 502 TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
306 device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, 503 device()->Allocate(kTestWidth, kTestHeight, kTestFramesPerSecond, consumer());
307 consumer());
308
309 504
310 // 1x1 is too small to process; we intend for this to result in an error. 505 // 1x1 is too small to process; we intend for this to result in an error.
311 source()->SetCopyResultSize(1, 1); 506 source()->SetCopyResultSize(1, 1);
312 source()->SetSolidColor(SK_ColorRED); 507 source()->SetSolidColor(SK_ColorRED);
313 device()->Start(); 508 device()->Start();
314 509
315 // These frames ought to be dropped during the Render stage. Let 510 // These frames ought to be dropped during the Render stage. Let
316 // several captures to happen. 511 // several captures to happen.
317 ASSERT_TRUE(source()->WaitForNextBackingStoreCopy()); 512 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
318 ASSERT_TRUE(source()->WaitForNextBackingStoreCopy()); 513 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
319 ASSERT_TRUE(source()->WaitForNextBackingStoreCopy()); 514 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
320 ASSERT_TRUE(source()->WaitForNextBackingStoreCopy()); 515 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
321 ASSERT_TRUE(source()->WaitForNextBackingStoreCopy()); 516 ASSERT_NO_FATAL_FAILURE(source()->WaitForNextBackingStoreCopy());
322 517
323 // Now push some good frames through; they should be processed normally. 518 // Now push some good frames through; they should be processed normally.
324 source()->SetCopyResultSize(kTestWidth, kTestHeight); 519 source()->SetCopyResultSize(kTestWidth, kTestHeight);
325 source()->SetSolidColor(SK_ColorGREEN); 520 source()->SetSolidColor(SK_ColorGREEN);
326 EXPECT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorGREEN)); 521 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorGREEN));
327 source()->SetSolidColor(SK_ColorRED); 522 source()->SetSolidColor(SK_ColorRED);
328 EXPECT_TRUE(consumer()->WaitForNextColorOrError(SK_ColorRED)); 523 ASSERT_NO_FATAL_FAILURE(consumer()->WaitForNextColor(SK_ColorRED));
524
525 device()->Stop();
329 device()->DeAllocate(); 526 device()->DeAllocate();
330 } 527 }
331 528
332 } // namespace content 529 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698