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