OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <stddef.h> | 5 #include <stddef.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <deque> | |
9 #include <vector> | 8 #include <vector> |
10 | 9 |
11 #include "base/bind.h" | 10 #include "base/bind.h" |
12 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
13 #include "base/macros.h" | 12 #include "base/macros.h" |
14 #include "base/md5.h" | 13 #include "base/md5.h" |
15 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
16 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
17 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
18 #include "base/sys_byteorder.h" | 17 #include "base/sys_byteorder.h" |
| 18 #include "base/threading/platform_thread.h" |
19 #include "build/build_config.h" | 19 #include "build/build_config.h" |
20 #include "media/base/audio_buffer.h" | 20 #include "media/base/audio_buffer.h" |
21 #include "media/base/audio_bus.h" | 21 #include "media/base/audio_bus.h" |
22 #include "media/base/audio_hash.h" | 22 #include "media/base/audio_hash.h" |
23 #include "media/base/decoder_buffer.h" | 23 #include "media/base/decoder_buffer.h" |
24 #include "media/base/media_util.h" | 24 #include "media/base/media_util.h" |
25 #include "media/base/test_data_util.h" | 25 #include "media/base/test_data_util.h" |
26 #include "media/base/test_helpers.h" | 26 #include "media/base/test_helpers.h" |
27 #include "media/base/timestamp_constants.h" | 27 #include "media/base/timestamp_constants.h" |
28 #include "media/ffmpeg/ffmpeg_common.h" | 28 #include "media/ffmpeg/ffmpeg_common.h" |
29 #include "media/filters/audio_file_reader.h" | 29 #include "media/filters/audio_file_reader.h" |
30 #include "media/filters/ffmpeg_audio_decoder.h" | 30 #include "media/filters/ffmpeg_audio_decoder.h" |
31 #include "media/filters/in_memory_url_protocol.h" | 31 #include "media/filters/in_memory_url_protocol.h" |
32 #include "media/filters/opus_audio_decoder.h" | 32 #include "media/filters/opus_audio_decoder.h" |
33 #include "testing/gtest/include/gtest/gtest.h" | 33 #include "testing/gtest/include/gtest/gtest.h" |
34 | 34 |
| 35 #if defined(OS_ANDROID) |
| 36 #include "base/android/build_info.h" |
| 37 #include "media/base/android/media_codec_util.h" |
| 38 #include "media/filters/android/media_codec_audio_decoder.h" |
| 39 |
| 40 // Helper macro to skip the test if MediaCodec is not available. |
| 41 #define SKIP_TEST_IF_NO_MEDIA_CODEC() \ |
| 42 do { \ |
| 43 if (GetParam().decoder_type == MEDIA_CODEC) { \ |
| 44 if (!MediaCodecUtil::IsMediaCodecAvailable()) { \ |
| 45 VLOG(0) << "Could not run test - no MediaCodec on device."; \ |
| 46 return; \ |
| 47 } \ |
| 48 if (GetParam().codec == kCodecOpus && \ |
| 49 base::android::BuildInfo::GetInstance()->sdk_int() < 21) { \ |
| 50 VLOG(0) << "Could not run test - Opus is not supported"; \ |
| 51 return; \ |
| 52 } \ |
| 53 } \ |
| 54 } while (0) |
| 55 #else |
| 56 #define SKIP_TEST_IF_NO_MEDIA_CODEC() \ |
| 57 do { \ |
| 58 } while (0) |
| 59 #endif // !defined(OS_ANDROID) |
| 60 |
35 namespace media { | 61 namespace media { |
36 | 62 |
37 // The number of packets to read and then decode from each file. | 63 // The number of packets to read and then decode from each file. |
38 static const size_t kDecodeRuns = 3; | 64 static const size_t kDecodeRuns = 3; |
39 static const uint8_t kOpusExtraData[] = { | 65 static const uint8_t kOpusExtraData[] = { |
40 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02, | 66 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02, |
41 // The next two bytes represent the codec delay. | 67 // The next two bytes represent the codec delay. |
42 0x00, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00}; | 68 0x00, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00}; |
43 | 69 |
44 enum AudioDecoderType { | 70 enum AudioDecoderType { |
45 FFMPEG, | 71 FFMPEG, |
46 OPUS, | 72 OPUS, |
| 73 #if defined(OS_ANDROID) |
| 74 MEDIA_CODEC, |
| 75 #endif |
47 }; | 76 }; |
48 | 77 |
49 struct DecodedBufferExpectations { | 78 struct DecodedBufferExpectations { |
50 const int64_t timestamp; | 79 const int64_t timestamp; |
51 const int64_t duration; | 80 const int64_t duration; |
52 const char* hash; | 81 const char* hash; |
53 }; | 82 }; |
54 | 83 |
55 struct DecoderTestData { | 84 struct DecoderTestData { |
56 const AudioDecoderType decoder_type; | 85 const AudioDecoderType decoder_type; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 last_decode_status_(AudioDecoder::kDecodeError) { | 135 last_decode_status_(AudioDecoder::kDecodeError) { |
107 switch (GetParam().decoder_type) { | 136 switch (GetParam().decoder_type) { |
108 case FFMPEG: | 137 case FFMPEG: |
109 decoder_.reset(new FFmpegAudioDecoder(message_loop_.task_runner(), | 138 decoder_.reset(new FFmpegAudioDecoder(message_loop_.task_runner(), |
110 new MediaLog())); | 139 new MediaLog())); |
111 break; | 140 break; |
112 case OPUS: | 141 case OPUS: |
113 decoder_.reset( | 142 decoder_.reset( |
114 new OpusAudioDecoder(message_loop_.task_runner())); | 143 new OpusAudioDecoder(message_loop_.task_runner())); |
115 break; | 144 break; |
| 145 #if defined(OS_ANDROID) |
| 146 case MEDIA_CODEC: |
| 147 decoder_.reset(new MediaCodecAudioDecoder(message_loop_.task_runner())); |
| 148 break; |
| 149 #endif |
116 } | 150 } |
117 } | 151 } |
118 | 152 |
119 virtual ~AudioDecoderTest() { | 153 virtual ~AudioDecoderTest() { |
120 EXPECT_FALSE(pending_decode_); | 154 EXPECT_FALSE(pending_decode_); |
121 EXPECT_FALSE(pending_reset_); | 155 EXPECT_FALSE(pending_reset_); |
122 } | 156 } |
123 | 157 |
124 protected: | 158 protected: |
125 void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { | 159 void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { |
126 ASSERT_FALSE(pending_decode_); | 160 ASSERT_FALSE(pending_decode_); |
127 pending_decode_ = true; | 161 pending_decode_ = true; |
128 last_decode_status_ = AudioDecoder::kDecodeError; | 162 last_decode_status_ = AudioDecoder::kDecodeError; |
| 163 |
| 164 base::RunLoop run_loop; |
129 decoder_->Decode( | 165 decoder_->Decode( |
130 buffer, | 166 buffer, base::Bind(&AudioDecoderTest::DecodeFinished, |
131 base::Bind(&AudioDecoderTest::DecodeFinished, base::Unretained(this))); | 167 base::Unretained(this), run_loop.QuitClosure())); |
132 base::RunLoop().RunUntilIdle(); | 168 run_loop.Run(); |
133 ASSERT_FALSE(pending_decode_); | 169 ASSERT_FALSE(pending_decode_); |
134 } | 170 } |
135 | 171 |
136 void SendEndOfStream() { | 172 void SendEndOfStream() { |
137 DecodeBuffer(DecoderBuffer::CreateEOSBuffer()); | 173 DecodeBuffer(DecoderBuffer::CreateEOSBuffer()); |
138 } | 174 } |
139 | 175 |
140 void Initialize() { | 176 void Initialize() { |
141 // Load the test data file. | 177 // Load the test data file. |
142 data_ = ReadTestDataFile(GetParam().filename); | 178 data_ = ReadTestDataFile(GetParam().filename); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 Reset(); | 254 Reset(); |
219 decoded_audio_.clear(); | 255 decoded_audio_.clear(); |
220 ASSERT_TRUE(reader_->SeekForTesting(seek_time)); | 256 ASSERT_TRUE(reader_->SeekForTesting(seek_time)); |
221 } | 257 } |
222 | 258 |
223 void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) { | 259 void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) { |
224 EXPECT_FALSE(buffer->end_of_stream()); | 260 EXPECT_FALSE(buffer->end_of_stream()); |
225 decoded_audio_.push_back(buffer); | 261 decoded_audio_.push_back(buffer); |
226 } | 262 } |
227 | 263 |
228 void DecodeFinished(AudioDecoder::Status status) { | 264 void DecodeFinished(const base::Closure& quit_closure, |
| 265 AudioDecoder::Status status) { |
229 EXPECT_TRUE(pending_decode_); | 266 EXPECT_TRUE(pending_decode_); |
230 EXPECT_FALSE(pending_reset_); | 267 EXPECT_FALSE(pending_reset_); |
231 pending_decode_ = false; | 268 pending_decode_ = false; |
232 last_decode_status_ = status; | 269 last_decode_status_ = status; |
| 270 quit_closure.Run(); |
233 } | 271 } |
234 | 272 |
235 void ResetFinished() { | 273 void ResetFinished() { |
236 EXPECT_TRUE(pending_reset_); | 274 EXPECT_TRUE(pending_reset_); |
237 EXPECT_FALSE(pending_decode_); | 275 EXPECT_FALSE(pending_decode_); |
238 pending_reset_ = false; | 276 pending_reset_ = false; |
239 } | 277 } |
240 | 278 |
241 // Generates an MD5 hash of the audio signal. Should not be used for checks | 279 // Generates an MD5 hash of the audio signal. Should not be used for checks |
242 // across platforms as audio varies slightly across platforms. | 280 // across platforms as audio varies slightly across platforms. |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 std::deque<scoped_refptr<AudioBuffer> > decoded_audio_; | 352 std::deque<scoped_refptr<AudioBuffer> > decoded_audio_; |
315 base::TimeDelta start_timestamp_; | 353 base::TimeDelta start_timestamp_; |
316 | 354 |
317 DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest); | 355 DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest); |
318 }; | 356 }; |
319 | 357 |
320 class OpusAudioDecoderBehavioralTest : public AudioDecoderTest {}; | 358 class OpusAudioDecoderBehavioralTest : public AudioDecoderTest {}; |
321 class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {}; | 359 class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {}; |
322 | 360 |
323 TEST_P(AudioDecoderTest, Initialize) { | 361 TEST_P(AudioDecoderTest, Initialize) { |
| 362 SKIP_TEST_IF_NO_MEDIA_CODEC(); |
324 ASSERT_NO_FATAL_FAILURE(Initialize()); | 363 ASSERT_NO_FATAL_FAILURE(Initialize()); |
325 } | 364 } |
326 | 365 |
327 // Verifies decode audio as well as the Decode() -> Reset() sequence. | 366 // Verifies decode audio as well as the Decode() -> Reset() sequence. |
328 TEST_P(AudioDecoderTest, ProduceAudioSamples) { | 367 TEST_P(AudioDecoderTest, ProduceAudioSamples) { |
| 368 SKIP_TEST_IF_NO_MEDIA_CODEC(); |
329 ASSERT_NO_FATAL_FAILURE(Initialize()); | 369 ASSERT_NO_FATAL_FAILURE(Initialize()); |
330 | 370 |
331 // Run the test multiple times with a seek back to the beginning in between. | 371 // Run the test multiple times with a seek back to the beginning in between. |
332 std::vector<std::string> decoded_audio_md5_hashes; | 372 std::vector<std::string> decoded_audio_md5_hashes; |
333 for (int i = 0; i < 2; ++i) { | 373 for (int i = 0; i < 2; ++i) { |
334 for (size_t j = 0; j < kDecodeRuns; ++j) { | 374 // Run decoder until we get at least |kDecodeRuns| output buffers. |
335 do { | 375 // Keeping Decode() in a loop seems to be the simplest way to guarantee that |
336 Decode(); | 376 // the predefined number of output buffers are produced without draining |
337 ASSERT_EQ(last_decode_status(), AudioDecoder::kOk); | 377 // (i.e. decoding EOS). |
338 // Some codecs have a multiple buffer delay and require an extra | 378 do { |
339 // Decode() step to extract the desired number of output buffers. | 379 Decode(); |
340 } while (j == 0 && decoded_audio_size() == 0); | 380 ASSERT_EQ(last_decode_status(), AudioDecoder::kOk); |
| 381 } while (decoded_audio_size() < kDecodeRuns); |
341 | 382 |
342 // On the first pass record the exact MD5 hash for each decoded buffer. | 383 // With MediaCodecAudioDecoder the output buffers might appear after |
343 if (i == 0) | 384 // some delay. Since we keep decoding in a loop, the number of output |
| 385 // buffers when they eventually appear might exceed |kDecodeRuns|. |
| 386 ASSERT_LE(kDecodeRuns, decoded_audio_size()); |
| 387 |
| 388 // On the first pass record the exact MD5 hash for each decoded buffer. |
| 389 if (i == 0) { |
| 390 for (size_t j = 0; j < kDecodeRuns; ++j) |
344 decoded_audio_md5_hashes.push_back(GetDecodedAudioMD5(j)); | 391 decoded_audio_md5_hashes.push_back(GetDecodedAudioMD5(j)); |
345 } | 392 } |
346 | 393 |
347 ASSERT_EQ(kDecodeRuns, decoded_audio_size()); | |
348 | |
349 // On the first pass verify the basic audio hash and sample info. On the | 394 // On the first pass verify the basic audio hash and sample info. On the |
350 // second, verify the exact MD5 sum for each packet. It shouldn't change. | 395 // second, verify the exact MD5 sum for each packet. It shouldn't change. |
351 for (size_t j = 0; j < kDecodeRuns; ++j) { | 396 for (size_t j = 0; j < kDecodeRuns; ++j) { |
352 SCOPED_TRACE(base::StringPrintf("i = %d, j = %" PRIuS, i, j)); | 397 SCOPED_TRACE(base::StringPrintf("i = %d, j = %" PRIuS, i, j)); |
353 ExpectDecodedAudio(j, i == 0 ? "" : decoded_audio_md5_hashes[j]); | 398 ExpectDecodedAudio(j, i == 0 ? "" : decoded_audio_md5_hashes[j]); |
354 } | 399 } |
355 | 400 |
356 SendEndOfStream(); | 401 SendEndOfStream(); |
357 ASSERT_EQ(kDecodeRuns, decoded_audio_size()); | |
358 | 402 |
359 // Seek back to the beginning. Calls Reset() on the decoder. | 403 // Seek back to the beginning. Calls Reset() on the decoder. |
360 Seek(start_timestamp()); | 404 Seek(start_timestamp()); |
361 } | 405 } |
362 } | 406 } |
363 | 407 |
364 TEST_P(AudioDecoderTest, Decode) { | 408 TEST_P(AudioDecoderTest, Decode) { |
| 409 SKIP_TEST_IF_NO_MEDIA_CODEC(); |
365 ASSERT_NO_FATAL_FAILURE(Initialize()); | 410 ASSERT_NO_FATAL_FAILURE(Initialize()); |
366 Decode(); | 411 Decode(); |
367 EXPECT_EQ(AudioDecoder::kOk, last_decode_status()); | 412 EXPECT_EQ(AudioDecoder::kOk, last_decode_status()); |
368 } | 413 } |
369 | 414 |
370 TEST_P(AudioDecoderTest, Reset) { | 415 TEST_P(AudioDecoderTest, Reset) { |
| 416 SKIP_TEST_IF_NO_MEDIA_CODEC(); |
371 ASSERT_NO_FATAL_FAILURE(Initialize()); | 417 ASSERT_NO_FATAL_FAILURE(Initialize()); |
372 Reset(); | 418 Reset(); |
373 } | 419 } |
374 | 420 |
375 TEST_P(AudioDecoderTest, NoTimestamp) { | 421 TEST_P(AudioDecoderTest, NoTimestamp) { |
| 422 SKIP_TEST_IF_NO_MEDIA_CODEC(); |
376 ASSERT_NO_FATAL_FAILURE(Initialize()); | 423 ASSERT_NO_FATAL_FAILURE(Initialize()); |
377 scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0)); | 424 scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0)); |
378 buffer->set_timestamp(kNoTimestamp()); | 425 buffer->set_timestamp(kNoTimestamp()); |
379 DecodeBuffer(buffer); | 426 DecodeBuffer(buffer); |
380 EXPECT_EQ(AudioDecoder::kDecodeError, last_decode_status()); | 427 EXPECT_EQ(AudioDecoder::kDecodeError, last_decode_status()); |
381 } | 428 } |
382 | 429 |
383 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) { | 430 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) { |
384 ASSERT_EQ(GetParam().decoder_type, OPUS); | 431 ASSERT_EQ(GetParam().decoder_type, OPUS); |
385 std::vector<uint8_t> extra_data( | 432 std::vector<uint8_t> extra_data( |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 {OPUS, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE}, | 495 {OPUS, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE}, |
449 }; | 496 }; |
450 | 497 |
451 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest, | 498 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest, |
452 AudioDecoderTest, | 499 AudioDecoderTest, |
453 testing::ValuesIn(kOpusTests)); | 500 testing::ValuesIn(kOpusTests)); |
454 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest, | 501 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest, |
455 OpusAudioDecoderBehavioralTest, | 502 OpusAudioDecoderBehavioralTest, |
456 testing::ValuesIn(kOpusBehavioralTest)); | 503 testing::ValuesIn(kOpusBehavioralTest)); |
457 | 504 |
| 505 #if defined(OS_ANDROID) |
| 506 |
| 507 const DecoderTestData kMediaCodecTests[] = { |
| 508 {MEDIA_CODEC, kCodecOpus, "bear-opus.ogg", kBearOpusExpectations, 24, 48000, |
| 509 CHANNEL_LAYOUT_STEREO}, |
| 510 }; |
| 511 |
| 512 INSTANTIATE_TEST_CASE_P(MediaCodecAudioDecoderTest, |
| 513 AudioDecoderTest, |
| 514 testing::ValuesIn(kMediaCodecTests)); |
| 515 |
| 516 #else // !defined(OS_ANDROID) |
| 517 |
458 // Disable all FFmpeg decoder tests on Android. http://crbug.com/570762. | 518 // Disable all FFmpeg decoder tests on Android. http://crbug.com/570762. |
459 #if !defined(OS_ANDROID) | |
460 | 519 |
461 #if defined(USE_PROPRIETARY_CODECS) | 520 #if defined(USE_PROPRIETARY_CODECS) |
462 const DecodedBufferExpectations kSfxMp3Expectations[] = { | 521 const DecodedBufferExpectations kSfxMp3Expectations[] = { |
463 {0, 1065, "2.81,3.99,4.53,4.10,3.08,2.46,"}, | 522 {0, 1065, "2.81,3.99,4.53,4.10,3.08,2.46,"}, |
464 {1065, 26122, "-3.81,-4.14,-3.90,-3.36,-3.03,-3.23,"}, | 523 {1065, 26122, "-3.81,-4.14,-3.90,-3.36,-3.03,-3.23,"}, |
465 {27188, 26122, "4.24,3.95,4.22,4.78,5.13,4.93,"}, | 524 {27188, 26122, "4.24,3.95,4.22,4.78,5.13,4.93,"}, |
466 }; | 525 }; |
467 | 526 |
468 const DecodedBufferExpectations kSfxAdtsExpectations[] = { | 527 const DecodedBufferExpectations kSfxAdtsExpectations[] = { |
469 {0, 23219, "-1.90,-1.53,-0.15,1.28,1.23,-0.33,"}, | 528 {0, 23219, "-1.90,-1.53,-0.15,1.28,1.23,-0.33,"}, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest, | 594 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest, |
536 AudioDecoderTest, | 595 AudioDecoderTest, |
537 testing::ValuesIn(kFFmpegTests)); | 596 testing::ValuesIn(kFFmpegTests)); |
538 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest, | 597 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest, |
539 FFmpegAudioDecoderBehavioralTest, | 598 FFmpegAudioDecoderBehavioralTest, |
540 testing::ValuesIn(kFFmpegBehavioralTest)); | 599 testing::ValuesIn(kFFmpegBehavioralTest)); |
541 | 600 |
542 #endif // !defined(OS_ANDROID) | 601 #endif // !defined(OS_ANDROID) |
543 | 602 |
544 } // namespace media | 603 } // namespace media |
OLD | NEW |