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.
8 #include "base/format_macros.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"
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};
37 enum AudioDecoderType
{
42 struct DecodedBufferExpectations
{
43 const int64 timestamp
;
48 struct DecoderTestData
{
49 const AudioDecoderType decoder_type
;
50 const AudioCodec codec
;
52 const DecodedBufferExpectations
* expectations
;
53 const int first_packet_pts
;
54 const int samples_per_second
;
55 const ChannelLayout channel_layout
;
58 // Tells gtest how to print our DecoderTestData structure.
59 std::ostream
& operator<<(std::ostream
& os
, const DecoderTestData
& data
) {
60 return os
<< data
.filename
;
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()));
75 if (buffer
->timestamp() < base::TimeDelta()) {
76 buffer
->set_discard_padding(
77 std::make_pair(-buffer
->timestamp(), base::TimeDelta()));
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)
88 buffer
->set_discard_padding(std::make_pair(
89 base::TimeDelta::FromSecondsD(base::ByteSwapToLE32(*skip_samples_ptr
) /
94 class AudioDecoderTest
: public testing::TestWithParam
<DecoderTestData
> {
97 : pending_decode_(false),
98 pending_reset_(false),
99 last_decode_status_(AudioDecoder::kDecodeError
) {
100 switch (GetParam().decoder_type
) {
102 decoder_
.reset(new FFmpegAudioDecoder(message_loop_
.task_runner(),
107 new OpusAudioDecoder(message_loop_
.task_runner()));
112 virtual ~AudioDecoderTest() {
113 EXPECT_FALSE(pending_decode_
);
114 EXPECT_FALSE(pending_reset_
);
118 void DecodeBuffer(const scoped_refptr
<DecoderBuffer
>& buffer
) {
119 ASSERT_FALSE(pending_decode_
);
120 pending_decode_
= true;
121 last_decode_status_
= AudioDecoder::kDecodeError
;
124 base::Bind(&AudioDecoderTest::DecodeFinished
, base::Unretained(this)));
125 base::RunLoop().RunUntilIdle();
126 ASSERT_FALSE(pending_decode_
);
129 void SendEndOfStream() {
130 DecodeBuffer(DecoderBuffer::CreateEOSBuffer());
134 // Load the test data file.
135 data_
= ReadTestDataFile(GetParam().filename
);
137 new InMemoryUrlProtocol(data_
->data(), data_
->data_size(), false));
138 reader_
.reset(new AudioFileReader(protocol_
.get()));
139 ASSERT_TRUE(reader_
->OpenDemuxerForTesting());
141 // Load the first packet and check its timestamp.
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
);
149 // Seek back to the beginning.
150 ASSERT_TRUE(reader_
->SeekForTesting(start_timestamp_
));
152 AudioDecoderConfig config
;
153 AVCodecContextToAudioDecoderConfig(
154 reader_
->codec_context_for_testing(), false, &config
, false);
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());
160 InitializeDecoder(config
);
163 void InitializeDecoder(const AudioDecoderConfig
& config
) {
164 InitializeDecoderWithResult(config
, true);
167 void InitializeDecoderWithResult(const AudioDecoderConfig
& config
,
169 decoder_
->Initialize(
170 config
, NewExpectedBoolCB(success
),
171 base::Bind(&AudioDecoderTest::OnDecoderOutput
, base::Unretained(this)));
172 base::RunLoop().RunUntilIdle();
177 ASSERT_TRUE(reader_
->ReadPacketForTesting(&packet
));
179 // Split out packet metadata before making a copy.
180 av_packet_split_side_data(&packet
);
182 scoped_refptr
<DecoderBuffer
> buffer
=
183 DecoderBuffer::CopyFrom(packet
.data
, packet
.size
);
184 buffer
->set_timestamp(ConvertFromTimeBase(
185 reader_
->GetAVStreamForTesting()->time_base
, packet
.pts
));
186 buffer
->set_duration(ConvertFromTimeBase(
187 reader_
->GetAVStreamForTesting()->time_base
, packet
.duration
));
188 if (packet
.flags
& AV_PKT_FLAG_KEY
)
189 buffer
->set_is_key_frame(true);
191 // Don't set discard padding for Opus, it already has discard behavior set
192 // based on the codec delay in the AudioDecoderConfig.
193 if (GetParam().decoder_type
== FFMPEG
)
194 SetDiscardPadding(&packet
, buffer
, GetParam().samples_per_second
);
196 // DecodeBuffer() shouldn't need the original packet since it uses the copy.
197 av_free_packet(&packet
);
198 DecodeBuffer(buffer
);
202 ASSERT_FALSE(pending_reset_
);
203 pending_reset_
= true;
205 base::Bind(&AudioDecoderTest::ResetFinished
, base::Unretained(this)));
206 base::RunLoop().RunUntilIdle();
207 ASSERT_FALSE(pending_reset_
);
210 void Seek(base::TimeDelta seek_time
) {
212 decoded_audio_
.clear();
213 ASSERT_TRUE(reader_
->SeekForTesting(seek_time
));
216 void OnDecoderOutput(const scoped_refptr
<AudioBuffer
>& buffer
) {
217 EXPECT_FALSE(buffer
->end_of_stream());
218 decoded_audio_
.push_back(buffer
);
221 void DecodeFinished(AudioDecoder::Status status
) {
222 EXPECT_TRUE(pending_decode_
);
223 EXPECT_FALSE(pending_reset_
);
224 pending_decode_
= false;
225 last_decode_status_
= status
;
228 void ResetFinished() {
229 EXPECT_TRUE(pending_reset_
);
230 EXPECT_FALSE(pending_decode_
);
231 pending_reset_
= false;
234 // Generates an MD5 hash of the audio signal. Should not be used for checks
235 // across platforms as audio varies slightly across platforms.
236 std::string
GetDecodedAudioMD5(size_t i
) {
237 CHECK_LT(i
, decoded_audio_
.size());
238 const scoped_refptr
<AudioBuffer
>& buffer
= decoded_audio_
[i
];
240 scoped_ptr
<AudioBus
> output
=
241 AudioBus::Create(buffer
->channel_count(), buffer
->frame_count());
242 buffer
->ReadFrames(buffer
->frame_count(), 0, 0, output
.get());
244 base::MD5Context context
;
245 base::MD5Init(&context
);
246 for (int ch
= 0; ch
< output
->channels(); ++ch
) {
249 base::StringPiece(reinterpret_cast<char*>(output
->channel(ch
)),
250 output
->frames() * sizeof(*output
->channel(ch
))));
252 base::MD5Digest digest
;
253 base::MD5Final(&digest
, &context
);
254 return base::MD5DigestToBase16(digest
);
257 void ExpectDecodedAudio(size_t i
, const std::string
& exact_hash
) {
258 CHECK_LT(i
, decoded_audio_
.size());
259 const scoped_refptr
<AudioBuffer
>& buffer
= decoded_audio_
[i
];
261 const DecodedBufferExpectations
& sample_info
= GetParam().expectations
[i
];
262 EXPECT_EQ(sample_info
.timestamp
, buffer
->timestamp().InMicroseconds());
263 EXPECT_EQ(sample_info
.duration
, buffer
->duration().InMicroseconds());
264 EXPECT_FALSE(buffer
->end_of_stream());
266 scoped_ptr
<AudioBus
> output
=
267 AudioBus::Create(buffer
->channel_count(), buffer
->frame_count());
268 buffer
->ReadFrames(buffer
->frame_count(), 0, 0, output
.get());
270 // Generate a lossy hash of the audio used for comparison across platforms.
271 AudioHash audio_hash
;
272 audio_hash
.Update(output
.get(), output
->frames());
273 EXPECT_EQ(sample_info
.hash
, audio_hash
.ToString());
275 if (!exact_hash
.empty()) {
276 EXPECT_EQ(exact_hash
, GetDecodedAudioMD5(i
));
278 // Verify different hashes are being generated. None of our test data
279 // files have audio that hashes out exactly the same.
281 EXPECT_NE(exact_hash
, GetDecodedAudioMD5(i
- 1));
285 size_t decoded_audio_size() const { return decoded_audio_
.size(); }
286 base::TimeDelta
start_timestamp() const { return start_timestamp_
; }
287 const scoped_refptr
<AudioBuffer
>& decoded_audio(size_t i
) {
288 return decoded_audio_
[i
];
290 AudioDecoder::Status
last_decode_status() const {
291 return last_decode_status_
;
295 base::MessageLoop message_loop_
;
296 scoped_refptr
<DecoderBuffer
> data_
;
297 scoped_ptr
<InMemoryUrlProtocol
> protocol_
;
298 scoped_ptr
<AudioFileReader
> reader_
;
300 scoped_ptr
<AudioDecoder
> decoder_
;
301 bool pending_decode_
;
303 AudioDecoder::Status last_decode_status_
;
305 std::deque
<scoped_refptr
<AudioBuffer
> > decoded_audio_
;
306 base::TimeDelta start_timestamp_
;
308 DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest
);
311 class OpusAudioDecoderBehavioralTest
: public AudioDecoderTest
{};
312 class FFmpegAudioDecoderBehavioralTest
: public AudioDecoderTest
{};
314 TEST_P(AudioDecoderTest
, Initialize
) {
315 ASSERT_NO_FATAL_FAILURE(Initialize());
318 // Verifies decode audio as well as the Decode() -> Reset() sequence.
319 TEST_P(AudioDecoderTest
, ProduceAudioSamples
) {
320 ASSERT_NO_FATAL_FAILURE(Initialize());
322 // Run the test multiple times with a seek back to the beginning in between.
323 std::vector
<std::string
> decoded_audio_md5_hashes
;
324 for (int i
= 0; i
< 2; ++i
) {
325 for (size_t j
= 0; j
< kDecodeRuns
; ++j
) {
328 ASSERT_EQ(last_decode_status(), AudioDecoder::kOk
);
329 // Some codecs have a multiple buffer delay and require an extra
330 // Decode() step to extract the desired number of output buffers.
331 } while (j
== 0 && decoded_audio_size() == 0);
333 // On the first pass record the exact MD5 hash for each decoded buffer.
335 decoded_audio_md5_hashes
.push_back(GetDecodedAudioMD5(j
));
338 ASSERT_EQ(kDecodeRuns
, decoded_audio_size());
340 // On the first pass verify the basic audio hash and sample info. On the
341 // second, verify the exact MD5 sum for each packet. It shouldn't change.
342 for (size_t j
= 0; j
< kDecodeRuns
; ++j
) {
343 SCOPED_TRACE(base::StringPrintf("i = %d, j = %" PRIuS
, i
, j
));
344 ExpectDecodedAudio(j
, i
== 0 ? "" : decoded_audio_md5_hashes
[j
]);
348 ASSERT_EQ(kDecodeRuns
, decoded_audio_size());
350 // Seek back to the beginning. Calls Reset() on the decoder.
351 Seek(start_timestamp());
355 TEST_P(AudioDecoderTest
, Decode
) {
356 ASSERT_NO_FATAL_FAILURE(Initialize());
358 EXPECT_EQ(AudioDecoder::kOk
, last_decode_status());
361 TEST_P(AudioDecoderTest
, Reset
) {
362 ASSERT_NO_FATAL_FAILURE(Initialize());
366 TEST_P(AudioDecoderTest
, NoTimestamp
) {
367 ASSERT_NO_FATAL_FAILURE(Initialize());
368 scoped_refptr
<DecoderBuffer
> buffer(new DecoderBuffer(0));
369 buffer
->set_timestamp(kNoTimestamp());
370 DecodeBuffer(buffer
);
371 EXPECT_EQ(AudioDecoder::kDecodeError
, last_decode_status());
374 TEST_P(OpusAudioDecoderBehavioralTest
, InitializeWithNoCodecDelay
) {
375 ASSERT_EQ(GetParam().decoder_type
, OPUS
);
376 AudioDecoderConfig decoder_config
;
377 decoder_config
.Initialize(kCodecOpus
,
379 CHANNEL_LAYOUT_STEREO
,
382 arraysize(kOpusExtraData
),
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(
396 CHANNEL_LAYOUT_STEREO
,
399 arraysize(kOpusExtraData
),
402 base::TimeDelta::FromMilliseconds(80),
403 // Use a different codec delay than in the extradata.
405 InitializeDecoderWithResult(decoder_config
, false);
408 TEST_P(FFmpegAudioDecoderBehavioralTest
, InitializeWithBadConfig
) {
409 const AudioDecoderConfig
decoder_config(kCodecVorbis
,
411 CHANNEL_LAYOUT_STEREO
,
412 // Invalid sample rate of zero.
417 InitializeDecoderWithResult(decoder_config
, false);
420 #if defined(OPUS_FIXED_POINT)
421 const DecodedBufferExpectations kSfxOpusExpectations
[] = {
422 {0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"},
423 {13500, 20000, "5.48,5.93,6.05,5.83,5.54,5.46,"},
424 {33500, 20000, "-3.44,-3.34,-3.57,-4.11,-4.74,-5.13,"},
427 const DecodedBufferExpectations kSfxOpusExpectations
[] = {
428 {0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"},
429 {13500, 20000, "5.48,5.93,6.04,5.83,5.54,5.45,"},
430 {33500, 20000, "-3.45,-3.35,-3.57,-4.12,-4.74,-5.14,"},
434 const DecodedBufferExpectations kBearOpusExpectations
[] = {
435 {500, 3500, "-0.26,0.87,1.36,0.84,-0.30,-1.22,"},
436 {4000, 10000, "0.09,0.23,0.21,0.03,-0.17,-0.24,"},
437 {14000, 10000, "0.10,0.24,0.23,0.04,-0.14,-0.23,"},
440 const DecoderTestData kOpusTests
[] = {
441 {OPUS
, kCodecOpus
, "sfx-opus.ogg", kSfxOpusExpectations
, -312, 48000,
442 CHANNEL_LAYOUT_MONO
},
443 {OPUS
, kCodecOpus
, "bear-opus.ogg", kBearOpusExpectations
, 24, 48000,
444 CHANNEL_LAYOUT_STEREO
},
447 // Dummy data for behavioral tests.
448 const DecoderTestData kOpusBehavioralTest
[] = {
449 {OPUS
, kUnknownAudioCodec
, "", NULL
, 0, 0, CHANNEL_LAYOUT_NONE
},
452 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest
,
454 testing::ValuesIn(kOpusTests
));
455 INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest
,
456 OpusAudioDecoderBehavioralTest
,
457 testing::ValuesIn(kOpusBehavioralTest
));
459 #if defined(USE_PROPRIETARY_CODECS)
460 const DecodedBufferExpectations kSfxMp3Expectations
[] = {
461 {0, 1065, "2.81,3.99,4.53,4.10,3.08,2.46,"},
462 {1065, 26122, "-3.81,-4.14,-3.90,-3.36,-3.03,-3.23,"},
463 {27188, 26122, "4.24,3.95,4.22,4.78,5.13,4.93,"},
466 const DecodedBufferExpectations kSfxAdtsExpectations
[] = {
467 {0, 23219, "-1.90,-1.53,-0.15,1.28,1.23,-0.33,"},
468 {23219, 23219, "0.54,0.88,2.19,3.54,3.24,1.63,"},
469 {46439, 23219, "1.42,1.69,2.95,4.23,4.02,2.36,"},
473 #if defined(OS_CHROMEOS)
474 const DecodedBufferExpectations kSfxFlacExpectations
[] = {
475 {0, 104489, "-2.42,-1.12,0.71,1.70,1.09,-0.68,"},
476 {104489, 104489, "-1.99,-0.67,1.18,2.19,1.60,-0.16,"},
477 {208979, 79433, "2.84,2.70,3.23,4.06,4.59,4.44,"},
481 const DecodedBufferExpectations kSfxWaveExpectations
[] = {
482 {0, 23219, "-1.23,-0.87,0.47,1.85,1.88,0.29,"},
483 {23219, 23219, "0.75,1.10,2.43,3.78,3.53,1.93,"},
484 {46439, 23219, "1.27,1.56,2.83,4.13,3.87,2.23,"},
487 const DecodedBufferExpectations kFourChannelWaveExpectations
[] = {
488 {0, 11609, "-1.68,1.68,0.89,-3.45,1.52,1.15,"},
489 {11609, 11609, "43.26,9.06,18.27,35.98,19.45,7.46,"},
490 {23219, 11609, "36.37,9.45,16.04,27.67,18.81,10.15,"},
493 const DecodedBufferExpectations kSfxOggExpectations
[] = {
494 {0, 13061, "-0.33,1.25,2.86,3.26,2.09,0.14,"},
495 {13061, 23219, "-2.79,-2.42,-1.06,0.33,0.93,-0.64,"},
496 {36281, 23219, "-1.19,-0.80,0.57,1.97,2.08,0.51,"},
499 const DecodedBufferExpectations kBearOgvExpectations
[] = {
500 {0, 13061, "-1.25,0.10,2.11,2.29,1.50,-0.68,"},
501 {13061, 23219, "-1.80,-1.41,-0.13,1.30,1.65,0.01,"},
502 {36281, 23219, "-1.43,-1.25,0.11,1.29,1.86,0.14,"},
505 const DecoderTestData kFFmpegTests
[] = {
506 #if defined(USE_PROPRIETARY_CODECS)
507 {FFMPEG
, kCodecMP3
, "sfx.mp3", kSfxMp3Expectations
, 0, 44100,
508 CHANNEL_LAYOUT_MONO
},
509 {FFMPEG
, kCodecAAC
, "sfx.adts", kSfxAdtsExpectations
, 0, 44100,
510 CHANNEL_LAYOUT_MONO
},
512 #if defined(OS_CHROMEOS)
513 {FFMPEG
, kCodecFLAC
, "sfx.flac", kSfxFlacExpectations
, 0, 44100,
514 CHANNEL_LAYOUT_MONO
},
516 {FFMPEG
, kCodecPCM
, "sfx_f32le.wav", kSfxWaveExpectations
, 0, 44100,
517 CHANNEL_LAYOUT_MONO
},
518 {FFMPEG
, kCodecPCM
, "4ch.wav", kFourChannelWaveExpectations
, 0, 44100,
519 CHANNEL_LAYOUT_QUAD
},
520 {FFMPEG
, kCodecVorbis
, "sfx.ogg", kSfxOggExpectations
, 0, 44100,
521 CHANNEL_LAYOUT_MONO
},
522 // Note: bear.ogv is incorrectly muxed such that valid samples are given
523 // negative timestamps, this marks them for discard per the ogg vorbis spec.
524 {FFMPEG
, kCodecVorbis
, "bear.ogv", kBearOgvExpectations
, -704, 44100,
525 CHANNEL_LAYOUT_STEREO
},
528 // Dummy data for behavioral tests.
529 const DecoderTestData kFFmpegBehavioralTest
[] = {
530 {FFMPEG
, kUnknownAudioCodec
, "", NULL
, 0, 0, CHANNEL_LAYOUT_NONE
},
533 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest
,
535 testing::ValuesIn(kFFmpegTests
));
536 INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest
,
537 FFmpegAudioDecoderBehavioralTest
,
538 testing::ValuesIn(kFFmpegBehavioralTest
));