Index: content/browser/renderer_host/media/video_capture_controller_unittest.cc |
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc |
index 18d6b94e760f36d8d05eb3d89ba95fef2805c4fd..fd6d419951a8aa44120a6b8de132bb4f206a5aba 100644 |
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc |
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc |
@@ -2,8 +2,6 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-// Unit test for VideoCaptureController. |
- |
#include "content/browser/renderer_host/media/video_capture_controller.h" |
#include <stdint.h> |
@@ -58,11 +56,15 @@ class MockVideoCaptureControllerEventHandler |
VideoCaptureController* controller) |
: controller_(controller), resource_utilization_(-1.0) {} |
~MockVideoCaptureControllerEventHandler() override {} |
+ void set_enable_auto_return_buffer_on_buffer_ready(bool enable) { |
+ enable_auto_return_buffer_on_buffer_ready_ = enable; |
+ } |
// These mock methods are delegated to by our fake implementation of |
// VideoCaptureControllerEventHandler, to be used in EXPECT_CALL(). |
- MOCK_METHOD1(DoBufferCreated, void(VideoCaptureControllerID)); |
- MOCK_METHOD1(DoBufferDestroyed, void(VideoCaptureControllerID)); |
+ MOCK_METHOD2(DoBufferCreated, void(VideoCaptureControllerID, int buffer_id)); |
+ MOCK_METHOD2(DoBufferDestroyed, |
+ void(VideoCaptureControllerID, int buffer_id)); |
MOCK_METHOD2(DoBufferReady, void(VideoCaptureControllerID, const gfx::Size&)); |
MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID)); |
MOCK_METHOD1(DoError, void(VideoCaptureControllerID)); |
@@ -72,10 +74,10 @@ class MockVideoCaptureControllerEventHandler |
mojo::ScopedSharedBufferHandle handle, |
int length, |
int buffer_id) override { |
- DoBufferCreated(id); |
+ DoBufferCreated(id, buffer_id); |
} |
void OnBufferDestroyed(VideoCaptureControllerID id, int buffer_id) override { |
- DoBufferDestroyed(id); |
+ DoBufferDestroyed(id, buffer_id); |
} |
void OnBufferReady(VideoCaptureControllerID id, |
int buffer_id, |
@@ -85,10 +87,12 @@ class MockVideoCaptureControllerEventHandler |
EXPECT_TRUE(frame->metadata()->GetTimeTicks( |
media::VideoFrameMetadata::REFERENCE_TIME, &reference_time)); |
DoBufferReady(id, frame->coded_size()); |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(&VideoCaptureController::ReturnBuffer, |
- base::Unretained(controller_), id, this, |
- buffer_id, resource_utilization_)); |
+ if (enable_auto_return_buffer_on_buffer_ready_) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&VideoCaptureController::ReturnBuffer, |
+ base::Unretained(controller_), id, this, |
+ buffer_id, resource_utilization_)); |
+ } |
} |
void OnEnded(VideoCaptureControllerID id) override { |
DoEnded(id); |
@@ -102,6 +106,7 @@ class MockVideoCaptureControllerEventHandler |
VideoCaptureController* controller_; |
media::VideoPixelFormat expected_pixel_format_ = media::PIXEL_FORMAT_I420; |
double resource_utilization_; |
+ bool enable_auto_return_buffer_on_buffer_ready_ = true; |
}; |
class MockConsumerFeedbackObserver |
@@ -117,31 +122,26 @@ class MockFrameBufferPool : public media::FrameBufferPool { |
MOCK_METHOD1(ReleaseBufferHold, void(int buffer_id)); |
}; |
-// Test class. |
+// Test fixture for testing a unit consisting of an instance of |
+// VideoCaptureController connected to an instance of VideoCaptureDeviceClient, |
+// an instance of VideoCaptureBufferPoolImpl, as well as related threading glue |
+// that replicates how it is used in production. |
class VideoCaptureControllerTest |
: public testing::Test, |
public testing::WithParamInterface<media::VideoPixelFormat> { |
public: |
- VideoCaptureControllerTest() {} |
+ VideoCaptureControllerTest() |
+ : arbitrary_format_(gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420), |
+ arbitrary_route_id_(0x99), |
+ arbitrary_session_id_(100) {} |
~VideoCaptureControllerTest() override {} |
protected: |
static const int kPoolSize = 3; |
void SetUp() override { |
- scoped_refptr<media::VideoCaptureBufferPool> buffer_pool( |
- new media::VideoCaptureBufferPoolImpl( |
- base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
- kPoolSize)); |
controller_.reset(new VideoCaptureController()); |
- device_client_.reset(new media::VideoCaptureDeviceClient( |
- base::MakeUnique<VideoFrameReceiverOnIOThread>( |
- controller_->GetWeakPtrForIOThread()), |
- buffer_pool, |
- base::Bind( |
- &CreateGpuJpegDecoder, |
- base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame, |
- controller_->GetWeakPtrForIOThread())))); |
+ InitializeNewDeviceClientAndBufferPoolInstances(); |
auto frame_receiver_observer = base::MakeUnique<MockFrameBufferPool>(); |
mock_frame_receiver_observer_ = frame_receiver_observer.get(); |
controller_->SetFrameBufferPool(std::move(frame_receiver_observer)); |
@@ -158,7 +158,37 @@ class VideoCaptureControllerTest |
void TearDown() override { base::RunLoop().RunUntilIdle(); } |
+ void InitializeNewDeviceClientAndBufferPoolInstances() { |
+ buffer_pool_ = new media::VideoCaptureBufferPoolImpl( |
+ base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
+ kPoolSize); |
+ device_client_.reset(new media::VideoCaptureDeviceClient( |
+ base::MakeUnique<VideoFrameReceiverOnIOThread>( |
+ controller_->GetWeakPtrForIOThread()), |
+ buffer_pool_, |
+ base::Bind( |
+ &CreateGpuJpegDecoder, |
+ base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame, |
+ controller_->GetWeakPtrForIOThread())))); |
+ } |
+ |
+ void SendStubFrameToDeviceClient(const media::VideoCaptureFormat format) { |
+ auto stub_frame = media::VideoFrame::CreateZeroInitializedFrame( |
+ format.pixel_format, format.frame_size, |
+ gfx::Rect(format.frame_size.width(), format.frame_size.height()), |
+ format.frame_size, base::TimeDelta()); |
+ const int rotation = 0; |
+ const int frame_feedback_id = 0; |
+ device_client_->OnIncomingCapturedData( |
+ stub_frame->data(0), |
+ media::VideoFrame::AllocationSize(stub_frame->format(), |
+ stub_frame->coded_size()), |
+ format, rotation, base::TimeTicks(), base::TimeDelta(), |
+ frame_feedback_id); |
+ } |
+ |
TestBrowserThreadBundle bundle_; |
+ scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_; |
std::unique_ptr<MockVideoCaptureControllerEventHandler> client_a_; |
std::unique_ptr<MockVideoCaptureControllerEventHandler> client_b_; |
std::unique_ptr<VideoCaptureController> controller_; |
@@ -168,6 +198,9 @@ class VideoCaptureControllerTest |
const float arbitrary_frame_rate_ = 10.0f; |
const base::TimeTicks arbitrary_reference_time_ = base::TimeTicks(); |
const base::TimeDelta arbitrary_timestamp_ = base::TimeDelta(); |
+ const media::VideoCaptureFormat arbitrary_format_; |
+ const VideoCaptureControllerID arbitrary_route_id_; |
+ const media::VideoCaptureSessionId arbitrary_session_id_; |
private: |
DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest); |
@@ -299,21 +332,21 @@ TEST_P(VideoCaptureControllerTest, NormalCaptureMultipleClients) { |
memset(buffer_access->data(), buffer_no++, buffer_access->mapped_size()); |
{ |
InSequence s; |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1); |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1, _)).Times(1); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_1, device_format.frame_size)) |
.Times(1); |
} |
{ |
InSequence s; |
- EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1); |
+ EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1, _)).Times(1); |
EXPECT_CALL(*client_b_, |
DoBufferReady(client_b_route_1, device_format.frame_size)) |
.Times(1); |
} |
{ |
InSequence s; |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1); |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2, _)).Times(1); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_2, device_format.frame_size)) |
.Times(1); |
@@ -379,21 +412,21 @@ TEST_P(VideoCaptureControllerTest, NormalCaptureMultipleClients) { |
// The buffer should be delivered to the clients in any order. |
{ |
InSequence s; |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1); |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1, _)).Times(1); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_1, device_format.frame_size)) |
.Times(1); |
} |
{ |
InSequence s; |
- EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1); |
+ EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1, _)).Times(1); |
EXPECT_CALL(*client_b_, |
DoBufferReady(client_b_route_1, device_format.frame_size)) |
.Times(1); |
} |
{ |
InSequence s; |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1); |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2, _)).Times(1); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_2, device_format.frame_size)) |
.Times(1); |
@@ -432,21 +465,22 @@ TEST_P(VideoCaptureControllerTest, NormalCaptureMultipleClients) { |
// The new client needs to be notified of the creation of |kPoolSize| buffers; |
// the old clients only |kPoolSize - 2|. |
- EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize); |
+ EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2, _)) |
+ .Times(kPoolSize); |
EXPECT_CALL(*client_b_, |
DoBufferReady(client_b_route_2, device_format.frame_size)) |
.Times(kPoolSize); |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)) |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1, _)) |
.Times(kPoolSize - 2); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_1, device_format.frame_size)) |
.Times(kPoolSize); |
- EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)) |
+ EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2, _)) |
.Times(kPoolSize - 2); |
EXPECT_CALL(*client_a_, |
DoBufferReady(client_a_route_2, device_format.frame_size)) |
.Times(kPoolSize); |
- EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)) |
+ EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1, _)) |
.Times(kPoolSize - 2); |
EXPECT_CALL(*client_b_, |
DoBufferReady(client_b_route_1, device_format.frame_size)) |
@@ -651,4 +685,160 @@ TEST_F(VideoCaptureControllerTest, FrameFeedbackIsReportedForSequenceOfFrames) { |
} |
} |
+TEST_F(VideoCaptureControllerTest, |
+ DeviceClientIsReleasedBeforeAnyBufferWasShared) { |
+ // Register |client_a_| at |controller_|. |
+ media::VideoCaptureParams requested_params; |
+ requested_params.requested_format = arbitrary_format_; |
+ controller_->AddClient(arbitrary_route_id_, client_a_.get(), |
+ arbitrary_session_id_, requested_params); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // |device_client_| is released by the device. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(arbitrary_route_id_, _)).Times(0); |
+ device_client_.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+} |
+ |
+TEST_F(VideoCaptureControllerTest, |
+ DeviceClientIsReleasedAfterFrameHasBeenConsumed) { |
+ // Register |client_a_| at |controller_|. |
+ media::VideoCaptureParams requested_params; |
+ requested_params.requested_format = arbitrary_format_; |
+ controller_->AddClient(arbitrary_route_id_, client_a_.get(), |
+ arbitrary_session_id_, requested_params); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Device sends a frame to |device_client_| and |client_a_| reports to |
+ // |controller_| that it has finished consuming the frame. |
+ int buffer_id_reported_to_client = -1; |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*client_a_, DoBufferCreated(_, _)) |
+ .Times(1) |
+ .WillOnce(SaveArg<1>(&buffer_id_reported_to_client)); |
+ EXPECT_CALL(*client_a_, DoBufferReady(_, _)).Times(1); |
+ } |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, _)).Times(0); |
+ SendStubFrameToDeviceClient(arbitrary_format_); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // |device_client_| is released by the device. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, buffer_id_reported_to_client)) |
+ .Times(1); |
mcasas
2017/02/03 23:24:22
.Times(1) is superfluous since it's the default va
chfremer
2017/02/06 18:16:35
Done.
|
+ device_client_.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+} |
+ |
+TEST_F(VideoCaptureControllerTest, |
+ DeviceClientIsReleasedWhileFrameIsBeingConsumed) { |
+ client_a_->set_enable_auto_return_buffer_on_buffer_ready(false); |
+ // Register |client_a_| at |controller_|. |
+ media::VideoCaptureParams requested_params; |
+ requested_params.requested_format = arbitrary_format_; |
+ controller_->AddClient(arbitrary_route_id_, client_a_.get(), |
+ arbitrary_session_id_, requested_params); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Device sends a frame to |device_client_|. |
+ int buffer_id_reported_to_client = -1; |
mcasas
2017/02/03 23:24:22
Should we s/-1/media::VideoCaptureBufferPool::kInv
chfremer
2017/02/06 18:16:35
Done.
|
+ { |
+ InSequence s; |
+ EXPECT_CALL(*client_a_, DoBufferCreated(_, _)) |
+ .Times(1) |
+ .WillOnce(SaveArg<1>(&buffer_id_reported_to_client)); |
+ EXPECT_CALL(*client_a_, DoBufferReady(_, _)).Times(1); |
+ } |
+ SendStubFrameToDeviceClient(arbitrary_format_); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // |device_client_| is released by the device. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, _)).Times(0); |
+ device_client_.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // |client_a_| signals to |controller_| that it has finished consuming the |
+ // frame. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, _)).Times(1); |
+ const double arbitrary_utilization = 0.0; |
+ controller_->ReturnBuffer(arbitrary_route_id_, client_a_.get(), |
+ buffer_id_reported_to_client, |
+ arbitrary_utilization); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+} |
+ |
+TEST_F(VideoCaptureControllerTest, |
+ NewDeviceClientSendsNewBufferWhileRetiredBufferStillBeingConsumed) { |
+ client_a_->set_enable_auto_return_buffer_on_buffer_ready(false); |
+ // Register |client_a_| at |controller_|. |
+ media::VideoCaptureParams requested_params; |
+ requested_params.requested_format = arbitrary_format_; |
+ controller_->AddClient(arbitrary_route_id_, client_a_.get(), |
+ arbitrary_session_id_, requested_params); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Device sends a frame to |device_client_|. |
+ int first_buffer_id = -1; |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*client_a_, DoBufferCreated(_, _)) |
+ .Times(1) |
+ .WillOnce(SaveArg<1>(&first_buffer_id)); |
+ EXPECT_CALL(*client_a_, DoBufferReady(_, _)).Times(1); |
+ } |
+ SendStubFrameToDeviceClient(arbitrary_format_); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // |device_client_| is released by the device. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, _)).Times(0); |
+ device_client_.reset(); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // A new |device_client_| is created with a new buffer pool. |
+ InitializeNewDeviceClientAndBufferPoolInstances(); |
+ |
+ // Device sends a frame to the new |device_client_|. |
+ int second_buffer_id = -1; |
+ { |
+ InSequence s; |
+ EXPECT_CALL(*client_a_, DoBufferCreated(_, _)) |
+ .Times(1) |
+ .WillOnce(SaveArg<1>(&second_buffer_id)); |
+ EXPECT_CALL(*client_a_, DoBufferReady(_, _)).Times(1); |
+ } |
+ SendStubFrameToDeviceClient(arbitrary_format_); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ EXPECT_NE(first_buffer_id, second_buffer_id); |
+ |
+ // |client_a_| signals to |controller_| that it has finished consuming the |
+ // first frame. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, first_buffer_id)).Times(1); |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, second_buffer_id)).Times(0); |
+ const double arbitrary_utilization = 0.0; |
+ controller_->ReturnBuffer(arbitrary_route_id_, client_a_.get(), |
+ first_buffer_id, arbitrary_utilization); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+ |
+ // |client_a_| signals to |controller_| that it has finished consuming the |
+ // second frame. Since the new |device_client_| is still alive, the second |
+ // buffer is expected to stay alive. |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, first_buffer_id)).Times(0); |
+ EXPECT_CALL(*client_a_, DoBufferDestroyed(_, second_buffer_id)).Times(0); |
+ controller_->ReturnBuffer(arbitrary_route_id_, client_a_.get(), |
+ second_buffer_id, arbitrary_utilization); |
+ base::RunLoop().RunUntilIdle(); |
+ Mock::VerifyAndClearExpectations(client_a_.get()); |
+} |
+ |
} // namespace content |