| 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..6efa93a8991319cb38978f3cfaeb74d5b5e7f794 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,159 @@ 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 = media::VideoCaptureBufferPool::kInvalidId;
|
| + {
|
| + 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));
|
| + 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 = media::VideoCaptureBufferPool::kInvalidId;
|
| + {
|
| + 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 = media::VideoCaptureBufferPool::kInvalidId;
|
| + {
|
| + 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 = media::VideoCaptureBufferPool::kInvalidId;
|
| + {
|
| + 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
|
|
|