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