| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "media/base/android/media_codec_loop.h" |
| 6 |
| 5 #include "base/macros.h" | 7 #include "base/macros.h" |
| 6 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/test/test_mock_time_task_runner.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" |
| 7 #include "media/base/android/media_codec_bridge.h" | 11 #include "media/base/android/media_codec_bridge.h" |
| 8 #include "media/base/android/media_codec_loop.h" | |
| 9 #include "media/base/android/mock_media_codec_bridge.h" | 12 #include "media/base/android/mock_media_codec_bridge.h" |
| 10 #include "media/base/fake_single_thread_task_runner.h" | |
| 11 #include "testing/gmock/include/gmock/gmock.h" | 13 #include "testing/gmock/include/gmock/gmock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 15 |
| 14 using ::testing::_; | 16 using ::testing::_; |
| 15 using ::testing::AtLeast; | 17 using ::testing::AtLeast; |
| 16 using ::testing::Eq; | 18 using ::testing::Eq; |
| 17 using ::testing::Field; | 19 using ::testing::Field; |
| 18 using ::testing::InSequence; | 20 using ::testing::InSequence; |
| 19 using ::testing::Mock; | 21 using ::testing::Mock; |
| 20 using ::testing::Return; | 22 using ::testing::Return; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 39 MOCK_METHOD1(OnInputDataQueued, void(bool)); | 41 MOCK_METHOD1(OnInputDataQueued, void(bool)); |
| 40 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&)); | 42 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&)); |
| 41 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&)); | 43 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&)); |
| 42 MOCK_METHOD0(OnOutputFormatChanged, bool()); | 44 MOCK_METHOD0(OnOutputFormatChanged, bool()); |
| 43 MOCK_METHOD0(OnCodecLoopError, void()); | 45 MOCK_METHOD0(OnCodecLoopError, void()); |
| 44 }; | 46 }; |
| 45 | 47 |
| 46 class MediaCodecLoopTest : public testing::Test { | 48 class MediaCodecLoopTest : public testing::Test { |
| 47 public: | 49 public: |
| 48 MediaCodecLoopTest() | 50 MediaCodecLoopTest() |
| 49 : client_(new StrictMock<MockMediaCodecLoopClient>()), | 51 : task_runner_handle_(mock_task_runner_), |
| 50 task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {} | 52 client_(new StrictMock<MockMediaCodecLoopClient>()) {} |
| 51 | 53 |
| 52 ~MediaCodecLoopTest() override {} | 54 ~MediaCodecLoopTest() override {} |
| 53 | 55 |
| 54 protected: | 56 protected: |
| 55 enum IdleExpectation { | 57 enum IdleExpectation { |
| 56 ShouldBeIdle, | 58 ShouldBeIdle, |
| 57 ShouldNotBeIdle, | 59 ShouldNotBeIdle, |
| 58 }; | 60 }; |
| 59 | 61 |
| 60 // Wait until |codec_loop_| is idle. | 62 // Wait until |codec_loop_| is idle. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 77 break; | 79 break; |
| 78 } | 80 } |
| 79 | 81 |
| 80 // Either way, we expect that MCL should not attempt to dequeue input | 82 // Either way, we expect that MCL should not attempt to dequeue input |
| 81 // buffers, either because it's idle or because we said that no input | 83 // buffers, either because it's idle or because we said that no input |
| 82 // is pending. | 84 // is pending. |
| 83 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0); | 85 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0); |
| 84 | 86 |
| 85 // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note | 87 // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note |
| 86 // that this doesn't actually wall-clock wait. | 88 // that this doesn't actually wall-clock wait. |
| 87 task_runner_->Sleep(base::TimeDelta::FromSeconds(30)); | 89 mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30)); |
| 88 } | 90 } |
| 89 | 91 |
| 90 void ConstructCodecLoop(int sdk_int = kLollipop) { | 92 void ConstructCodecLoop(int sdk_int = kLollipop) { |
| 91 std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge()); | 93 std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge()); |
| 92 // Since we're providing a codec, we do not expect an error. | 94 // Since we're providing a codec, we do not expect an error. |
| 93 EXPECT_CALL(*client_, OnCodecLoopError()).Times(0); | 95 EXPECT_CALL(*client_, OnCodecLoopError()).Times(0); |
| 94 codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(), | 96 codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(), |
| 95 std::move(codec), task_runner_)); | 97 std::move(codec), mock_task_runner_)); |
| 96 codec_loop_->SetTestTickClock(&clock_); | 98 codec_loop_->SetTestTickClock(clock_.get()); |
| 97 Mock::VerifyAndClearExpectations(client_.get()); | 99 Mock::VerifyAndClearExpectations(client_.get()); |
| 98 } | 100 } |
| 99 | 101 |
| 100 // Set an expectation that MCL will try to get another input / output buffer, | 102 // Set an expectation that MCL will try to get another input / output buffer, |
| 101 // and not get one in DoPendingWork. | 103 // and not get one in DoPendingWork. |
| 102 void ExpectEmptyIOLoop() { | 104 void ExpectEmptyIOLoop() { |
| 103 ExpectIsAnyInputPending(false); | 105 ExpectIsAnyInputPending(false); |
| 104 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | 106 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) |
| 105 .Times(1) | 107 .Times(1) |
| 106 .WillOnce(Return(MEDIA_CODEC_TRY_AGAIN_LATER)); | 108 .WillOnce(Return(MEDIA_CODEC_TRY_AGAIN_LATER)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index)))) | 177 Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index)))) |
| 176 .Times(1) | 178 .Times(1) |
| 177 .WillOnce(Return(true)); | 179 .WillOnce(Return(true)); |
| 178 } | 180 } |
| 179 | 181 |
| 180 MockMediaCodecBridge& Codec() { | 182 MockMediaCodecBridge& Codec() { |
| 181 return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec()); | 183 return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec()); |
| 182 } | 184 } |
| 183 | 185 |
| 184 public: | 186 public: |
| 187 // Mocks the current thread's task runner which will also be used as the |
| 188 // MediaCodecLoop's task runner. |
| 189 scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_ = |
| 190 new base::TestMockTimeTaskRunner; |
| 191 base::ThreadTaskRunnerHandle task_runner_handle_; |
| 192 |
| 193 // A reference to |mock_task_runner_|'s TickClock handed to |codec_loop_|. |
| 194 std::unique_ptr<base::TickClock> clock_ = |
| 195 mock_task_runner_->GetMockTickClock(); |
| 196 |
| 185 std::unique_ptr<MediaCodecLoop> codec_loop_; | 197 std::unique_ptr<MediaCodecLoop> codec_loop_; |
| 186 std::unique_ptr<MockMediaCodecLoopClient> client_; | 198 std::unique_ptr<MockMediaCodecLoopClient> client_; |
| 187 // TODO: how is the lifecycle of |clock_| handled? |task_runner_| can outlive | |
| 188 // us, since it's a refptr. | |
| 189 base::SimpleTestTickClock clock_; | |
| 190 scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; | |
| 191 | 199 |
| 192 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); | 200 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); |
| 193 }; | 201 }; |
| 194 | 202 |
| 195 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { | 203 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { |
| 196 std::unique_ptr<MediaCodecBridge> codec; | 204 std::unique_ptr<MediaCodecBridge> codec; |
| 197 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); | 205 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); |
| 198 const int sdk_int = kLollipop; | 206 const int sdk_int = kLollipop; |
| 199 codec_loop_.reset( | 207 codec_loop_.reset( |
| 200 new MediaCodecLoop(sdk_int, client_.get(), std::move(codec))); | 208 new MediaCodecLoop(sdk_int, client_.get(), std::move(codec), |
| 209 scoped_refptr<base::SingleThreadTaskRunner>())); |
| 201 // Do not WaitUntilIdle() here, since that assumes that we have a codec. | 210 // Do not WaitUntilIdle() here, since that assumes that we have a codec. |
| 202 | 211 |
| 203 ASSERT_FALSE(codec_loop_->GetCodec()); | 212 ASSERT_FALSE(codec_loop_->GetCodec()); |
| 204 } | 213 } |
| 205 | 214 |
| 206 TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) { | 215 TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) { |
| 207 ConstructCodecLoop(); | 216 ConstructCodecLoop(); |
| 208 ASSERT_EQ(codec_loop_->GetCodec(), &Codec()); | 217 ASSERT_EQ(codec_loop_->GetCodec(), &Codec()); |
| 209 WaitUntilIdle(ShouldBeIdle); | 218 WaitUntilIdle(ShouldBeIdle); |
| 210 } | 219 } |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 | 466 |
| 458 // MCL did work, so it will try again. | 467 // MCL did work, so it will try again. |
| 459 ExpectEmptyIOLoop(); | 468 ExpectEmptyIOLoop(); |
| 460 } | 469 } |
| 461 | 470 |
| 462 codec_loop_->OnKeyAdded(); | 471 codec_loop_->OnKeyAdded(); |
| 463 WaitUntilIdle(ShouldNotBeIdle); | 472 WaitUntilIdle(ShouldNotBeIdle); |
| 464 } | 473 } |
| 465 | 474 |
| 466 } // namespace media | 475 } // namespace media |
| OLD | NEW |