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 3 // found in the LICENSE file. 4 5 #include <deque> 6 7 #include "base/bind.h" 8 #include "base/format_macros.h" 9 #include "base/md5.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/run_loop.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/sys_byteorder.h" 14 #include "build/build_config.h" 15 #include "media/base/audio_buffer.h" 16 #include "media/base/audio_bus.h" 17 #include "media/base/audio_hash.h" 18 #include "media/base/decoder_buffer.h" 19 #include "media/base/test_data_util.h" 20 #include "media/base/test_helpers.h" 21 #include "media/ffmpeg/ffmpeg_common.h" 22 #include "media/filters/audio_file_reader.h" 23 #include "media/filters/ffmpeg_audio_decoder.h" 24 #include "media/filters/in_memory_url_protocol.h" 25 #include "media/filters/opus_audio_decoder.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 28 namespace media { 29 30 // The number of packets to read and then decode from each file. 31 static const size_t kDecodeRuns = 3; 32 static const uint8_t kOpusExtraData[] = { 33 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02, 34 // The next two bytes represent the codec delay. 35 0x00, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00}; 36 37 enum AudioDecoderType { 38 FFMPEG, 39 OPUS, 40 }; 41 42 struct DecodedBufferExpectations { 43 const int64 timestamp; 44 const int64 duration; 45 const char* hash; 46 }; 47 48 struct DecoderTestData { 49 const AudioDecoderType decoder_type; 50 const AudioCodec codec; 51 const char* filename; 52 const DecodedBufferExpectations* expectations; 53 const int first_packet_pts; 54 const int samples_per_second; 55 const ChannelLayout channel_layout; 56 }; 57 58 // Tells gtest how to print our DecoderTestData structure. 59 std::ostream& operator<<(std::ostream& os, const DecoderTestData& data) { 60 return os << data.filename; 61 } 62 63 // Marks negative timestamp buffers for discard or transfers FFmpeg's built in 64 // discard metadata in favor of setting DiscardPadding on the DecoderBuffer. 65 // Allows better testing of AudioDiscardHelper usage. 66 static void SetDiscardPadding(AVPacket* packet, 67 const scoped_refptr<DecoderBuffer> buffer, 68 double samples_per_second) { 69 // Discard negative timestamps. 70 if (buffer->timestamp() + buffer->duration() < base::TimeDelta()) { 71 buffer->set_discard_padding( 72 std::make_pair(kInfiniteDuration(), base::TimeDelta())); 73 return; 74 } 75 if (buffer->timestamp() < base::TimeDelta()) { 76 buffer->set_discard_padding( 77 std::make_pair(-buffer->timestamp(), base::TimeDelta())); 78 return; 79 } 80 81 // If the timestamp is positive, try to use FFmpeg's discard data. 82 int skip_samples_size = 0; 83 const uint32* skip_samples_ptr = 84 reinterpret_cast<const uint32*>(av_packet_get_side_data( 85 packet, AV_PKT_DATA_SKIP_SAMPLES, &skip_samples_size)); 86 if (skip_samples_size < 4) 87 return; 88 buffer->set_discard_padding(std::make_pair( 89 base::TimeDelta::FromSecondsD(base::ByteSwapToLE32(*skip_samples_ptr) / 90 samples_per_second), 91 base::TimeDelta())); 92 } 93 94 class AudioDecoderTest : public testing::TestWithParam<DecoderTestData> { 95 public: 96 AudioDecoderTest() 97 : pending_decode_(false), 98 pending_reset_(false), 99 last_decode_status_(AudioDecoder::kDecodeError) { 100 switch (GetParam().decoder_type) { 101 case FFMPEG: 102 decoder_.reset(new FFmpegAudioDecoder( 103 message_loop_.message_loop_proxy(), LogCB())); 104 break; 105 case OPUS: 106 decoder_.reset( 107 new OpusAudioDecoder(message_loop_.message_loop_proxy())); 108 break; 109 } 110 } 111 112 virtual ~AudioDecoderTest() { 113 EXPECT_FALSE(pending_decode_); 114 EXPECT_FALSE(pending_reset_); 115 } 116 117 protected: 118 void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) { 119 ASSERT_FALSE(pending_decode_); 120 pending_decode_ = true; 121 last_decode_status_ = AudioDecoder::kDecodeError; 122 decoder_->Decode( 123 buffer, 124 base::Bind(&AudioDecoderTest::DecodeFinished, base::Unretained(this))); 125 base::RunLoop().RunUntilIdle(); 126 ASSERT_FALSE(pending_decode_); 127 } 128 129 void SendEndOfStream() { 130 DecodeBuffer(DecoderBuffer::CreateEOSBuffer()); 131 } 132 133 void Initialize() { 134 // Load the test data file. 135 data_ = ReadTestDataFile(GetParam().filename); 136 protocol_.reset( 137 new InMemoryUrlProtocol(data_->data(), data_->data_size(), false)); 138 reader_.reset(new AudioFileReader(protocol_.get())); 139 ASSERT_TRUE(reader_->OpenDemuxerForTesting()); 140 141 // Load the first packet and check its timestamp. 142 AVPacket packet; 143 ASSERT_TRUE(reader_->ReadPacketForTesting(&packet)); 144 EXPECT_EQ(GetParam().first_packet_pts, packet.pts); 145 start_timestamp_ = ConvertFromTimeBase( 146 reader_->GetAVStreamForTesting()->time_base, packet.pts); 147 av_free_packet(&packet); 148 149 // Seek back to the beginning. 150 ASSERT_TRUE(reader_->SeekForTesting(start_timestamp_)); 151 152 AudioDecoderConfig config; 153 AVCodecContextToAudioDecoderConfig( 154 reader_->codec_context_for_testing(), false, &config, false); 155 156 EXPECT_EQ(GetParam().codec, config.codec()); 157 EXPECT_EQ(GetParam().samples_per_second, config.samples_per_second()); 158 EXPECT_EQ(GetParam().channel_layout, config.channel_layout()); 159 160 InitializeDecoder(config); 161 } 162 163 void InitializeDecoder(const AudioDecoderConfig& config) { 164 InitializeDecoderWithStatus(config, PIPELINE_OK); 165 } 166 167 void InitializeDecoderWithStatus(const AudioDecoderConfig& config, 168 PipelineStatus status) { 169 decoder_->Initialize( 170 config, 171 NewExpectedStatusCB(status), 172 base::Bind(&AudioDecoderTest::OnDecoderOutput, base::Unretained(this))); 173 base::RunLoop().RunUntilIdle(); 174 } 175 176 void Decode() { 177 AVPacket packet; 178 ASSERT_TRUE(reader_->ReadPacketForTesting(&packet)); 179 180 // Split out packet metadata before making a copy. 181 av_packet_split_side_data(&packet); 182 183 scoped_refptr<DecoderBuffer> buffer = 184 DecoderBuffer::CopyFrom(packet.data, packet.size); 185 buffer->set_timestamp(ConvertFromTimeBase( 186 reader_->GetAVStreamForTesting()->time_base, packet.pts)); 187 buffer->set_duration(ConvertFromTimeBase( 188 reader_->GetAVStreamForTesting()->time_base, packet.duration)); 189 190 // Don't set discard padding for Opus, it already has discard behavior set 191 // based on the codec delay in the AudioDecoderConfig. 192 if (GetParam().decoder_type == FFMPEG) 193 SetDiscardPadding(&packet, buffer, GetParam().samples_per_second); 194 195 // DecodeBuffer() shouldn't need the original packet since it uses the copy. 196 av_free_packet(&packet); 197 DecodeBuffer(buffer); 198 } 199 200 void Reset() { 201 ASSERT_FALSE(pending_reset_); 202 pending_reset_ = true; 203 decoder_->Reset( 204 base::Bind(&AudioDecoderTest::ResetFinished, base::Unretained(this))); 205 base::RunLoop().RunUntilIdle(); 206 ASSERT_FALSE(pending_reset_); 207 } 208 209 void Seek(base::TimeDelta seek_time) { 210 Reset(); 211 decoded_audio_.clear(); 212 ASSERT_TRUE(reader_->SeekForTesting(seek_time)); 213 } 214 215 void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) { 216 EXPECT_FALSE(buffer->end_of_stream()); 217 decoded_audio_.push_back(buffer); 218 } 219 220 void DecodeFinished(AudioDecoder::Status status) { 221 EXPECT_TRUE(pending_decode_); 222 EXPECT_FALSE(pending_reset_); 223 pending_decode_ = false; 224 last_decode_status_ = status; 225 } 226 227 void ResetFinished() { 228 EXPECT_TRUE(pending_reset_); 229 EXPECT_FALSE(pending_decode_); 230 pending_reset_ = false; 231 } 232 233 // Generates an MD5 hash of the audio signal. Should not be used for checks 234 // across platforms as audio varies slightly across platforms. 235 std::string GetDecodedAudioMD5(size_t i) { 236 CHECK_LT(i, decoded_audio_.size()); 237 const scoped_refptr<AudioBuffer>& buffer = decoded_audio_[i]; 238 239 scoped_ptr<AudioBus> output = 240 AudioBus::Create(buffer->channel_count(), buffer->frame_count()); 241 buffer->ReadFrames(buffer->frame_count(), 0, 0, output.get()); 242 243 base::MD5Context context; 244 base::MD5Init(&context); 245 for (int ch = 0; ch < output->channels(); ++ch) { 246 base::MD5Update( 247 &context, 248 base::StringPiece(reinterpret_cast<char*>(output->channel(ch)), 249 output->frames() * sizeof(*output->channel(ch)))); 250 } 251 base::MD5Digest digest; 252 base::MD5Final(&digest, &context); 253 return base::MD5DigestToBase16(digest); 254 } 255 256 void ExpectDecodedAudio(size_t i, const std::string& exact_hash) { 257 CHECK_LT(i, decoded_audio_.size()); 258 const scoped_refptr<AudioBuffer>& buffer = decoded_audio_[i]; 259 260 const DecodedBufferExpectations& sample_info = GetParam().expectations[i]; 261 EXPECT_EQ(sample_info.timestamp, buffer->timestamp().InMicroseconds()); 262 EXPECT_EQ(sample_info.duration, buffer->duration().InMicroseconds()); 263 EXPECT_FALSE(buffer->end_of_stream()); 264 265 scoped_ptr<AudioBus> output = 266 AudioBus::Create(buffer->channel_count(), buffer->frame_count()); 267 buffer->ReadFrames(buffer->frame_count(), 0, 0, output.get()); 268 269 // Generate a lossy hash of the audio used for comparison across platforms. 270 AudioHash audio_hash; 271 audio_hash.Update(output.get(), output->frames()); 272 EXPECT_EQ(sample_info.hash, audio_hash.ToString()); 273 274 if (!exact_hash.empty()) { 275 EXPECT_EQ(exact_hash, GetDecodedAudioMD5(i)); 276 277 // Verify different hashes are being generated. None of our test data 278 // files have audio that hashes out exactly the same. 279 if (i > 0) 280 EXPECT_NE(exact_hash, GetDecodedAudioMD5(i - 1)); 281 } 282 } 283 284 size_t decoded_audio_size() const { return decoded_audio_.size(); } 285 base::TimeDelta start_timestamp() const { return start_timestamp_; } 286 const scoped_refptr<AudioBuffer>& decoded_audio(size_t i) { 287 return decoded_audio_[i]; 288 } 289 AudioDecoder::Status last_decode_status() const { 290 return last_decode_status_; 291 } 292 293 private: 294 base::MessageLoop message_loop_; 295 scoped_refptr<DecoderBuffer> data_; 296 scoped_ptr<InMemoryUrlProtocol> protocol_; 297 scoped_ptr<AudioFileReader> reader_; 298 299 scoped_ptr<AudioDecoder> decoder_; 300 bool pending_decode_; 301 bool pending_reset_; 302 AudioDecoder::Status last_decode_status_; 303 304 std::deque<scoped_refptr<AudioBuffer> > decoded_audio_; 305 base::TimeDelta start_timestamp_; 306 307 DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest); 308 }; 309 310 class OpusAudioDecoderBehavioralTest : public AudioDecoderTest {}; 311 class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {}; 312 313 TEST_P(AudioDecoderTest, Initialize) { 314 ASSERT_NO_FATAL_FAILURE(Initialize()); 315 } 316 317 // Verifies decode audio as well as the Decode() -> Reset() sequence. 318 TEST_P(AudioDecoderTest, ProduceAudioSamples) { 319 ASSERT_NO_FATAL_FAILURE(Initialize()); 320 321 // Run the test multiple times with a seek back to the beginning in between. 322 std::vector<std::string> decoded_audio_md5_hashes; 323 for (int i = 0; i < 2; ++i) { 324 for (size_t j = 0; j < kDecodeRuns; ++j) { 325 do { 326 Decode(); 327 ASSERT_EQ(last_decode_status(), AudioDecoder::kOk); 328 // Some codecs have a multiple buffer delay and require an extra 329 // Decode() step to extract the desired number of output buffers. 330 } while (j == 0 && decoded_audio_size() == 0); 331 332 // On the first pass record the exact MD5 hash for each decoded buffer. 333 if (i == 0) 334 decoded_audio_md5_hashes.push_back(GetDecodedAudioMD5(j)); 335 } 336 337 ASSERT_EQ(kDecodeRuns, decoded_audio_size()); 338 339 // On the first pass verify the basic audio hash and sample info. On the 340 // second, verify the exact MD5 sum for each packet. It shouldn't change. 341 for (size_t j = 0; j < kDecodeRuns; ++j) { 342 SCOPED_TRACE(base::StringPrintf("i = %d, j = %" PRIuS, i, j)); 343 ExpectDecodedAudio(j, i == 0 ? "" : decoded_audio_md5_hashes[j]); 344 } 345 346 SendEndOfStream(); 347 ASSERT_EQ(kDecodeRuns, decoded_audio_size()); 348 349 // Seek back to the beginning. Calls Reset() on the decoder. 350 Seek(start_timestamp()); 351 } 352 } 353 354 TEST_P(AudioDecoderTest, Decode) { 355 ASSERT_NO_FATAL_FAILURE(Initialize()); 356 Decode(); 357 EXPECT_EQ(AudioDecoder::kOk, last_decode_status()); 358 } 359 360 TEST_P(AudioDecoderTest, Reset) { 361 ASSERT_NO_FATAL_FAILURE(Initialize()); 362 Reset(); 363 } 364 365 TEST_P(AudioDecoderTest, NoTimestamp) { 366 ASSERT_NO_FATAL_FAILURE(Initialize()); 367 scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0)); 368 buffer->set_timestamp(kNoTimestamp()); 369 DecodeBuffer(buffer); 370 EXPECT_EQ(AudioDecoder::kDecodeError, last_decode_status()); 371 } 372 373 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) { 374 ASSERT_EQ(GetParam().decoder_type, OPUS); 375 AudioDecoderConfig decoder_config; 376 decoder_config.Initialize(kCodecOpus, 377 kSampleFormatF32, 378 CHANNEL_LAYOUT_STEREO, 379 48000, 380 kOpusExtraData, 381 ARRAYSIZE_UNSAFE(kOpusExtraData), 382 false, 383 false, 384 base::TimeDelta::FromMilliseconds(80), 385 0); 386 InitializeDecoder(decoder_config); 387 } 388 389 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithBadCodecDelay) { 390 ASSERT_EQ(GetParam().decoder_type, OPUS); 391 AudioDecoderConfig decoder_config; 392 decoder_config.Initialize( 393 kCodecOpus, 394 kSampleFormatF32, 395 CHANNEL_LAYOUT_STEREO, 396 48000, 397 kOpusExtraData, 398 ARRAYSIZE_UNSAFE(kOpusExtraData), 399 false, 400 false, 401 base::TimeDelta::FromMilliseconds(80), 402 // Use a different codec delay than in the extradata. 403 100); 404 InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED); 405 } 406 407 TEST_P(FFmpegAudioDecoderBehavioralTest, InitializeWithBadConfig) { 408 const AudioDecoderConfig decoder_config(kCodecVorbis, 409 kSampleFormatF32, 410 CHANNEL_LAYOUT_STEREO, 411 // Invalid sample rate of zero. 412 0, 413 NULL, 414 0, 415 false); 416 InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED); 417 } 418 419 const DecodedBufferExpectations kSfxOpusExpectations[] = { 420 {0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"}, 421 {13500, 20000, "5.48,5.93,6.04,5.83,5.54,5.45,"}, 422 {33500, 20000, "-3.45,-3.35,-3.57,-4.12,-4.74,-5.14,"}, 423 }; 424 425 const DecodedBufferExpectations kBearOpusExpectations[] = { 426 {500, 3500, "-0.26,0.87,1.36,0.84,-0.30,-1.22,"}, 427 {4000, 10000, "0.09,0.23,0.21,0.03,-0.17,-0.24,"}, 428 {14000, 10000, "0.10,0.24,0.23,0.04,-0.14,-0.23,"}, 429 }; 430 431 const DecoderTestData kOpusTests[] = { 432 {OPUS, kCodecOpus, "sfx-opus.ogg", kSfxOpusExpectations, -312, 48000, 433 CHANNEL_LAYOUT_MONO}, 434 {OPUS, kCodecOpus, "bear-opus.ogg", kBearOpusExpectations, 24, 48000, 435 CHANNEL_LAYOUT_STEREO}, 436 }; 437 438 // Dummy data for behavioral tests. 439 const DecoderTestData kOpusBehavioralTest[] = { 440 {OPUS, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE}, 441 }; 442 443 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest, 444 AudioDecoderTest, 445 testing::ValuesIn(kOpusTests)); 446 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest, 447 OpusAudioDecoderBehavioralTest, 448 testing::ValuesIn(kOpusBehavioralTest)); 449 450 #if defined(USE_PROPRIETARY_CODECS) 451 const DecodedBufferExpectations kSfxMp3Expectations[] = { 452 {0, 1065, "2.81,3.99,4.53,4.10,3.08,2.46,"}, 453 {1065, 26122, "-3.81,-4.14,-3.90,-3.36,-3.03,-3.23,"}, 454 {27188, 26122, "4.24,3.95,4.22,4.78,5.13,4.93,"}, 455 }; 456 457 const DecodedBufferExpectations kSfxAdtsExpectations[] = { 458 {0, 23219, "-1.90,-1.53,-0.15,1.28,1.23,-0.33,"}, 459 {23219, 23219, "0.54,0.88,2.19,3.54,3.24,1.63,"}, 460 {46439, 23219, "1.42,1.69,2.95,4.23,4.02,2.36,"}, 461 }; 462 #endif 463 464 #if defined(OS_CHROMEOS) 465 const DecodedBufferExpectations kSfxFlacExpectations[] = { 466 {0, 104489, "-2.42,-1.12,0.71,1.70,1.09,-0.68,"}, 467 {104489, 104489, "-1.99,-0.67,1.18,2.19,1.60,-0.16,"}, 468 {208979, 79433, "2.84,2.70,3.23,4.06,4.59,4.44,"}, 469 }; 470 #endif 471 472 const DecodedBufferExpectations kSfxWaveExpectations[] = { 473 {0, 23219, "-1.23,-0.87,0.47,1.85,1.88,0.29,"}, 474 {23219, 23219, "0.75,1.10,2.43,3.78,3.53,1.93,"}, 475 {46439, 23219, "1.27,1.56,2.83,4.13,3.87,2.23,"}, 476 }; 477 478 const DecodedBufferExpectations kFourChannelWaveExpectations[] = { 479 {0, 11609, "-1.68,1.68,0.89,-3.45,1.52,1.15,"}, 480 {11609, 11609, "43.26,9.06,18.27,35.98,19.45,7.46,"}, 481 {23219, 11609, "36.37,9.45,16.04,27.67,18.81,10.15,"}, 482 }; 483 484 const DecodedBufferExpectations kSfxOggExpectations[] = { 485 {0, 13061, "-0.33,1.25,2.86,3.26,2.09,0.14,"}, 486 {13061, 23219, "-2.79,-2.42,-1.06,0.33,0.93,-0.64,"}, 487 {36281, 23219, "-1.19,-0.80,0.57,1.97,2.08,0.51,"}, 488 }; 489 490 const DecodedBufferExpectations kBearOgvExpectations[] = { 491 {0, 13061, "-1.25,0.10,2.11,2.29,1.50,-0.68,"}, 492 {13061, 23219, "-1.80,-1.41,-0.13,1.30,1.65,0.01,"}, 493 {36281, 23219, "-1.43,-1.25,0.11,1.29,1.86,0.14,"}, 494 }; 495 496 const DecoderTestData kFFmpegTests[] = { 497 #if defined(USE_PROPRIETARY_CODECS) 498 {FFMPEG, kCodecMP3, "sfx.mp3", kSfxMp3Expectations, 0, 44100, 499 CHANNEL_LAYOUT_MONO}, 500 {FFMPEG, kCodecAAC, "sfx.adts", kSfxAdtsExpectations, 0, 44100, 501 CHANNEL_LAYOUT_MONO}, 502 #endif 503 #if defined(OS_CHROMEOS) 504 {FFMPEG, kCodecFLAC, "sfx.flac", kSfxFlacExpectations, 0, 44100, 505 CHANNEL_LAYOUT_MONO}, 506 #endif 507 {FFMPEG, kCodecPCM, "sfx_f32le.wav", kSfxWaveExpectations, 0, 44100, 508 CHANNEL_LAYOUT_MONO}, 509 {FFMPEG, kCodecPCM, "4ch.wav", kFourChannelWaveExpectations, 0, 44100, 510 CHANNEL_LAYOUT_QUAD}, 511 {FFMPEG, kCodecVorbis, "sfx.ogg", kSfxOggExpectations, 0, 44100, 512 CHANNEL_LAYOUT_MONO}, 513 // Note: bear.ogv is incorrectly muxed such that valid samples are given 514 // negative timestamps, this marks them for discard per the ogg vorbis spec. 515 {FFMPEG, kCodecVorbis, "bear.ogv", kBearOgvExpectations, -704, 44100, 516 CHANNEL_LAYOUT_STEREO}, 517 }; 518 519 // Dummy data for behavioral tests. 520 const DecoderTestData kFFmpegBehavioralTest[] = { 521 {FFMPEG, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE}, 522 }; 523 524 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest, 525 AudioDecoderTest, 526 testing::ValuesIn(kFFmpegTests)); 527 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest, 528 FFmpegAudioDecoderBehavioralTest, 529 testing::ValuesIn(kFFmpegBehavioralTest)); 530 531 } // namespace media 532