OLD | NEW |
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/media/capture/web_contents_video_capture_device.h" | 5 #include "content/browser/media/capture/web_contents_video_capture_device.h" |
6 | 6 |
7 #include "base/bind_helpers.h" | 7 #include "base/bind_helpers.h" |
8 #include "base/debug/debugger.h" | 8 #include "base/debug/debugger.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "base/test/test_timeouts.h" | 10 #include "base/test/test_timeouts.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include "content/public/test/test_utils.h" | 25 #include "content/public/test/test_utils.h" |
26 #include "content/test/test_render_view_host.h" | 26 #include "content/test/test_render_view_host.h" |
27 #include "content/test/test_web_contents.h" | 27 #include "content/test/test_web_contents.h" |
28 #include "media/base/video_frame.h" | 28 #include "media/base/video_frame.h" |
29 #include "media/base/video_util.h" | 29 #include "media/base/video_util.h" |
30 #include "media/base/yuv_convert.h" | 30 #include "media/base/yuv_convert.h" |
31 #include "media/video/capture/video_capture_types.h" | 31 #include "media/video/capture/video_capture_types.h" |
32 #include "skia/ext/platform_canvas.h" | 32 #include "skia/ext/platform_canvas.h" |
33 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
34 #include "third_party/skia/include/core/SkColor.h" | 34 #include "third_party/skia/include/core/SkColor.h" |
| 35 #include "ui/gfx/display.h" |
| 36 #include "ui/gfx/screen.h" |
35 | 37 |
36 namespace content { | 38 namespace content { |
37 namespace { | 39 namespace { |
38 | 40 |
39 const int kTestWidth = 320; | 41 const int kTestWidth = 320; |
40 const int kTestHeight = 240; | 42 const int kTestHeight = 240; |
41 const int kTestFramesPerSecond = 20; | 43 const int kTestFramesPerSecond = 20; |
| 44 const float kTestDeviceScaleFactor = 2.0f; |
42 const SkColor kNothingYet = 0xdeadbeef; | 45 const SkColor kNothingYet = 0xdeadbeef; |
43 const SkColor kNotInterested = ~kNothingYet; | 46 const SkColor kNotInterested = ~kNothingYet; |
44 | 47 |
45 void DeadlineExceeded(base::Closure quit_closure) { | 48 void DeadlineExceeded(base::Closure quit_closure) { |
46 if (!base::debug::BeingDebugged()) { | 49 if (!base::debug::BeingDebugged()) { |
47 quit_closure.Run(); | 50 quit_closure.Run(); |
48 FAIL() << "Deadline exceeded while waiting, quitting"; | 51 FAIL() << "Deadline exceeded while waiting, quitting"; |
49 } else { | 52 } else { |
50 LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't " | 53 LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't " |
51 << "attached."; | 54 << "attached."; |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 | 462 |
460 private: | 463 private: |
461 base::Lock lock_; | 464 base::Lock lock_; |
462 bool error_encountered_; | 465 bool error_encountered_; |
463 SkColor wait_color_yuv_; | 466 SkColor wait_color_yuv_; |
464 scoped_ptr<StubClient> client_; | 467 scoped_ptr<StubClient> client_; |
465 | 468 |
466 DISALLOW_COPY_AND_ASSIGN(StubClientObserver); | 469 DISALLOW_COPY_AND_ASSIGN(StubClientObserver); |
467 }; | 470 }; |
468 | 471 |
| 472 // A dummy implementation of gfx::Screen, since WebContentsVideoCaptureDevice |
| 473 // needs access to a gfx::Display's device scale factor. |
| 474 class FakeScreen : public gfx::Screen { |
| 475 public: |
| 476 FakeScreen() : the_one_display_(0x1337, gfx::Rect(0, 0, 2560, 1440)) { |
| 477 the_one_display_.set_device_scale_factor(kTestDeviceScaleFactor); |
| 478 } |
| 479 virtual ~FakeScreen() {} |
| 480 |
| 481 // gfx::Screen implementation (only what's needed for testing). |
| 482 virtual bool IsDIPEnabled() OVERRIDE { return true; } |
| 483 virtual gfx::Point GetCursorScreenPoint() OVERRIDE { return gfx::Point(); } |
| 484 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { return NULL; } |
| 485 virtual gfx::NativeWindow GetWindowAtScreenPoint( |
| 486 const gfx::Point& point) OVERRIDE { return NULL; } |
| 487 virtual int GetNumDisplays() const OVERRIDE { return 1; } |
| 488 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { |
| 489 return std::vector<gfx::Display>(1, the_one_display_); |
| 490 } |
| 491 virtual gfx::Display GetDisplayNearestWindow( |
| 492 gfx::NativeView view) const OVERRIDE { |
| 493 return the_one_display_; |
| 494 } |
| 495 virtual gfx::Display GetDisplayNearestPoint( |
| 496 const gfx::Point& point) const OVERRIDE { |
| 497 return the_one_display_; |
| 498 } |
| 499 virtual gfx::Display GetDisplayMatching( |
| 500 const gfx::Rect& match_rect) const OVERRIDE { |
| 501 return the_one_display_; |
| 502 } |
| 503 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { |
| 504 return the_one_display_; |
| 505 } |
| 506 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {} |
| 507 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {} |
| 508 |
| 509 private: |
| 510 gfx::Display the_one_display_; |
| 511 |
| 512 DISALLOW_COPY_AND_ASSIGN(FakeScreen); |
| 513 }; |
| 514 |
469 // Test harness that sets up a minimal environment with necessary stubs. | 515 // Test harness that sets up a minimal environment with necessary stubs. |
470 class WebContentsVideoCaptureDeviceTest : public testing::Test { | 516 class WebContentsVideoCaptureDeviceTest : public testing::Test { |
471 public: | 517 public: |
472 // This is public because C++ method pointer scoping rules are silly and make | 518 // This is public because C++ method pointer scoping rules are silly and make |
473 // this hard to use with Bind(). | 519 // this hard to use with Bind(). |
474 void ResetWebContents() { | 520 void ResetWebContents() { |
475 web_contents_.reset(); | 521 web_contents_.reset(); |
476 } | 522 } |
477 | 523 |
478 protected: | 524 protected: |
479 virtual void SetUp() { | 525 virtual void SetUp() { |
| 526 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, &fake_screen_); |
| 527 ASSERT_EQ(&fake_screen_, gfx::Screen::GetNativeScreen()); |
| 528 |
480 // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be | 529 // TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be |
481 // eliminated here, if only we could use RenderViewHostTestHarness. The | 530 // eliminated here, if only we could use RenderViewHostTestHarness. The |
482 // catch is that we need our TestRenderViewHost to support a | 531 // catch is that we need our TestRenderViewHost to support a |
483 // CopyFromBackingStore operation that we control. To accomplish that, | 532 // CopyFromBackingStore operation that we control. To accomplish that, |
484 // either RenderViewHostTestHarness would have to support installing a | 533 // either RenderViewHostTestHarness would have to support installing a |
485 // custom RenderViewHostFactory, or else we implant some kind of delegated | 534 // custom RenderViewHostFactory, or else we implant some kind of delegated |
486 // CopyFromBackingStore functionality into TestRenderViewHost itself. | 535 // CopyFromBackingStore functionality into TestRenderViewHost itself. |
487 | 536 |
488 render_process_host_factory_.reset(new MockRenderProcessHostFactory()); | 537 render_process_host_factory_.reset(new MockRenderProcessHostFactory()); |
489 // Create our (self-registering) RVH factory, so that when we create a | 538 // Create our (self-registering) RVH factory, so that when we create a |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 | 572 |
524 // Destroy the browser objects. | 573 // Destroy the browser objects. |
525 web_contents_.reset(); | 574 web_contents_.reset(); |
526 browser_context_.reset(); | 575 browser_context_.reset(); |
527 | 576 |
528 base::RunLoop().RunUntilIdle(); | 577 base::RunLoop().RunUntilIdle(); |
529 | 578 |
530 SiteInstanceImpl::set_render_process_host_factory(NULL); | 579 SiteInstanceImpl::set_render_process_host_factory(NULL); |
531 render_view_host_factory_.reset(); | 580 render_view_host_factory_.reset(); |
532 render_process_host_factory_.reset(); | 581 render_process_host_factory_.reset(); |
| 582 |
| 583 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, NULL); |
533 } | 584 } |
534 | 585 |
535 // Accessors. | 586 // Accessors. |
536 CaptureTestSourceController* source() { return &controller_; } | 587 CaptureTestSourceController* source() { return &controller_; } |
| 588 WebContents* web_contents() const { return web_contents_.get(); } |
537 media::VideoCaptureDevice* device() { return device_.get(); } | 589 media::VideoCaptureDevice* device() { return device_.get(); } |
538 | 590 |
539 void SimulateDrawEvent() { | 591 void SimulateDrawEvent() { |
540 if (source()->CanUseFrameSubscriber()) { | 592 if (source()->CanUseFrameSubscriber()) { |
541 // Print | 593 // Print |
542 CaptureTestView* test_view = static_cast<CaptureTestView*>( | 594 CaptureTestView* test_view = static_cast<CaptureTestView*>( |
543 web_contents_->GetRenderViewHost()->GetView()); | 595 web_contents_->GetRenderViewHost()->GetView()); |
544 test_view->SimulateUpdate(); | 596 test_view->SimulateUpdate(); |
545 } else { | 597 } else { |
546 // Simulate a non-accelerated paint. | 598 // Simulate a non-accelerated paint. |
547 NotificationService::current()->Notify( | 599 NotificationService::current()->Notify( |
548 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | 600 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, |
549 Source<RenderWidgetHost>(web_contents_->GetRenderViewHost()), | 601 Source<RenderWidgetHost>(web_contents_->GetRenderViewHost()), |
550 NotificationService::NoDetails()); | 602 NotificationService::NoDetails()); |
551 } | 603 } |
552 } | 604 } |
553 | 605 |
554 void DestroyVideoCaptureDevice() { device_.reset(); } | 606 void DestroyVideoCaptureDevice() { device_.reset(); } |
555 | 607 |
556 StubClientObserver* client_observer() { | 608 StubClientObserver* client_observer() { |
557 return &client_observer_; | 609 return &client_observer_; |
558 } | 610 } |
559 | 611 |
560 private: | 612 private: |
| 613 FakeScreen fake_screen_; |
| 614 |
561 StubClientObserver client_observer_; | 615 StubClientObserver client_observer_; |
562 | 616 |
563 // The controller controls which pixel patterns to produce. | 617 // The controller controls which pixel patterns to produce. |
564 CaptureTestSourceController controller_; | 618 CaptureTestSourceController controller_; |
565 | 619 |
566 // Self-registering RenderProcessHostFactory. | 620 // Self-registering RenderProcessHostFactory. |
567 scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_; | 621 scoped_ptr<MockRenderProcessHostFactory> render_process_host_factory_; |
568 | 622 |
569 // Creates capture-capable RenderViewHosts whose pixel content production is | 623 // Creates capture-capable RenderViewHosts whose pixel content production is |
570 // under the control of |controller_|. | 624 // under the control of |controller_|. |
(...skipping 19 matching lines...) Expand all Loading... |
590 capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); | 644 capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); |
591 capture_params.requested_format.frame_rate = kTestFramesPerSecond; | 645 capture_params.requested_format.frame_rate = kTestFramesPerSecond; |
592 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; | 646 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; |
593 capture_params.allow_resolution_change = false; | 647 capture_params.allow_resolution_change = false; |
594 device()->AllocateAndStart(capture_params, client_observer()->PassClient()); | 648 device()->AllocateAndStart(capture_params, client_observer()->PassClient()); |
595 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForError()); | 649 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForError()); |
596 device()->StopAndDeAllocate(); | 650 device()->StopAndDeAllocate(); |
597 } | 651 } |
598 | 652 |
599 TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) { | 653 TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) { |
| 654 const gfx::Size capture_preferred_size( |
| 655 static_cast<int>(kTestWidth / kTestDeviceScaleFactor), |
| 656 static_cast<int>(kTestHeight / kTestDeviceScaleFactor)); |
| 657 ASSERT_NE(capture_preferred_size, web_contents()->GetPreferredSize()); |
| 658 |
600 // We'll simulate the tab being closed after the capture pipeline is up and | 659 // We'll simulate the tab being closed after the capture pipeline is up and |
601 // running. | 660 // running. |
602 media::VideoCaptureParams capture_params; | 661 media::VideoCaptureParams capture_params; |
603 capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); | 662 capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight); |
604 capture_params.requested_format.frame_rate = kTestFramesPerSecond; | 663 capture_params.requested_format.frame_rate = kTestFramesPerSecond; |
605 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; | 664 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; |
606 capture_params.allow_resolution_change = false; | 665 capture_params.allow_resolution_change = false; |
607 device()->AllocateAndStart(capture_params, client_observer()->PassClient()); | 666 device()->AllocateAndStart(capture_params, client_observer()->PassClient()); |
608 // Do one capture to prove | 667 // Do one capture to prove |
609 source()->SetSolidColor(SK_ColorRED); | 668 source()->SetSolidColor(SK_ColorRED); |
610 SimulateDrawEvent(); | 669 SimulateDrawEvent(); |
611 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED)); | 670 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED)); |
612 | 671 |
613 base::RunLoop().RunUntilIdle(); | 672 base::RunLoop().RunUntilIdle(); |
614 | 673 |
| 674 // Check that the preferred size of the WebContents matches the one provided |
| 675 // by WebContentsVideoCaptureDevice. |
| 676 EXPECT_EQ(capture_preferred_size, web_contents()->GetPreferredSize()); |
| 677 |
615 // Post a task to close the tab. We should see an error reported to the | 678 // Post a task to close the tab. We should see an error reported to the |
616 // consumer. | 679 // consumer. |
617 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 680 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
618 base::Bind(&WebContentsVideoCaptureDeviceTest::ResetWebContents, | 681 base::Bind(&WebContentsVideoCaptureDeviceTest::ResetWebContents, |
619 base::Unretained(this))); | 682 base::Unretained(this))); |
620 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForError()); | 683 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForError()); |
621 device()->StopAndDeAllocate(); | 684 device()->StopAndDeAllocate(); |
622 } | 685 } |
623 | 686 |
624 TEST_F(WebContentsVideoCaptureDeviceTest, | 687 TEST_F(WebContentsVideoCaptureDeviceTest, |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
800 source()->SetSolidColor(SK_ColorGREEN); | 863 source()->SetSolidColor(SK_ColorGREEN); |
801 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN)); | 864 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN)); |
802 source()->SetSolidColor(SK_ColorRED); | 865 source()->SetSolidColor(SK_ColorRED); |
803 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED)); | 866 ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED)); |
804 | 867 |
805 device()->StopAndDeAllocate(); | 868 device()->StopAndDeAllocate(); |
806 } | 869 } |
807 | 870 |
808 } // namespace | 871 } // namespace |
809 } // namespace content | 872 } // namespace content |
OLD | NEW |