Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(422)

Side by Side Diff: media/base/android/media_codec_loop_unittest.cc

Issue 2132653002: MediaCodecLoop unit tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: added some tests Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/android/media_codec_loop.cc ('k') | media/base/android/media_codec_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "base/macros.h" 5 #include "base/macros.h"
6 #include "base/message_loop/message_loop.h" 6 #include "base/message_loop/message_loop.h"
7 #include "media/base/android/media_codec_bridge.h" 7 #include "media/base/android/media_codec_bridge.h"
8 #include "media/base/android/media_codec_loop.h" 8 #include "media/base/android/media_codec_loop.h"
9 #include "media/base/android/mock_media_codec_bridge.h"
10 #include "media/base/fake_single_thread_task_runner.h"
9 #include "testing/gmock/include/gmock/gmock.h" 11 #include "testing/gmock/include/gmock/gmock.h"
10 #include "testing/gtest/include/gtest/gtest.h" 12 #include "testing/gtest/include/gtest/gtest.h"
11 13
14 using ::testing::_;
15 using ::testing::AtLeast;
16 using ::testing::Eq;
17 using ::testing::Field;
18 using ::testing::InSequence;
19 using ::testing::Mock;
20 using ::testing::Return;
21 using ::testing::SetArgPointee;
22 using ::testing::StrictMock;
23
12 namespace media { 24 namespace media {
13 25
14 class MockMediaCodecLoopClient : public MediaCodecLoop::Client { 26 // The client is a strict mock, since we don't want random calls into it. We
27 // want to be sure about the call sequence.
28 class MockMediaCodecLoopClient : public StrictMock<MediaCodecLoop::Client> {
15 public: 29 public:
16 MOCK_CONST_METHOD0(IsAnyInputPending, bool()); 30 MOCK_CONST_METHOD0(IsAnyInputPending, bool());
17 MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData()); 31 MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData());
18 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&)); 32 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&));
19 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&)); 33 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&));
20 MOCK_METHOD0(OnOutputFormatChanged, bool()); 34 MOCK_METHOD0(OnOutputFormatChanged, bool());
21 MOCK_METHOD0(OnCodecLoopError, void()); 35 MOCK_METHOD0(OnCodecLoopError, void());
22 }; 36 };
23 37
24 class MediaCodecLoopTest : public testing::Test { 38 class MediaCodecLoopTest : public testing::Test {
25 public: 39 public:
26 MediaCodecLoopTest() : client_(new MockMediaCodecLoopClient) {} 40 MediaCodecLoopTest()
41 : client_(new StrictMock<MockMediaCodecLoopClient>()),
42 task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {}
43
44 ~MediaCodecLoopTest() override {}
45
46 protected:
47 enum IdleExpectation {
48 ShouldBeIdle,
49 ShouldNotBeIdle,
50 };
51
52 // Wait until |codec_loop_| is idle.
53 void WaitUntilIdle(IdleExpectation idleExpectation = ShouldBeIdle) {
54 switch (idleExpectation) {
55 case ShouldBeIdle:
56 EXPECT_CALL(*client_, IsAnyInputPending()).Times(0);
57 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(0);
58 break;
59 case ShouldNotBeIdle:
60 // Expect at least one call to see if more work is ready. We will
61 // return 'no'.
62 EXPECT_CALL(*client_, IsAnyInputPending())
63 .Times(AtLeast(1))
64 .WillRepeatedly(Return(false));
65 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
66 .Times(AtLeast(1))
67 .WillRepeatedly(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
68 break;
69 }
70
71 // Either way, we expect that MCL should not attempt to dequeue input
72 // buffers, either because it's idle or because we said that no input
73 // is pending.
74 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0);
75
76 // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note
77 // that this doesn't actually wall-clock wait.
78 task_runner_->Sleep(base::TimeDelta::FromSeconds(30));
79 }
80
81 void ConstructCodecLoop() {
82 std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge());
83 // Since we're providing a codec, we do not expect an error.
84 EXPECT_CALL(*client_, OnCodecLoopError()).Times(0);
85 codec_loop_.reset(
86 new MediaCodecLoop(client_.get(), std::move(codec), task_runner_));
87 codec_loop_->SetTestTickClock(&clock_);
88 Mock::VerifyAndClearExpectations(client_.get());
89 // We might want to WaitUntilIdle here.
90 }
91
92 struct OutputBuffer {
93 int index = 1;
94 size_t offset = 0;
95 size_t size = 1024;
96 base::TimeDelta pts = base::TimeDelta::FromSeconds(1);
97 bool eos = false;
98 bool key_frame = true;
99 };
100
101 struct EosOutputBuffer : public OutputBuffer {
102 EosOutputBuffer() { eos = true; }
103 };
104
105 void QueueOutputBuffer(OutputBuffer buffer) {
106 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
107 .WillOnce(DoAll(
108 SetArgPointee<1>(buffer.index), SetArgPointee<2>(buffer.offset),
109 SetArgPointee<3>(buffer.size), SetArgPointee<4>(buffer.pts),
110 SetArgPointee<5>(buffer.eos), SetArgPointee<6>(buffer.key_frame),
111 Return(MEDIA_CODEC_OK)));
112 }
113
114 MockMediaCodecBridge& Codec() {
115 return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec());
116 }
27 117
28 public: 118 public:
29 std::unique_ptr<MediaCodecLoop> codec_loop_; 119 std::unique_ptr<MediaCodecLoop> codec_loop_;
30 std::unique_ptr<MockMediaCodecLoopClient> client_; 120 std::unique_ptr<MockMediaCodecLoopClient> client_;
121 // TODO: how is the lifecycle of |clock_| handled? |task_runner_| can outlive
122 // us, since it's a refptr.
123 base::SimpleTestTickClock clock_;
124 scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
31 125
32 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); 126 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest);
33 }; 127 };
34 128
35 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { 129 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) {
36 std::unique_ptr<MediaCodecBridge> codec; 130 std::unique_ptr<MediaCodecBridge> codec;
37 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); 131 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1);
38 codec_loop_.reset(new MediaCodecLoop(client_.get(), std::move(codec))); 132 codec_loop_.reset(new MediaCodecLoop(client_.get(), std::move(codec)));
133 // Do not WaitUntilIdle() here, since that assumes that we have a codec.
39 134
40 ASSERT_FALSE(codec_loop_->GetCodec()); 135 ASSERT_FALSE(codec_loop_->GetCodec());
41 } 136 }
42 137
138 TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) {
139 ConstructCodecLoop();
140 ASSERT_EQ(codec_loop_->GetCodec(), &Codec());
141 WaitUntilIdle(ShouldBeIdle);
142 }
143
144 TEST_F(MediaCodecLoopTest, TestPendingWorkWithoutInput) {
145 ConstructCodecLoop();
146 // MCL should try ask if there is pending input, and try to dequeue output.
147 EXPECT_CALL(*client_, IsAnyInputPending()).Times(1).WillOnce(Return(false));
148 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
149 .Times(1)
150 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
151 codec_loop_->DoPendingWork();
152 WaitUntilIdle(ShouldNotBeIdle);
153 }
154
155 TEST_F(MediaCodecLoopTest, TestPendingWorkWithInput) {
156 ConstructCodecLoop();
157 // MCL should try ask if there is pending input, and try to dequeue both an
158 // output and input buffer.
159 EXPECT_CALL(*client_, IsAnyInputPending()).Times(1).WillOnce(Return(true));
160 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(1);
161 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(1);
162 codec_loop_->DoPendingWork();
163 WaitUntilIdle(ShouldNotBeIdle);
164 }
165
166 TEST_F(MediaCodecLoopTest, TestPendingWorkWithOutputBuffer) {
167 ConstructCodecLoop();
168 {
169 InSequence _s;
170
171 // MCL will first request input, then try to dequeue output.
172 EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
173 OutputBuffer buf;
174 QueueOutputBuffer(buf);
175 EXPECT_CALL(*client_,
liberato (no reviews please) 2016/07/08 17:49:46 gmock is really amazing. it lets me set an expect
176 OnDecodedFrame(
177 Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index))))
178 .Times(1)
179 .WillOnce(Return(true));
180
181 // MCL will try again for another set of buffers before DoPendingWork()
182 // returns. This is why we don't just leave them for WaitUntilIdle().
183 EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
184 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
185 .Times(1)
186 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
187 }
188 codec_loop_->DoPendingWork();
189 WaitUntilIdle(ShouldNotBeIdle);
190 }
191
192 TEST_F(MediaCodecLoopTest, TestUnqueuedEos) {
193 // Test sending an unsolicited EOS from MCB to MCL.
194 ConstructCodecLoop();
195 {
196 InSequence _s;
197
198 // MCL will first request input, then try to dequeue output.
199 EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
200 EosOutputBuffer eos;
201 QueueOutputBuffer(eos);
202 EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false));
203 EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1);
204
205 // MCL should not call back for another input buffer once it receives EOS,
206 // so don't expect a call to IsAnyInputPending. It will try for more
207 // output, however. It's unclear if it should.
208 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
209 .Times(1)
210 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
211 }
212 codec_loop_->DoPendingWork();
213 // Don't WaitUntilIdle() here, since MCL is not requesting buffers. It would
214 // fail the IsAnyInputPending expectation.
215 }
216
217 TEST_F(MediaCodecLoopTest, TestQueueEos) {
218 // Test sending an unsolicited EOS from MCB to MCL.
219 ConstructCodecLoop();
220 {
221 InSequence _s;
222
223 // MCL will first request input. We will provide an EOS from the client,
224 // and an input buffer to hold it.
225 EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(true));
226 int input_buffer_index = 123;
227 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _))
228 .WillOnce(DoAll(SetArgPointee<1>(input_buffer_index),
liberato (no reviews please) 2016/07/08 17:49:46 this sets the *index parameter of DequeueInputBuff
229 Return(MEDIA_CODEC_OK)));
230 MediaCodecLoop::InputData data;
231 data.is_eos = true;
232 EXPECT_CALL(*client_, ProvideInputData()).WillOnce(Return(data));
233 EXPECT_CALL(Codec(), QueueEOS(input_buffer_index));
234
235 // Now send the EOS back on the output queue.
236 EosOutputBuffer eos;
237 QueueOutputBuffer(eos);
238 EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false));
239 EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1);
240
241 // See TestUnqueuedEos.
242 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
243 .Times(1)
244 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
245 }
246 codec_loop_->DoPendingWork();
247 // Don't WaitUntilIdle() here. See TestUnqueuedEos.
248 }
249
43 } // namespace media 250 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_loop.cc ('k') | media/base/android/media_codec_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698