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
28namespace media {
29
30// The number of packets to read and then decode from each file.
31static const size_t kDecodeRuns = 3;
32static 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
37enum AudioDecoderType {
38  FFMPEG,
39  OPUS,
40};
41
42struct DecodedBufferExpectations {
43  const int64 timestamp;
44  const int64 duration;
45  const char* hash;
46};
47
48struct 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.
59std::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.
66static 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
94class 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
310class OpusAudioDecoderBehavioralTest : public AudioDecoderTest {};
311class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {};
312
313TEST_P(AudioDecoderTest, Initialize) {
314  ASSERT_NO_FATAL_FAILURE(Initialize());
315}
316
317// Verifies decode audio as well as the Decode() -> Reset() sequence.
318TEST_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
354TEST_P(AudioDecoderTest, Decode) {
355  ASSERT_NO_FATAL_FAILURE(Initialize());
356  Decode();
357  EXPECT_EQ(AudioDecoder::kOk, last_decode_status());
358}
359
360TEST_P(AudioDecoderTest, Reset) {
361  ASSERT_NO_FATAL_FAILURE(Initialize());
362  Reset();
363}
364
365TEST_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
373TEST_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
389TEST_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
407TEST_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
419const 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
425const 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
431const 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.
439const DecoderTestData kOpusBehavioralTest[] = {
440    {OPUS, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE},
441};
442
443INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest,
444                        AudioDecoderTest,
445                        testing::ValuesIn(kOpusTests));
446INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest,
447                        OpusAudioDecoderBehavioralTest,
448                        testing::ValuesIn(kOpusBehavioralTest));
449
450#if defined(USE_PROPRIETARY_CODECS)
451const 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
457const 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)
465const 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
472const 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
478const 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
484const 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
490const 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
496const 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.
520const DecoderTestData kFFmpegBehavioralTest[] = {
521    {FFMPEG, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE},
522};
523
524INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest,
525                        AudioDecoderTest,
526                        testing::ValuesIn(kFFmpegTests));
527INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest,
528                        FFmpegAudioDecoderBehavioralTest,
529                        testing::ValuesIn(kFFmpegBehavioralTest));
530
531}  // namespace media
532