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

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

Powered by Google App Engine
This is Rietveld 408576698