Chromium Code Reviews| 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. | |
| 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 { | |
|
DaleCurtis
2016/08/01 18:23:17
Move above or below all functions.
| |
| 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 | |
|
DaleCurtis
2016/08/01 18:23:17
See VideoRendererImpl tests.
| |
| 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 |