Index: content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
index d089f630a6f417b832ff7a3695518a569903c72a..dfa654843f8986525d0c5b97d0c879bc5a4fcd5d 100644
|
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
|
@@ -22,6 +22,8 @@
|
#include "content/browser/renderer_host/render_view_host_factory.h"
|
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
#include "content/browser/web_contents/web_contents_impl.h"
|
+#include "content/public/browser/notification_service.h"
|
+#include "content/public/browser/notification_types.h"
|
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
|
#include "content/public/browser/web_contents_media_capture_id.h"
|
#include "content/public/test/mock_render_process_host.h"
|
@@ -58,8 +60,7 @@
|
|
void DeadlineExceeded(base::Closure quit_closure) {
|
if (!base::debug::BeingDebugged()) {
|
- if (!quit_closure.is_null())
|
- quit_closure.Run();
|
+ quit_closure.Run();
|
FAIL() << "Deadline exceeded while waiting, quitting";
|
} else {
|
LOG(WARNING) << "Deadline exceeded; test would fail if debugger weren't "
|
@@ -93,7 +94,8 @@
|
CaptureTestSourceController()
|
: color_(SK_ColorMAGENTA),
|
copy_result_size_(kTestWidth, kTestHeight),
|
- can_copy_to_video_frame_(true) {}
|
+ can_copy_to_video_frame_(false),
|
+ use_frame_subscriber_(false) {}
|
|
void SetSolidColor(SkColor color) {
|
base::AutoLock guard(lock_);
|
@@ -134,6 +136,16 @@
|
return can_copy_to_video_frame_;
|
}
|
|
+ void SetUseFrameSubscriber(bool value) {
|
+ base::AutoLock guard(lock_);
|
+ use_frame_subscriber_ = value;
|
+ }
|
+
|
+ bool CanUseFrameSubscriber() {
|
+ base::AutoLock guard(lock_);
|
+ return use_frame_subscriber_;
|
+ }
|
+
|
void WaitForNextCopy() {
|
{
|
base::AutoLock guard(lock_);
|
@@ -148,6 +160,7 @@
|
SkColor color_;
|
gfx::Size copy_result_size_;
|
bool can_copy_to_video_frame_;
|
+ bool use_frame_subscriber_;
|
base::Closure copy_done_;
|
|
DISALLOW_COPY_AND_ASSIGN(CaptureTestSourceController);
|
@@ -474,7 +487,8 @@
|
public:
|
StubClientObserver()
|
: error_encountered_(false),
|
- wait_color_yuv_(0xcafe1950) {
|
+ wait_color_yuv_(0xcafe1950),
|
+ wait_size_(kTestWidth, kTestHeight) {
|
client_.reset(new StubClient(
|
base::Bind(&StubClientObserver::DidDeliverFrame,
|
base::Unretained(this)),
|
@@ -489,35 +503,28 @@
|
|
void QuitIfConditionsMet(SkColor color, const gfx::Size& size) {
|
base::AutoLock guard(lock_);
|
- if (error_encountered_ || wait_color_yuv_ == kNotInterested ||
|
- wait_color_yuv_ == color) {
|
- last_frame_color_yuv_ = color;
|
- last_frame_size_ = size;
|
+ if (error_encountered_)
|
base::MessageLoop::current()->QuitWhenIdle();
|
- }
|
- }
|
-
|
- // Run the current loop until the next frame is delivered. Returns the YUV
|
- // color and frame size.
|
- std::pair<SkColor, gfx::Size> WaitForNextFrame() {
|
- {
|
- base::AutoLock guard(lock_);
|
- wait_color_yuv_ = kNotInterested;
|
- error_encountered_ = false;
|
- }
|
- RunCurrentLoopWithDeadline();
|
- {
|
- base::AutoLock guard(lock_);
|
- CHECK(!error_encountered_);
|
- return std::make_pair(last_frame_color_yuv_, last_frame_size_);
|
- }
|
- }
|
-
|
- // Run the current loop until a frame is delivered with the |expected_color|.
|
+ else if (wait_color_yuv_ == color && wait_size_.IsEmpty())
|
+ base::MessageLoop::current()->QuitWhenIdle();
|
+ else if (wait_color_yuv_ == color && wait_size_ == size)
|
+ base::MessageLoop::current()->QuitWhenIdle();
|
+ }
|
+
|
+ // Run the current loop until a frame is delivered with the |expected_color|
|
+ // and any non-empty frame size.
|
void WaitForNextColor(SkColor expected_color) {
|
+ WaitForNextColorAndFrameSize(expected_color, gfx::Size());
|
+ }
|
+
|
+ // Run the current loop until a frame is delivered with the |expected_color|
|
+ // and is of the |expected_size|.
|
+ void WaitForNextColorAndFrameSize(SkColor expected_color,
|
+ const gfx::Size& expected_size) {
|
{
|
base::AutoLock guard(lock_);
|
wait_color_yuv_ = ConvertRgbToYuv(expected_color);
|
+ wait_size_ = expected_size;
|
error_encountered_ = false;
|
}
|
RunCurrentLoopWithDeadline();
|
@@ -531,6 +538,7 @@
|
{
|
base::AutoLock guard(lock_);
|
wait_color_yuv_ = kNotInterested;
|
+ wait_size_ = gfx::Size();
|
error_encountered_ = false;
|
}
|
RunCurrentLoopWithDeadline();
|
@@ -569,8 +577,7 @@
|
base::Lock lock_;
|
bool error_encountered_;
|
SkColor wait_color_yuv_;
|
- SkColor last_frame_color_yuv_;
|
- gfx::Size last_frame_size_;
|
+ gfx::Size wait_size_;
|
scoped_ptr<StubClient> client_;
|
|
DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
|
@@ -679,30 +686,19 @@
|
}
|
|
void SimulateDrawEvent() {
|
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
-
|
- // Force at least one frame period's worth of time to pass. Otherwise,
|
- // internal logic may decide not to capture a frame because the draw events
|
- // are more frequent that kTestFramesPerSecond.
|
- //
|
- // TODO(miu): Instead of physically waiting, we should inject simulated
|
- // clocks for testing.
|
- base::RunLoop run_loop;
|
- BrowserThread::PostDelayedTask(
|
- BrowserThread::UI, FROM_HERE,
|
- run_loop.QuitClosure(),
|
- base::TimeDelta::FromMicroseconds(
|
- base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
|
- run_loop.Run();
|
-
|
- // Schedule the update to occur when the test runs the event loop (and not
|
- // before expectations have been set).
|
- CaptureTestView* test_view = static_cast<CaptureTestView*>(
|
- web_contents_->GetRenderViewHost()->GetWidget()->GetView());
|
- BrowserThread::PostTask(
|
- BrowserThread::UI, FROM_HERE,
|
- base::Bind(&CaptureTestView::SimulateUpdate,
|
- base::Unretained(test_view)));
|
+ if (source()->CanUseFrameSubscriber()) {
|
+ // Print
|
+ CaptureTestView* test_view = static_cast<CaptureTestView*>(
|
+ web_contents_->GetRenderViewHost()->GetWidget()->GetView());
|
+ test_view->SimulateUpdate();
|
+ } else {
|
+ // Simulate a non-accelerated paint.
|
+ NotificationService::current()->Notify(
|
+ NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
|
+ Source<RenderWidgetHost>(
|
+ web_contents_->GetRenderViewHost()->GetWidget()),
|
+ NotificationService::NoDetails());
|
+ }
|
}
|
|
void SimulateSourceSizeChange(const gfx::Size& size) {
|
@@ -721,45 +717,6 @@
|
as_web_contents_impl->GetMainFrame()->GetRenderWidgetHost(), true);
|
}
|
|
- // Repeatedly schedules draw events and scans for frames until the output from
|
- // the capture device matches the given RGB |color| and frame |size|.
|
- void SimulateDrawsUntilNewFrameSizeArrives(SkColor color,
|
- const gfx::Size& size) {
|
- const base::TimeTicks start_time = base::TimeTicks::Now();
|
- while ((base::TimeTicks::Now() - start_time) <
|
- TestTimeouts::action_max_timeout()) {
|
- SimulateDrawEvent();
|
- const auto color_and_size = client_observer()->WaitForNextFrame();
|
- if (color_and_size.first == ConvertRgbToYuv(color) &&
|
- color_and_size.second == size) {
|
- return;
|
- }
|
- }
|
- DeadlineExceeded(base::Closure());
|
- }
|
-
|
- void SimulateRefreshFrameRequest() {
|
- // Force at least three frame period's worth of time to pass. The wait is
|
- // needed because refresh frame requests are only honored when drawing
|
- // events, which trigger frame captures, are not occurring frequently
|
- // enough.
|
- //
|
- // TODO(miu): Instead of physically waiting, we should inject simulated
|
- // clocks for testing.
|
- base::RunLoop run_loop;
|
- BrowserThread::PostDelayedTask(
|
- BrowserThread::UI, FROM_HERE,
|
- run_loop.QuitClosure(),
|
- base::TimeDelta::FromMicroseconds(
|
- 3 * base::Time::kMicrosecondsPerSecond / kTestFramesPerSecond));
|
- run_loop.Run();
|
-
|
- BrowserThread::PostTask(
|
- BrowserThread::UI, FROM_HERE,
|
- base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame,
|
- base::Unretained(device_.get())));
|
- }
|
-
|
void DestroyVideoCaptureDevice() { device_.reset(); }
|
|
StubClientObserver* client_observer() {
|
@@ -824,9 +781,7 @@
|
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
-
|
- // Do one capture to prove the tab is initially open and being captured
|
- // normally.
|
+ // Do one capture to prove
|
source()->SetSolidColor(SK_ColorRED);
|
SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
@@ -866,9 +821,9 @@
|
}
|
|
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
|
- // Set up the test to use RGB captures into SkBitmaps instead of YUV captures
|
- // into VideoFrames.
|
+ // Set up the test to use RGB copies and an normal
|
source()->SetCanCopyToVideoFrame(false);
|
+ source()->SetUseFrameSubscriber(false);
|
media::VideoCaptureParams capture_params;
|
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
@@ -877,7 +832,7 @@
|
|
base::RunLoop().RunUntilIdle();
|
|
- for (int i = 0; i < 3; ++i)
|
+ for (int i = 0; i < 10; ++i)
|
SimulateDrawEvent();
|
|
ASSERT_FALSE(client_observer()->HasError());
|
@@ -923,8 +878,8 @@
|
|
// The "happy case" test. No scaling is needed, so we should be able to change
|
// the picture emitted from the source and expect to see each delivered to the
|
-// consumer. The test will alternate between the RGB/SkBitmap and YUV/VideoFrame
|
-// capture paths.
|
+// consumer. The test will alternate between the three capture paths, simulating
|
+// falling in and out of accelerated compositing.
|
TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
|
media::VideoCaptureParams capture_params;
|
capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
@@ -932,14 +887,26 @@
|
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
- for (int i = 0; i < 4; i++) {
|
+ for (int i = 0; i < 6; i++) {
|
const char* name = NULL;
|
- if (i % 2) {
|
- source()->SetCanCopyToVideoFrame(false);
|
- name = "SkBitmap";
|
- } else {
|
- source()->SetCanCopyToVideoFrame(true);
|
- name = "VideoFrame";
|
+ switch (i % 3) {
|
+ case 0:
|
+ source()->SetCanCopyToVideoFrame(true);
|
+ source()->SetUseFrameSubscriber(false);
|
+ name = "VideoFrame";
|
+ break;
|
+ case 1:
|
+ source()->SetCanCopyToVideoFrame(false);
|
+ source()->SetUseFrameSubscriber(true);
|
+ name = "Subscriber";
|
+ break;
|
+ case 2:
|
+ source()->SetCanCopyToVideoFrame(false);
|
+ source()->SetUseFrameSubscriber(false);
|
+ name = "SkBitmap";
|
+ break;
|
+ default:
|
+ FAIL();
|
}
|
|
SCOPED_TRACE(base::StringPrintf("Using %s path, iteration #%d", name, i));
|
@@ -975,18 +942,17 @@
|
|
// These frames ought to be dropped during the Render stage. Let
|
// several captures to happen.
|
- for (int i = 0; i < 3; ++i) {
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
- }
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
+ ASSERT_NO_FATAL_FAILURE(source()->WaitForNextCopy());
|
|
// Now push some good frames through; they should be processed normally.
|
source()->SetCopyResultSize(kTestWidth, kTestHeight);
|
source()->SetSolidColor(SK_ColorGREEN);
|
- SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
source()->SetSolidColor(SK_ColorRED);
|
- SimulateDrawEvent();
|
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
|
device()->StopAndDeAllocate();
|
@@ -1006,14 +972,17 @@
|
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
+ source()->SetUseFrameSubscriber(true);
|
+
|
// Source size equals maximum size. Expect delivered frames to be
|
// kTestWidth by kTestHeight.
|
source()->SetSolidColor(SK_ColorRED);
|
const float device_scale_factor = GetDeviceScaleFactor();
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
|
|
// Source size is half in both dimensions. Expect delivered frames to be of
|
// the same aspect ratio as kTestWidth by kTestHeight, but larger than the
|
@@ -1021,24 +990,27 @@
|
source()->SetSolidColor(SK_ColorGREEN);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorGREEN, gfx::Size(180 * kTestWidth / kTestHeight, 180)));
|
|
// Source size changes aspect ratio. Expect delivered frames to be padded
|
// in the horizontal dimension to preserve aspect ratio.
|
source()->SetSolidColor(SK_ColorBLUE);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorBLUE, gfx::Size(kTestWidth, kTestHeight)));
|
|
// Source size changes aspect ratio again. Expect delivered frames to be
|
// padded in the vertical dimension to preserve aspect ratio.
|
source()->SetSolidColor(SK_ColorBLACK);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight / 2)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorBLACK, gfx::Size(kTestWidth, kTestHeight)));
|
|
device()->StopAndDeAllocate();
|
}
|
@@ -1057,22 +1029,26 @@
|
|
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
|
+ source()->SetUseFrameSubscriber(true);
|
+
|
// Source size equals maximum size. Expect delivered frames to be
|
// kTestWidth by kTestHeight.
|
source()->SetSolidColor(SK_ColorRED);
|
const float device_scale_factor = GetDeviceScaleFactor();
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth, kTestHeight)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorRED, gfx::Size(kTestWidth, kTestHeight));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorRED, gfx::Size(kTestWidth, kTestHeight)));
|
|
// Source size is half in both dimensions. Expect delivered frames to also
|
// be half in both dimensions.
|
source()->SetSolidColor(SK_ColorGREEN);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(
|
device_scale_factor, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
- SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2));
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorGREEN, gfx::Size(kTestWidth / 2, kTestHeight / 2)));
|
|
// Source size changes to something arbitrary. Since the source size is
|
// less than the maximum size, expect delivered frames to be the same size
|
@@ -1081,7 +1057,9 @@
|
gfx::Size arbitrary_source_size(kTestWidth / 2 + 42, kTestHeight - 10);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
|
arbitrary_source_size));
|
- SimulateDrawsUntilNewFrameSizeArrives(SK_ColorBLUE, arbitrary_source_size);
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
+ SK_ColorBLUE, arbitrary_source_size));
|
|
// Source size changes to something arbitrary that exceeds the maximum frame
|
// size. Since the source size exceeds the maximum size, expect delivered
|
@@ -1090,10 +1068,11 @@
|
arbitrary_source_size = gfx::Size(kTestWidth * 2, kTestHeight / 2);
|
SimulateSourceSizeChange(gfx::ConvertSizeToDIP(device_scale_factor,
|
arbitrary_source_size));
|
- SimulateDrawsUntilNewFrameSizeArrives(
|
+ SimulateDrawEvent();
|
+ ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColorAndFrameSize(
|
SK_ColorBLACK, gfx::Size(kTestWidth,
|
kTestWidth * arbitrary_source_size.height() /
|
- arbitrary_source_size.width()));
|
+ arbitrary_source_size.width())));
|
|
device()->StopAndDeAllocate();
|
}
|
@@ -1192,36 +1171,5 @@
|
}
|
}
|
|
-// Tests the RequestRefreshFrame() functionality.
|
-TEST_F(MAYBE_WebContentsVideoCaptureDeviceTest, ProvidesRefreshFrames) {
|
- media::VideoCaptureParams capture_params;
|
- capture_params.requested_format.frame_size.SetSize(kTestWidth, kTestHeight);
|
- capture_params.requested_format.frame_rate = kTestFramesPerSecond;
|
- capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
|
- device()->AllocateAndStart(capture_params, client_observer()->PassClient());
|
-
|
- // Request a refresh frame before the first frame has been drawn. This forces
|
- // a capture.
|
- source()->SetSolidColor(SK_ColorRED);
|
- SimulateRefreshFrameRequest();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorRED));
|
-
|
- // Now, draw a frame and wait for a normal frame capture to occur.
|
- source()->SetSolidColor(SK_ColorGREEN);
|
- SimulateDrawEvent();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
-
|
- // Now, make three more refresh frame requests. Although the source has
|
- // changed to BLUE, no draw event has occurred. Therefore, expect the refresh
|
- // frames to contain the content from the last drawn frame, which is GREEN.
|
- source()->SetSolidColor(SK_ColorBLUE);
|
- for (int i = 0; i < 3; ++i) {
|
- SimulateRefreshFrameRequest();
|
- ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForNextColor(SK_ColorGREEN));
|
- }
|
-
|
- device()->StopAndDeAllocate();
|
-}
|
-
|
} // namespace
|
} // namespace content
|
|