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 "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 // These will come from mockable BuildInfo, once it exists. |
27 enum TemporaryAndroidVersions { | |
28 kJellyBeanMR1 = 17, | |
29 kJellyBeanMR2 = 18, | |
30 kLollipop = 21, | |
31 }; | |
32 | |
33 // The client is a strict mock, since we don't want random calls into it. We | |
34 // want to be sure about the call sequence. | |
35 class MockMediaCodecLoopClient : public StrictMock<MediaCodecLoop::Client> { | |
15 public: | 36 public: |
16 MOCK_CONST_METHOD0(IsAnyInputPending, bool()); | 37 MOCK_CONST_METHOD0(IsAnyInputPending, bool()); |
17 MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData()); | 38 MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData()); |
18 MOCK_METHOD1(OnInputDataQueued, void(bool)); | 39 MOCK_METHOD1(OnInputDataQueued, void(bool)); |
19 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&)); | 40 MOCK_METHOD1(OnDecodedEos, void(const MediaCodecLoop::OutputBuffer&)); |
20 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&)); | 41 MOCK_METHOD1(OnDecodedFrame, bool(const MediaCodecLoop::OutputBuffer&)); |
21 MOCK_METHOD0(OnOutputFormatChanged, bool()); | 42 MOCK_METHOD0(OnOutputFormatChanged, bool()); |
22 MOCK_METHOD0(OnCodecLoopError, void()); | 43 MOCK_METHOD0(OnCodecLoopError, void()); |
23 }; | 44 }; |
24 | 45 |
25 class MediaCodecLoopTest : public testing::Test { | 46 class MediaCodecLoopTest : public testing::Test { |
26 public: | 47 public: |
27 MediaCodecLoopTest() : client_(new MockMediaCodecLoopClient) {} | 48 MediaCodecLoopTest() |
49 : client_(new StrictMock<MockMediaCodecLoopClient>()), | |
50 task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {} | |
51 | |
52 ~MediaCodecLoopTest() override {} | |
53 | |
54 protected: | |
55 enum IdleExpectation { | |
56 ShouldBeIdle, | |
57 ShouldNotBeIdle, | |
58 }; | |
59 | |
60 // Wait until |codec_loop_| is idle. | |
61 // Do not call this in a sequence. | |
62 void WaitUntilIdle(IdleExpectation idleExpectation = ShouldBeIdle) { | |
63 switch (idleExpectation) { | |
64 case ShouldBeIdle: | |
65 EXPECT_CALL(*client_, IsAnyInputPending()).Times(0); | |
66 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(0); | |
67 break; | |
68 case ShouldNotBeIdle: | |
69 // Expect at least one call to see if more work is ready. We will | |
70 // return 'no'. | |
71 EXPECT_CALL(*client_, IsAnyInputPending()) | |
72 .Times(AtLeast(1)) | |
73 .WillRepeatedly(Return(false)); | |
74 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
75 .Times(AtLeast(1)) | |
76 .WillRepeatedly(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); | |
77 break; | |
78 } | |
79 | |
80 // 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 | |
82 // is pending. | |
83 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0); | |
84 | |
85 // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note | |
86 // that this doesn't actually wall-clock wait. | |
87 task_runner_->Sleep(base::TimeDelta::FromSeconds(30)); | |
88 } | |
89 | |
90 void ConstructCodecLoop(int sdk_int = kLollipop) { | |
91 std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge()); | |
92 // Since we're providing a codec, we do not expect an error. | |
93 EXPECT_CALL(*client_, OnCodecLoopError()).Times(0); | |
94 codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(), | |
95 std::move(codec), task_runner_)); | |
96 codec_loop_->SetTestTickClock(&clock_); | |
97 Mock::VerifyAndClearExpectations(client_.get()); | |
98 // We might want to WaitUntilIdle here. | |
watk
2016/08/09 18:32:55
Not sure what you mean by this
liberato (no reviews please)
2016/08/09 21:20:47
doesn't mean much anymore. removed.
| |
99 } | |
100 | |
101 // Set an expectation that MCL will try to get another input / output buffer, | |
102 // and not get one in DoPendingWork. | |
103 void ExpectEmptyIOLoop() { | |
104 ExpectIsAnyInputPending(false); | |
105 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
106 .Times(1) | |
107 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); | |
108 } | |
109 | |
110 void ExpectIsAnyInputPending(bool pending) { | |
111 EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(pending)); | |
112 } | |
113 | |
114 void ExpectDequeueInputBuffer(int input_buffer_index, | |
115 MediaCodecStatus status = MEDIA_CODEC_OK) { | |
116 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)) | |
117 .WillOnce(DoAll(SetArgPointee<1>(input_buffer_index), Return(status))); | |
118 } | |
119 | |
120 void ExpectInputDataQueued(bool success) { | |
121 EXPECT_CALL(*client_, OnInputDataQueued(success)).Times(1); | |
122 } | |
123 | |
124 // Expect a call to queue |data| into MC buffer |input_buffer_index|. | |
125 void ExpectQueueInputBuffer(int input_buffer_index, | |
126 const MediaCodecLoop::InputData& data, | |
127 MediaCodecStatus status = MEDIA_CODEC_OK) { | |
128 EXPECT_CALL(Codec(), QueueInputBuffer(input_buffer_index, data.memory, | |
129 data.length, data.presentation_time)) | |
130 .Times(1) | |
131 .WillOnce(Return(status)); | |
132 } | |
133 | |
134 void ExpectProvideInputData(const MediaCodecLoop::InputData& data) { | |
135 EXPECT_CALL(*client_, ProvideInputData()).WillOnce(Return(data)); | |
136 } | |
137 | |
138 MediaCodecLoop::InputData BigBuckBunny() { | |
139 MediaCodecLoop::InputData data; | |
140 data.memory = reinterpret_cast<const uint8_t*>("big buck bunny"); | |
141 data.length = 14; | |
142 data.presentation_time = base::TimeDelta::FromSeconds(1); | |
143 return data; | |
144 } | |
145 | |
146 struct OutputBuffer { | |
147 int index = 1; | |
148 size_t offset = 0; | |
149 size_t size = 1024; | |
150 base::TimeDelta pts = base::TimeDelta::FromSeconds(1); | |
151 bool eos = false; | |
152 bool key_frame = true; | |
153 }; | |
154 | |
155 struct EosOutputBuffer : public OutputBuffer { | |
156 EosOutputBuffer() { eos = true; } | |
157 }; | |
158 | |
159 void ExpectDequeueOutputBuffer(MediaCodecStatus status) { | |
160 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
161 .WillOnce(Return(status)); | |
162 } | |
163 | |
164 void ExpectDequeueOutputBuffer(const OutputBuffer& buffer) { | |
165 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
166 .WillOnce(DoAll( | |
167 SetArgPointee<1>(buffer.index), SetArgPointee<2>(buffer.offset), | |
168 SetArgPointee<3>(buffer.size), SetArgPointee<4>(buffer.pts), | |
169 SetArgPointee<5>(buffer.eos), SetArgPointee<6>(buffer.key_frame), | |
170 Return(MEDIA_CODEC_OK))); | |
171 } | |
172 | |
173 void ExpectOnDecodedFrame(const OutputBuffer& buf) { | |
174 EXPECT_CALL(*client_, | |
175 OnDecodedFrame( | |
176 Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index)))) | |
177 .Times(1) | |
178 .WillOnce(Return(true)); | |
179 } | |
180 | |
181 MockMediaCodecBridge& Codec() { | |
182 return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec()); | |
183 } | |
28 | 184 |
29 public: | 185 public: |
30 std::unique_ptr<MediaCodecLoop> codec_loop_; | 186 std::unique_ptr<MediaCodecLoop> codec_loop_; |
31 std::unique_ptr<MockMediaCodecLoopClient> client_; | 187 std::unique_ptr<MockMediaCodecLoopClient> client_; |
188 // TODO: how is the lifecycle of |clock_| handled? |task_runner_| can outlive | |
189 // us, since it's a refptr. | |
190 base::SimpleTestTickClock clock_; | |
191 scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; | |
32 | 192 |
33 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); | 193 DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); |
34 }; | 194 }; |
35 | 195 |
36 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { | 196 TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { |
37 std::unique_ptr<MediaCodecBridge> codec; | 197 std::unique_ptr<MediaCodecBridge> codec; |
38 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); | 198 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); |
39 codec_loop_.reset(new MediaCodecLoop(client_.get(), std::move(codec))); | 199 const int sdk_int = kLollipop; |
200 codec_loop_.reset( | |
201 new MediaCodecLoop(sdk_int, client_.get(), std::move(codec))); | |
202 // Do not WaitUntilIdle() here, since that assumes that we have a codec. | |
40 | 203 |
41 ASSERT_FALSE(codec_loop_->GetCodec()); | 204 ASSERT_FALSE(codec_loop_->GetCodec()); |
42 } | 205 } |
43 | 206 |
207 TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) { | |
208 ConstructCodecLoop(); | |
209 ASSERT_EQ(codec_loop_->GetCodec(), &Codec()); | |
210 WaitUntilIdle(ShouldBeIdle); | |
211 } | |
212 | |
213 TEST_F(MediaCodecLoopTest, TestPendingWorkWithoutInput) { | |
214 ConstructCodecLoop(); | |
215 // MCL should try ask if there is pending input, and try to dequeue output. | |
216 ExpectIsAnyInputPending(false); | |
217 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
218 .Times(1) | |
219 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); | |
220 codec_loop_->DoPendingWork(); | |
221 WaitUntilIdle(ShouldNotBeIdle); | |
222 } | |
223 | |
224 TEST_F(MediaCodecLoopTest, TestPendingWorkWithInput) { | |
225 ConstructCodecLoop(); | |
226 // MCL should try ask if there is pending input, and try to dequeue both an | |
227 // output and input buffer. | |
228 ExpectIsAnyInputPending(true); | |
229 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(1); | |
230 EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(1); | |
231 codec_loop_->DoPendingWork(); | |
232 WaitUntilIdle(ShouldNotBeIdle); | |
233 } | |
234 | |
235 TEST_F(MediaCodecLoopTest, TestPendingWorkWithOutputBuffer) { | |
236 ConstructCodecLoop(); | |
237 { | |
238 InSequence _s; | |
239 | |
240 // MCL will first request input, then try to dequeue output. | |
241 ExpectIsAnyInputPending(false); | |
242 OutputBuffer buf; | |
243 ExpectDequeueOutputBuffer(buf); | |
244 ExpectOnDecodedFrame(buf); | |
245 | |
246 // MCL will try again for another set of buffers before DoPendingWork() | |
247 // returns. This is why we don't just leave them for WaitUntilIdle(). | |
248 ExpectEmptyIOLoop(); | |
249 } | |
250 codec_loop_->DoPendingWork(); | |
251 WaitUntilIdle(ShouldNotBeIdle); | |
252 } | |
253 | |
254 TEST_F(MediaCodecLoopTest, TestQueueEos) { | |
255 // Test sending an EOS to MCL => MCB =dequeue output=> MCL . | |
256 ConstructCodecLoop(); | |
257 { | |
258 InSequence _s; | |
259 | |
260 ExpectIsAnyInputPending(true); | |
261 int input_buffer_index = 123; | |
262 ExpectDequeueInputBuffer(input_buffer_index); | |
263 | |
264 MediaCodecLoop::InputData data; | |
265 data.is_eos = true; | |
266 ExpectProvideInputData(data); | |
267 EXPECT_CALL(Codec(), QueueEOS(input_buffer_index)); | |
268 ExpectInputDataQueued(true); | |
269 | |
270 // Now send the EOS back on the output queue. | |
271 EosOutputBuffer eos; | |
272 ExpectDequeueOutputBuffer(eos); | |
273 EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false)); | |
274 EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1); | |
275 | |
276 // See TestUnqueuedEos. | |
277 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
278 .Times(1) | |
279 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); | |
280 } | |
281 codec_loop_->DoPendingWork(); | |
282 // Don't WaitUntilIdle() here. See TestUnqueuedEos. | |
283 } | |
284 | |
285 TEST_F(MediaCodecLoopTest, TestQueueInputData) { | |
286 // Send a buffer full of data into MCL and make sure that it gets queued with | |
287 // MediaCodecBridge correctly. | |
288 ConstructCodecLoop(); | |
289 { | |
290 InSequence _s; | |
291 | |
292 ExpectIsAnyInputPending(true); | |
293 int input_buffer_index = 123; | |
294 ExpectDequeueInputBuffer(input_buffer_index); | |
295 | |
296 MediaCodecLoop::InputData data = BigBuckBunny(); | |
297 ExpectProvideInputData(data); | |
298 | |
299 // MCL should send the buffer into MediaCodec and notify the client. | |
300 ExpectQueueInputBuffer(input_buffer_index, data); | |
301 ExpectInputDataQueued(true); | |
302 | |
303 // MCL will try to dequeue an output buffer too. | |
304 EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) | |
305 .Times(1) | |
306 .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); | |
307 | |
308 // DoPendingWork will try again. | |
309 ExpectEmptyIOLoop(); | |
310 } | |
311 codec_loop_->DoPendingWork(); | |
312 WaitUntilIdle(ShouldNotBeIdle); | |
313 } | |
314 | |
315 TEST_F(MediaCodecLoopTest, TestQueueInputDataFails) { | |
316 // Send a buffer full of data into MCL, but MediaCodecBridge fails to queue | |
317 // it successfully. | |
318 ConstructCodecLoop(); | |
319 { | |
320 InSequence _s; | |
321 | |
322 ExpectIsAnyInputPending(true); | |
323 int input_buffer_index = 123; | |
324 ExpectDequeueInputBuffer(input_buffer_index); | |
325 | |
326 MediaCodecLoop::InputData data = BigBuckBunny(); | |
327 ExpectProvideInputData(data); | |
328 | |
329 // MCL should send the buffer into MediaCodec and notify the client. | |
330 ExpectQueueInputBuffer(input_buffer_index, data, MEDIA_CODEC_ERROR); | |
331 ExpectInputDataQueued(false); | |
332 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); | |
333 } | |
334 codec_loop_->DoPendingWork(); | |
335 // MCL is now in the error state. | |
336 } | |
337 | |
338 TEST_F(MediaCodecLoopTest, TestQueueInputDataTryAgain) { | |
339 // Signal that there is input pending, but don't provide an input buffer. | |
340 ConstructCodecLoop(); | |
341 { | |
342 InSequence _s; | |
343 | |
344 ExpectIsAnyInputPending(true); | |
345 ExpectDequeueInputBuffer(-1, MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER); | |
346 // MCL will try for output too. | |
347 ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | |
348 } | |
349 codec_loop_->DoPendingWork(); | |
350 // Note that the client might not be allowed to change from "input pending" | |
351 // to "no input pending" without actually being asked for input. For now, | |
352 // MCL doesn't assume this. | |
353 WaitUntilIdle(ShouldNotBeIdle); | |
354 } | |
355 | |
356 TEST_F(MediaCodecLoopTest, TestSeveralPendingIOBuffers) { | |
357 // Provide several input and output buffers to MCL. | |
358 ConstructCodecLoop(); | |
359 int input_buffer_index = 123; | |
360 const int num_loops = 4; | |
361 | |
362 InSequence _s; | |
363 for (int i = 0; i < num_loops; i++, input_buffer_index++) { | |
364 ExpectIsAnyInputPending(true); | |
365 ExpectDequeueInputBuffer(input_buffer_index); | |
366 | |
367 MediaCodecLoop::InputData data = BigBuckBunny(); | |
368 ExpectProvideInputData(data); | |
369 | |
370 ExpectQueueInputBuffer(input_buffer_index, data); | |
371 ExpectInputDataQueued(true); | |
372 | |
373 OutputBuffer buffer; | |
374 buffer.index = i; | |
375 buffer.size += i; | |
376 buffer.pts = base::TimeDelta::FromSeconds(i + 1); | |
377 ExpectDequeueOutputBuffer(buffer); | |
378 ExpectOnDecodedFrame(buffer); | |
379 } | |
380 | |
381 ExpectEmptyIOLoop(); | |
382 | |
383 codec_loop_->DoPendingWork(); | |
384 } | |
385 | |
386 TEST_F(MediaCodecLoopTest, TestTryFlushOnJellyBeanMR2) { | |
387 // On JB MR2+ MCL should be willing to use MediaCodecBridge::Flush. | |
388 ConstructCodecLoop(kJellyBeanMR2); | |
389 EXPECT_CALL(Codec(), Flush()).Times(1).WillOnce(Return(MEDIA_CODEC_OK)); | |
390 ASSERT_TRUE(codec_loop_->TryFlush()); | |
391 } | |
392 | |
393 TEST_F(MediaCodecLoopTest, TestTryFlushAfterJellyBeanMR2Fails) { | |
394 // On JB MR2+, MCL should be willing to use MediaCodecBridge::Flush. Try | |
395 // that, but make Flush fail. | |
396 ConstructCodecLoop(kJellyBeanMR2); | |
397 EXPECT_CALL(Codec(), Flush()).Times(1).WillOnce(Return(MEDIA_CODEC_ERROR)); | |
398 EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); | |
399 ASSERT_FALSE(codec_loop_->TryFlush()); | |
400 } | |
401 | |
402 TEST_F(MediaCodecLoopTest, TestTryFlushOnJellyBeanMR1) { | |
403 // In JB MR1, MCL should not be willing to use MediaCodecBridge::Flush. | |
404 ConstructCodecLoop(kJellyBeanMR1); | |
405 ASSERT_FALSE(codec_loop_->TryFlush()); | |
406 } | |
407 | |
408 TEST_F(MediaCodecLoopTest, TestOnKeyAdded) { | |
409 ConstructCodecLoop(); | |
410 | |
411 int input_buffer_index = 123; | |
412 MediaCodecLoop::InputData data = BigBuckBunny(); | |
413 | |
414 // First provide input, but have MediaCodecBridge require a key. | |
415 { | |
416 InSequence _s; | |
417 | |
418 // First DoPendingWork() | |
419 ExpectIsAnyInputPending(true); | |
420 ExpectDequeueInputBuffer(input_buffer_index); | |
421 | |
422 ExpectProvideInputData(data); | |
423 | |
424 // Notify MCL that it's missing the key. | |
425 ExpectQueueInputBuffer(input_buffer_index, data, MEDIA_CODEC_NO_KEY); | |
426 | |
427 // MCL should now try for output buffers. | |
428 ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | |
429 | |
430 // MCL will try again, since trying to queue the input buffer is considered | |
431 // doing work, for some reason. It would be nice to make this optional. | |
432 // Note that it should not ask us for more input, since it has not yet sent | |
433 // the buffer we just provided. | |
434 ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | |
435 } | |
436 codec_loop_->DoPendingWork(); | |
437 | |
438 // Try again, to be sure that MCL doesn't request more input. Note that this | |
439 // is also done in the above loop, but that one could be made optional. This | |
440 // forces MCL to try again as part of an entirely new DoPendingWork cycle. | |
441 { | |
442 InSequence _s; | |
443 // MCL should only try for output buffers, since it's still waiting for a | |
444 // key to be added. | |
445 ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | |
446 } | |
447 codec_loop_->DoPendingWork(); | |
448 | |
449 // When we add the key, MCL will DoPending work again. This time, it should | |
450 // succeed since the key has been added. | |
451 { | |
452 InSequence _s; | |
453 // MCL should not retain the original pointer. | |
454 data.memory = nullptr; | |
455 ExpectQueueInputBuffer(input_buffer_index, data); | |
456 ExpectInputDataQueued(true); | |
457 ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); | |
458 | |
459 // MCL did work, so it will try again. | |
460 ExpectEmptyIOLoop(); | |
461 } | |
462 | |
463 codec_loop_->OnKeyAdded(); | |
464 WaitUntilIdle(ShouldNotBeIdle); | |
465 } | |
466 | |
44 } // namespace media | 467 } // namespace media |
OLD | NEW |