Consolidate and improve audio decoding test for all decoders.

- Consolidates FFmpegAudioDecoder and OpusAudioDecoder unittests
since they were identical anyways.
- Extends the AudioFileReader unittests to perform packet consistency
checks between seeks.
- Extends the new consolidated tests for WAV, FLAC, MP3, and AAC.
- Adds decoded output consistency checks using MD5 for all files.
- Removes old tests which end up duplicating efforts.
- Expands tests for bad decoder configs and buffers w/o timestamps.
- Expands tests to include AudioDiscardHelper usage.

BUG=381356
TEST=shiny new tests!

Review URL: https://codereview.chromium.org/311373004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278667 0039d316-1c4b-4281-b951-d872f2087c98
parent 7896ddcc
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <deque>
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/md5.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/sys_byteorder.h"
#include "build/build_config.h"
#include "media/base/audio_buffer.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_hash.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/audio_file_reader.h"
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/in_memory_url_protocol.h"
#include "media/filters/opus_audio_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
// The number of packets to read and then decode from each file.
static const size_t kDecodeRuns = 3;
static const uint8_t kOpusExtraData[] = {
0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02,
// The next two bytes represent the codec delay.
0x00, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00};
enum AudioDecoderType {
FFMPEG,
OPUS,
};
struct DecodedBufferExpectations {
const int64 timestamp;
const int64 duration;
const char* hash;
};
struct DecoderTestData {
const AudioDecoderType decoder_type;
const AudioCodec codec;
const char* filename;
const DecodedBufferExpectations* expectations;
const int first_packet_pts;
const int samples_per_second;
const ChannelLayout channel_layout;
};
// Tells gtest how to print our DecoderTestData structure.
std::ostream& operator<<(std::ostream& os, const DecoderTestData& data) {
return os << data.filename;
}
// Marks negative timestamp buffers for discard or transfers FFmpeg's built in
// discard metadata in favor of setting DiscardPadding on the DecoderBuffer.
// Allows better testing of AudioDiscardHelper usage.
static void SetDiscardPadding(AVPacket* packet,
const scoped_refptr<DecoderBuffer> buffer,
double samples_per_second) {
// Discard negative timestamps.
if (buffer->timestamp() + buffer->duration() < base::TimeDelta()) {
buffer->set_discard_padding(
std::make_pair(kInfiniteDuration(), base::TimeDelta()));
return;
}
if (buffer->timestamp() < base::TimeDelta()) {
buffer->set_discard_padding(
std::make_pair(-buffer->timestamp(), base::TimeDelta()));
return;
}
// If the timestamp is positive, try to use FFmpeg's discard data.
int skip_samples_size = 0;
const uint32* skip_samples_ptr =
reinterpret_cast<const uint32*>(av_packet_get_side_data(
packet, AV_PKT_DATA_SKIP_SAMPLES, &skip_samples_size));
if (skip_samples_size < 4)
return;
buffer->set_discard_padding(std::make_pair(
base::TimeDelta::FromSecondsD(base::ByteSwapToLE32(*skip_samples_ptr) /
samples_per_second),
base::TimeDelta()));
}
class AudioDecoderTest : public testing::TestWithParam<DecoderTestData> {
public:
AudioDecoderTest()
: pending_decode_(false),
pending_reset_(false),
last_decode_status_(AudioDecoder::kDecodeError) {
switch (GetParam().decoder_type) {
case FFMPEG:
decoder_.reset(new FFmpegAudioDecoder(
message_loop_.message_loop_proxy(), LogCB()));
break;
case OPUS:
decoder_.reset(
new OpusAudioDecoder(message_loop_.message_loop_proxy()));
break;
}
}
virtual ~AudioDecoderTest() {
// Always issue a Stop() even if it's already been sent to avoid assertion
// failures causing crashes.
Stop();
EXPECT_FALSE(pending_decode_);
EXPECT_FALSE(pending_reset_);
}
protected:
void DecodeBuffer(const scoped_refptr<DecoderBuffer>& buffer) {
ASSERT_FALSE(pending_decode_);
pending_decode_ = true;
last_decode_status_ = AudioDecoder::kDecodeError;
decoder_->Decode(
buffer,
base::Bind(&AudioDecoderTest::DecodeFinished, base::Unretained(this)));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pending_decode_);
}
void SendEndOfStream() {
DecodeBuffer(DecoderBuffer::CreateEOSBuffer());
}
void Initialize() {
// Load the test data file.
data_ = ReadTestDataFile(GetParam().filename);
protocol_.reset(
new InMemoryUrlProtocol(data_->data(), data_->data_size(), false));
reader_.reset(new AudioFileReader(protocol_.get()));
ASSERT_TRUE(reader_->OpenDemuxerForTesting());
// Load the first packet and check its timestamp.
AVPacket packet;
ASSERT_TRUE(reader_->ReadPacketForTesting(&packet));
EXPECT_EQ(GetParam().first_packet_pts, packet.pts);
start_timestamp_ = ConvertFromTimeBase(
reader_->GetAVStreamForTesting()->time_base, packet.pts);
av_free_packet(&packet);
// Seek back to the beginning.
ASSERT_TRUE(reader_->SeekForTesting(start_timestamp_));
AudioDecoderConfig config;
AVCodecContextToAudioDecoderConfig(
reader_->codec_context_for_testing(), false, &config, false);
EXPECT_EQ(GetParam().codec, config.codec());
EXPECT_EQ(GetParam().samples_per_second, config.samples_per_second());
EXPECT_EQ(GetParam().channel_layout, config.channel_layout());
InitializeDecoder(config);
}
void InitializeDecoder(const AudioDecoderConfig& config) {
InitializeDecoderWithStatus(config, PIPELINE_OK);
}
void InitializeDecoderWithStatus(const AudioDecoderConfig& config,
PipelineStatus status) {
decoder_->Initialize(
config,
NewExpectedStatusCB(status),
base::Bind(&AudioDecoderTest::OnDecoderOutput, base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Decode() {
AVPacket packet;
ASSERT_TRUE(reader_->ReadPacketForTesting(&packet));
// Split out packet metadata before making a copy.
av_packet_split_side_data(&packet);
scoped_refptr<DecoderBuffer> buffer =
DecoderBuffer::CopyFrom(packet.data, packet.size);
buffer->set_timestamp(ConvertFromTimeBase(
reader_->GetAVStreamForTesting()->time_base, packet.pts));
buffer->set_duration(ConvertFromTimeBase(
reader_->GetAVStreamForTesting()->time_base, packet.duration));
// Don't set discard padding for Opus, it already has discard behavior set
// based on the codec delay in the AudioDecoderConfig.
if (GetParam().decoder_type == FFMPEG)
SetDiscardPadding(&packet, buffer, GetParam().samples_per_second);
// DecodeBuffer() shouldn't need the original packet since it uses the copy.
av_free_packet(&packet);
DecodeBuffer(buffer);
}
void Reset() {
ASSERT_FALSE(pending_reset_);
pending_reset_ = true;
decoder_->Reset(
base::Bind(&AudioDecoderTest::ResetFinished, base::Unretained(this)));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(pending_reset_);
}
void Stop() {
decoder_->Stop();
}
void Seek(base::TimeDelta seek_time) {
Reset();
decoded_audio_.clear();
ASSERT_TRUE(reader_->SeekForTesting(seek_time));
}
void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) {
EXPECT_FALSE(buffer->end_of_stream());
decoded_audio_.push_back(buffer);
}
void DecodeFinished(AudioDecoder::Status status) {
EXPECT_TRUE(pending_decode_);
EXPECT_FALSE(pending_reset_);
pending_decode_ = false;
last_decode_status_ = status;
}
void ResetFinished() {
EXPECT_TRUE(pending_reset_);
EXPECT_FALSE(pending_decode_);
pending_reset_ = false;
}
// Generates an MD5 hash of the audio signal. Should not be used for checks
// across platforms as audio varies slightly across platforms.
std::string GetDecodedAudioMD5(size_t i) {
CHECK_LT(i, decoded_audio_.size());
const scoped_refptr<AudioBuffer>& buffer = decoded_audio_[i];
scoped_ptr<AudioBus> output =
AudioBus::Create(buffer->channel_count(), buffer->frame_count());
buffer->ReadFrames(buffer->frame_count(), 0, 0, output.get());
base::MD5Context context;
base::MD5Init(&context);
for (int ch = 0; ch < output->channels(); ++ch) {
base::MD5Update(
&context,
base::StringPiece(reinterpret_cast<char*>(output->channel(ch)),
output->frames() * sizeof(*output->channel(ch))));
}
base::MD5Digest digest;
base::MD5Final(&digest, &context);
return base::MD5DigestToBase16(digest);
}
void ExpectDecodedAudio(size_t i, const std::string& exact_hash) {
CHECK_LT(i, decoded_audio_.size());
const scoped_refptr<AudioBuffer>& buffer = decoded_audio_[i];
const DecodedBufferExpectations& sample_info = GetParam().expectations[i];
EXPECT_EQ(sample_info.timestamp, buffer->timestamp().InMicroseconds());
EXPECT_EQ(sample_info.duration, buffer->duration().InMicroseconds());
EXPECT_FALSE(buffer->end_of_stream());
scoped_ptr<AudioBus> output =
AudioBus::Create(buffer->channel_count(), buffer->frame_count());
buffer->ReadFrames(buffer->frame_count(), 0, 0, output.get());
// Generate a lossy hash of the audio used for comparison across platforms.
AudioHash audio_hash;
audio_hash.Update(output.get(), output->frames());
EXPECT_EQ(sample_info.hash, audio_hash.ToString());
if (!exact_hash.empty()) {
EXPECT_EQ(exact_hash, GetDecodedAudioMD5(i));
// Verify different hashes are being generated. None of our test data
// files have audio that hashes out exactly the same.
if (i > 0)
EXPECT_NE(exact_hash, GetDecodedAudioMD5(i - 1));
}
}
size_t decoded_audio_size() const { return decoded_audio_.size(); }
base::TimeDelta start_timestamp() const { return start_timestamp_; }
const scoped_refptr<AudioBuffer>& decoded_audio(size_t i) {
return decoded_audio_[i];
}
AudioDecoder::Status last_decode_status() const {
return last_decode_status_;
}
private:
base::MessageLoop message_loop_;
scoped_refptr<DecoderBuffer> data_;
scoped_ptr<InMemoryUrlProtocol> protocol_;
scoped_ptr<AudioFileReader> reader_;
scoped_ptr<AudioDecoder> decoder_;
bool pending_decode_;
bool pending_reset_;
AudioDecoder::Status last_decode_status_;
std::deque<scoped_refptr<AudioBuffer> > decoded_audio_;
base::TimeDelta start_timestamp_;
DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest);
};
class OpusAudioDecoderBehavioralTest : public AudioDecoderTest {};
class FFmpegAudioDecoderBehavioralTest : public AudioDecoderTest {};
TEST_P(AudioDecoderTest, Initialize) {
ASSERT_NO_FATAL_FAILURE(Initialize());
Stop();
}
// Verifies decode audio as well as the Decode() -> Reset() -> Stop() sequence.
TEST_P(AudioDecoderTest, ProduceAudioSamples) {
ASSERT_NO_FATAL_FAILURE(Initialize());
// Run the test multiple times with a seek back to the beginning in between.
std::vector<std::string> decoded_audio_md5_hashes;
for (int i = 0; i < 2; ++i) {
for (size_t j = 0; j < kDecodeRuns; ++j) {
do {
Decode();
ASSERT_EQ(last_decode_status(), AudioDecoder::kOk);
// Some codecs have a multiple buffer delay and require an extra
// Decode() step to extract the desired number of output buffers.
} while (j == 0 && decoded_audio_size() == 0);
// On the first pass record the exact MD5 hash for each decoded buffer.
if (i == 0)
decoded_audio_md5_hashes.push_back(GetDecodedAudioMD5(j));
}
ASSERT_EQ(kDecodeRuns, decoded_audio_size());
// On the first pass verify the basic audio hash and sample info. On the
// second, verify the exact MD5 sum for each packet. It shouldn't change.
for (size_t j = 0; j < kDecodeRuns; ++j) {
SCOPED_TRACE(base::StringPrintf("i = %d, j = %" PRIuS, i, j));
ExpectDecodedAudio(j, i == 0 ? "" : decoded_audio_md5_hashes[j]);
}
SendEndOfStream();
ASSERT_EQ(kDecodeRuns, decoded_audio_size());
// Seek back to the beginning. Calls Reset() on the decoder.
Seek(start_timestamp());
}
Stop();
}
TEST_P(AudioDecoderTest, DecodeStop) {
ASSERT_NO_FATAL_FAILURE(Initialize());
Decode();
EXPECT_EQ(AudioDecoder::kOk, last_decode_status());
Stop();
}
TEST_P(AudioDecoderTest, ResetStop) {
ASSERT_NO_FATAL_FAILURE(Initialize());
Reset();
Stop();
}
TEST_P(AudioDecoderTest, NoTimestamp) {
ASSERT_NO_FATAL_FAILURE(Initialize());
scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(0));
buffer->set_timestamp(kNoTimestamp());
DecodeBuffer(buffer);
EXPECT_EQ(AudioDecoder::kDecodeError, last_decode_status());
Stop();
}
TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) {
ASSERT_EQ(GetParam().decoder_type, OPUS);
AudioDecoderConfig decoder_config;
decoder_config.Initialize(kCodecOpus,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
48000,
kOpusExtraData,
ARRAYSIZE_UNSAFE(kOpusExtraData),
false,
false,
base::TimeDelta::FromMilliseconds(80),
0);
InitializeDecoder(decoder_config);
Stop();
}
TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithBadCodecDelay) {
ASSERT_EQ(GetParam().decoder_type, OPUS);
AudioDecoderConfig decoder_config;
decoder_config.Initialize(
kCodecOpus,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
48000,
kOpusExtraData,
ARRAYSIZE_UNSAFE(kOpusExtraData),
false,
false,
base::TimeDelta::FromMilliseconds(80),
// Use a different codec delay than in the extradata.
100);
InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED);
Stop();
}
TEST_P(FFmpegAudioDecoderBehavioralTest, InitializeWithBadConfig) {
const AudioDecoderConfig decoder_config(kCodecVorbis,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
// Invalid sample rate of zero.
0,
NULL,
0,
false);
InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED);
Stop();
}
const DecodedBufferExpectations kSfxOpusExpectations[] = {
{0, 13500, "-2.70,-1.41,-0.78,-1.27,-2.56,-3.73,"},
{13500, 20000, "5.48,5.93,6.04,5.83,5.54,5.45,"},
{33500, 20000, "-3.45,-3.35,-3.57,-4.12,-4.74,-5.14,"},
};
const DecodedBufferExpectations kBearOpusExpectations[] = {
{500, 3500, "-0.26,0.87,1.36,0.84,-0.30,-1.22,"},
{4000, 10000, "0.09,0.23,0.21,0.03,-0.17,-0.24,"},
{14000, 10000, "0.10,0.24,0.23,0.04,-0.14,-0.23,"},
};
const DecoderTestData kOpusTests[] = {
{OPUS, kCodecOpus, "sfx-opus.ogg", kSfxOpusExpectations, -312, 48000,
CHANNEL_LAYOUT_MONO},
{OPUS, kCodecOpus, "bear-opus.ogg", kBearOpusExpectations, 24, 48000,
CHANNEL_LAYOUT_STEREO},
};
// Dummy data for behavioral tests.
const DecoderTestData kOpusBehavioralTest[] = {
{OPUS, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE},
};
INSTANTIATE_TEST_CASE_P(OpusAudioDecoderTest,
AudioDecoderTest,
testing::ValuesIn(kOpusTests));
INSTANTIATE_TEST_CASE_P(OpusAudioDecoderBehavioralTest,
OpusAudioDecoderBehavioralTest,
testing::ValuesIn(kOpusBehavioralTest));
#if defined(USE_PROPRIETARY_CODECS)
const DecodedBufferExpectations kSfxMp3Expectations[] = {
{0, 1065, "2.81,3.99,4.53,4.10,3.08,2.46,"},
{1065, 26122, "-3.81,-4.14,-3.90,-3.36,-3.03,-3.23,"},
{27188, 26122, "4.24,3.95,4.22,4.78,5.13,4.93,"},
};
const DecodedBufferExpectations kSfxAdtsExpectations[] = {
{0, 23219, "-1.90,-1.53,-0.15,1.28,1.23,-0.33,"},
{23219, 23219, "0.54,0.88,2.19,3.54,3.24,1.63,"},
{46439, 23219, "1.42,1.69,2.95,4.23,4.02,2.36,"},
};
#endif
#if defined(OS_CHROMEOS)
const DecodedBufferExpectations kSfxFlacExpectations[] = {
{0, 104489, "-2.42,-1.12,0.71,1.70,1.09,-0.68,"},
{104489, 104489, "-1.99,-0.67,1.18,2.19,1.60,-0.16,"},
{208979, 79433, "2.84,2.70,3.23,4.06,4.59,4.44,"},
};
#endif
const DecodedBufferExpectations kSfxWaveExpectations[] = {
{0, 23219, "-1.23,-0.87,0.47,1.85,1.88,0.29,"},
{23219, 23219, "0.75,1.10,2.43,3.78,3.53,1.93,"},
{46439, 23219, "1.27,1.56,2.83,4.13,3.87,2.23,"},
};
const DecodedBufferExpectations kFourChannelWaveExpectations[] = {
{0, 11609, "-1.68,1.68,0.89,-3.45,1.52,1.15,"},
{11609, 11609, "43.26,9.06,18.27,35.98,19.45,7.46,"},
{23219, 11609, "36.37,9.45,16.04,27.67,18.81,10.15,"},
};
const DecodedBufferExpectations kSfxOggExpectations[] = {
{0, 13061, "-0.33,1.25,2.86,3.26,2.09,0.14,"},
{13061, 23219, "-2.79,-2.42,-1.06,0.33,0.93,-0.64,"},
{36281, 23219, "-1.19,-0.80,0.57,1.97,2.08,0.51,"},
};
const DecodedBufferExpectations kBearOgvExpectations[] = {
{0, 13061, "-1.25,0.10,2.11,2.29,1.50,-0.68,"},
{13061, 23219, "-1.80,-1.41,-0.13,1.30,1.65,0.01,"},
{36281, 23219, "-1.43,-1.25,0.11,1.29,1.86,0.14,"},
};
const DecoderTestData kFFmpegTests[] = {
#if defined(USE_PROPRIETARY_CODECS)
{FFMPEG, kCodecMP3, "sfx.mp3", kSfxMp3Expectations, 0, 44100,
CHANNEL_LAYOUT_MONO},
{FFMPEG, kCodecAAC, "sfx.adts", kSfxAdtsExpectations, 0, 44100,
CHANNEL_LAYOUT_MONO},
#endif
#if defined(OS_CHROMEOS)
{FFMPEG, kCodecFLAC, "sfx.flac", kSfxFlacExpectations, 0, 44100,
CHANNEL_LAYOUT_MONO},
#endif
{FFMPEG, kCodecPCM, "sfx_f32le.wav", kSfxWaveExpectations, 0, 44100,
CHANNEL_LAYOUT_MONO},
{FFMPEG, kCodecPCM, "4ch.wav", kFourChannelWaveExpectations, 0, 44100,
CHANNEL_LAYOUT_QUAD},
{FFMPEG, kCodecVorbis, "sfx.ogg", kSfxOggExpectations, 0, 44100,
CHANNEL_LAYOUT_MONO},
// Note: bear.ogv is incorrectly muxed such that valid samples are given
// negative timestamps, this marks them for discard per the ogg vorbis spec.
{FFMPEG, kCodecVorbis, "bear.ogv", kBearOgvExpectations, -704, 44100,
CHANNEL_LAYOUT_STEREO},
};
// Dummy data for behavioral tests.
const DecoderTestData kFFmpegBehavioralTest[] = {
{FFMPEG, kUnknownAudioCodec, "", NULL, 0, 0, CHANNEL_LAYOUT_NONE},
};
INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderTest,
AudioDecoderTest,
testing::ValuesIn(kFFmpegTests));
INSTANTIATE_TEST_CASE_P(FFmpegAudioDecoderBehavioralTest,
FFmpegAudioDecoderBehavioralTest,
testing::ValuesIn(kFFmpegBehavioralTest));
} // namespace media
......@@ -28,6 +28,12 @@ AudioFileReader::~AudioFileReader() {
}
bool AudioFileReader::Open() {
if (!OpenDemuxer())
return false;
return OpenDecoder();
}
bool AudioFileReader::OpenDemuxer() {
glue_.reset(new FFmpegGlue(protocol_));
AVFormatContext* format_context = glue_->format_context();
......@@ -52,20 +58,21 @@ bool AudioFileReader::Open() {
if (!codec_context_)
return false;
int result = avformat_find_stream_info(format_context, NULL);
if (result < 0) {
DLOG(WARNING)
<< "AudioFileReader::Open() : error in avformat_find_stream_info()";
return false;
}
const int result = avformat_find_stream_info(format_context, NULL);
DLOG_IF(WARNING, result < 0)
<< "AudioFileReader::Open() : error in avformat_find_stream_info()";
return result >= 0;
}
bool AudioFileReader::OpenDecoder() {
AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
if (codec) {
// MP3 decodes to S16P which we don't support, tell it to use S16 instead.
if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P)
codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
if ((result = avcodec_open2(codec_context_, codec, NULL)) < 0) {
const int result = avcodec_open2(codec_context_, codec, NULL);
if (result < 0) {
DLOG(WARNING) << "AudioFileReader::Open() : could not open codec -"
<< " result: " << result;
return false;
......@@ -79,8 +86,7 @@ bool AudioFileReader::Open() {
return false;
}
} else {
DLOG(WARNING) << "AudioFileReader::Open() : could not find codec -"
<< " result: " << result;
DLOG(WARNING) << "AudioFileReader::Open() : could not find codec.";
return false;
}
......@@ -96,7 +102,6 @@ bool AudioFileReader::Open() {
channels_ = codec_context_->channels;
sample_rate_ = codec_context_->sample_rate;
av_sample_format_ = codec_context_->sample_fmt;
return true;
}
......@@ -240,6 +245,10 @@ int AudioFileReader::GetNumberOfFrames() const {
return static_cast<int>(ceil(GetDuration().InSecondsF() * sample_rate()));
}
bool AudioFileReader::OpenDemuxerForTesting() {
return OpenDemuxer();
}
bool AudioFileReader::ReadPacketForTesting(AVPacket* output_packet) {
return ReadPacket(output_packet);
}
......@@ -257,4 +266,15 @@ bool AudioFileReader::ReadPacket(AVPacket* output_packet) {
return false;
}
bool AudioFileReader::SeekForTesting(base::TimeDelta seek_time) {
return av_seek_frame(glue_->format_context(),
stream_index_,
ConvertToTimeBase(codec_context_->time_base, seek_time),
AVSEEK_FLAG_BACKWARD) >= 0;
}
const AVStream* AudioFileReader::GetAVStreamForTesting() const {
return glue_->format_context()->streams[stream_index_];
}
} // namespace media
......@@ -8,16 +8,17 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
#include "media/filters/ffmpeg_glue.h"
struct AVCodecContext;
struct AVPacket;
struct AVStream;
namespace base { class TimeDelta; }
namespace media {
class AudioBus;
class FFmpegGlue;
class FFmpegURLProtocol;
class MEDIA_EXPORT AudioFileReader {
......@@ -55,17 +56,29 @@ class MEDIA_EXPORT AudioFileReader {
base::TimeDelta GetDuration() const;
int GetNumberOfFrames() const;
// Helper methods which allows AudioFileReader to double as a test utility for
// demuxing audio files. Returns true if a packet could be demuxed from the
// first audio stream in the file, |output_packet| will contain the demuxed
// packet then.
// The methods below are helper methods which allow AudioFileReader to double
// as a test utility for demuxing audio files.
// --------------------------------------------------------------------------
// Similar to Open() but does not initialize the decoder.
bool OpenDemuxerForTesting();
// Returns true if a packet could be demuxed from the first audio stream in
// the file, |output_packet| will contain the demuxed packet then.
bool ReadPacketForTesting(AVPacket* output_packet);
// Seeks to the given point and returns true if successful. |seek_time| will
// be converted to the stream's time base automatically.
bool SeekForTesting(base::TimeDelta seek_time);
const AVStream* GetAVStreamForTesting() const;
const AVCodecContext* codec_context_for_testing() const {
return codec_context_;
}
private:
bool OpenDemuxer();
bool OpenDecoder();
bool ReadPacket(AVPacket* output_packet);
scoped_ptr<FFmpegGlue> glue_;
......
......@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "base/logging.h"
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_hash.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/audio_file_reader.h"
#include "media/filters/in_memory_url_protocol.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -17,20 +19,20 @@ namespace media {
class AudioFileReaderTest : public testing::Test {
public:
AudioFileReaderTest() {}
AudioFileReaderTest() : packet_verification_disabled_(false) {}
virtual ~AudioFileReaderTest() {}
void Initialize(const char* filename) {
data_ = ReadTestDataFile(filename);
protocol_.reset(new InMemoryUrlProtocol(
data_->data(), data_->data_size(), false));
protocol_.reset(
new InMemoryUrlProtocol(data_->data(), data_->data_size(), false));
reader_.reset(new AudioFileReader(protocol_.get()));
}
// Reads and the entire file provided to Initialize().
void ReadAndVerify(const char* expected_audio_hash, int expected_frames) {
scoped_ptr<AudioBus> decoded_audio_data = AudioBus::Create(
reader_->channels(), reader_->GetNumberOfFrames());
scoped_ptr<AudioBus> decoded_audio_data =
AudioBus::Create(reader_->channels(), reader_->GetNumberOfFrames());
int actual_frames = reader_->Read(decoded_audio_data.get());
ASSERT_LE(actual_frames, decoded_audio_data->frames());
ASSERT_EQ(expected_frames, actual_frames);
......@@ -40,8 +42,50 @@ class AudioFileReaderTest : public testing::Test {
EXPECT_EQ(expected_audio_hash, audio_hash.ToString());
}
void RunTest(const char* fn, const char* hash, int channels, int sample_rate,
base::TimeDelta duration, int frames, int trimmed_frames) {
// Verify packets are consistent across demuxer runs. Reads the first few
// packets and then seeks back to the start timestamp and verifies that the
// hashes match on the packets just read.
void VerifyPackets() {
const int kReads = 3;
const int kTestPasses = 2;
AVPacket packet;
base::TimeDelta start_timestamp;
std::vector<std::string> packet_md5_hashes_;
for (int i = 0; i < kTestPasses; ++i) {
for (int j = 0; j < kReads; ++j) {
ASSERT_TRUE(reader_->ReadPacketForTesting(&packet));
// Remove metadata from the packet data section before hashing.
av_packet_split_side_data(&packet);
// On the first pass save the MD5 hash of each packet, on subsequent
// passes ensure it matches.
const std::string md5_hash = base::MD5String(base::StringPiece(
reinterpret_cast<char*>(packet.data), packet.size));
if (i == 0) {
packet_md5_hashes_.push_back(md5_hash);
if (j == 0) {
start_timestamp = ConvertFromTimeBase(
reader_->codec_context_for_testing()->time_base, packet.pts);
}
} else {
EXPECT_EQ(packet_md5_hashes_[j], md5_hash) << "j = " << j;
}
av_free_packet(&packet);
}
ASSERT_TRUE(reader_->SeekForTesting(start_timestamp));
}
}
void RunTest(const char* fn,
const char* hash,
int channels,
int sample_rate,
base::TimeDelta duration,
int frames,
int trimmed_frames) {
Initialize(fn);
ASSERT_TRUE(reader_->Open());
EXPECT_EQ(channels, reader_->channels());
......@@ -49,6 +93,8 @@ class AudioFileReaderTest : public testing::Test {
EXPECT_EQ(duration.InMicroseconds(),
reader_->GetDuration().InMicroseconds());
EXPECT_EQ(frames, reader_->GetNumberOfFrames());
if (!packet_verification_disabled_)
ASSERT_NO_FATAL_FAILURE(VerifyPackets());
ReadAndVerify(hash, trimmed_frames);
}
......@@ -60,15 +106,20 @@ class AudioFileReaderTest : public testing::Test {
void RunTestFailingDecode(const char* fn) {
Initialize(fn);
EXPECT_TRUE(reader_->Open());
scoped_ptr<AudioBus> decoded_audio_data = AudioBus::Create(
reader_->channels(), reader_->GetNumberOfFrames());
scoped_ptr<AudioBus> decoded_audio_data =
AudioBus::Create(reader_->channels(), reader_->GetNumberOfFrames());
EXPECT_EQ(reader_->Read(decoded_audio_data.get()), 0);
}
void disable_packet_verification() {
packet_verification_disabled_ = true;
}
protected:
scoped_refptr<DecoderBuffer> data_;
scoped_ptr<InMemoryUrlProtocol> protocol_;
scoped_ptr<AudioFileReader> reader_;
bool packet_verification_disabled_;
DISALLOW_COPY_AND_ASSIGN(AudioFileReaderTest);
};
......@@ -82,49 +133,97 @@ TEST_F(AudioFileReaderTest, InvalidFile) {
}
TEST_F(AudioFileReaderTest, WithVideo) {
RunTest("bear.ogv", "-2.49,-0.75,0.38,1.60,0.70,-1.22,", 2, 44100,
base::TimeDelta::FromMicroseconds(1011520), 44609, 44609);
RunTest("bear.ogv",
"-2.49,-0.75,0.38,1.60,0.70,-1.22,",
2,
44100,
base::TimeDelta::FromMicroseconds(1011520),
44609,
44609);
}
TEST_F(AudioFileReaderTest, Vorbis) {
RunTest("sfx.ogg", "4.36,4.81,4.84,4.45,4.61,4.63,", 1, 44100,
base::TimeDelta::FromMicroseconds(350001), 15436, 15436);
RunTest("sfx.ogg",
"4.36,4.81,4.84,4.45,4.61,4.63,",
1,
44100,
base::TimeDelta::FromMicroseconds(350001),
15436,
15436);
}
TEST_F(AudioFileReaderTest, WaveU8) {
RunTest("sfx_u8.wav", "-1.23,-1.57,-1.14,-0.91,-0.87,-0.07,", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12720, 12719);
RunTest("sfx_u8.wav",
"-1.23,-1.57,-1.14,-0.91,-0.87,-0.07,",
1,
44100,
base::TimeDelta::FromMicroseconds(288414),
12720,
12719);
}
TEST_F(AudioFileReaderTest, WaveS16LE) {
RunTest("sfx_s16le.wav", "3.05,2.87,3.00,3.32,3.58,4.08,", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12720, 12719);
RunTest("sfx_s16le.wav",
"3.05,2.87,3.00,3.32,3.58,4.08,",
1,
44100,
base::TimeDelta::FromMicroseconds(288414),
12720,
12719);
}
TEST_F(AudioFileReaderTest, WaveS24LE) {
RunTest("sfx_s24le.wav", "3.03,2.86,2.99,3.31,3.57,4.06,", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12720, 12719);
RunTest("sfx_s24le.wav",
"3.03,2.86,2.99,3.31,3.57,4.06,",
1,
44100,
base::TimeDelta::FromMicroseconds(288414),
12720,
12719);
}
TEST_F(AudioFileReaderTest, WaveF32LE) {
RunTest("sfx_f32le.wav", "3.03,2.86,2.99,3.31,3.57,4.06,", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12720, 12719);
RunTest("sfx_f32le.wav",
"3.03,2.86,2.99,3.31,3.57,4.06,",
1,
44100,
base::TimeDelta::FromMicroseconds(288414),
12720,
12719);
}
#if defined(USE_PROPRIETARY_CODECS)
TEST_F(AudioFileReaderTest, MP3) {
RunTest("sfx.mp3", "3.05,2.87,3.00,3.32,3.58,4.08,", 1, 44100,
base::TimeDelta::FromMicroseconds(313470), 13825, 12719);
RunTest("sfx.mp3",
"3.05,2.87,3.00,3.32,3.58,4.08,",
1,
44100,
base::TimeDelta::FromMicroseconds(313470),
13825,
12719);
}
TEST_F(AudioFileReaderTest, CorruptMP3) {
RunTest("corrupt.mp3", "-4.95,-2.95,-0.44,1.16,0.31,-2.21,", 1, 44100,
base::TimeDelta::FromMicroseconds(1018826), 44931, 44928);
// Disable packet verification since the file is corrupt and FFmpeg does not
// make any guarantees on packet consistency in this case.
disable_packet_verification();
RunTest("corrupt.mp3",
"-4.95,-2.95,-0.44,1.16,0.31,-2.21,",
1,
44100,
base::TimeDelta::FromMicroseconds(1018826),
44931,
44928);
}
TEST_F(AudioFileReaderTest, AAC) {
RunTest("sfx.m4a", "1.81,1.66,2.32,3.27,4.46,3.36,", 1, 44100,
base::TimeDelta::FromMicroseconds(312001), 13760, 13312);
RunTest("sfx.m4a",
"1.81,1.66,2.32,3.27,4.46,3.36,",
1,
44100,
base::TimeDelta::FromMicroseconds(312001),
13760,
13312);
}
TEST_F(AudioFileReaderTest, MidStreamConfigChangesFail) {
......@@ -137,8 +236,13 @@ TEST_F(AudioFileReaderTest, VorbisInvalidChannelLayout) {
}
TEST_F(AudioFileReaderTest, WaveValidFourChannelLayout) {
RunTest("4ch.wav", "131.71,38.02,130.31,44.89,135.98,42.52,", 4, 44100,
base::TimeDelta::FromMicroseconds(100001), 4411, 4410);
RunTest("4ch.wav",
"131.71,38.02,130.31,44.89,135.98,42.52,",
4,
44100,
base::TimeDelta::FromMicroseconds(100001),
4411,
4410);
}
} // namespace media
......@@ -210,7 +210,6 @@ void FFmpegAudioDecoder::DecodeBuffer(
DCHECK_NE(state_, kUninitialized);
DCHECK_NE(state_, kDecodeFinished);
DCHECK_NE(state_, kError);
DCHECK(buffer);
// Make sure we are notified if http://crbug.com/49709 returns. Issue also
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <deque>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "media/base/audio_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/mock_filters.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_audio_decoder.h"
#include "media/filters/ffmpeg_glue.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::StrictMock;
namespace media {
class FFmpegAudioDecoderTest : public testing::Test {
public:
FFmpegAudioDecoderTest()
: decoder_(new FFmpegAudioDecoder(message_loop_.message_loop_proxy(),
LogCB())),
pending_decode_(false),
pending_reset_(false),
last_decode_status_(AudioDecoder::kOk) {
FFmpegGlue::InitializeFFmpeg();
vorbis_extradata_ = ReadTestDataFile("vorbis-extradata");
// Refer to media/test/data/README for details on vorbis test data.
for (int i = 0; i < 4; ++i) {
scoped_refptr<DecoderBuffer> buffer =
ReadTestDataFile(base::StringPrintf("vorbis-packet-%d", i));
if (i < 3) {
buffer->set_timestamp(base::TimeDelta());
} else {
buffer->set_timestamp(base::TimeDelta::FromMicroseconds(2902));
}
buffer->set_duration(base::TimeDelta());
encoded_audio_.push_back(buffer);
}
// Push in an EOS buffer.
encoded_audio_.push_back(DecoderBuffer::CreateEOSBuffer());
Initialize();
}
virtual ~FFmpegAudioDecoderTest() {
EXPECT_FALSE(pending_decode_);
EXPECT_FALSE(pending_reset_);
}
void Initialize() {
AudioDecoderConfig config(kCodecVorbis,
kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO,
44100,
vorbis_extradata_->data(),
vorbis_extradata_->data_size(),
false); // Not encrypted.
decoder_->Initialize(config,
NewExpectedStatusCB(PIPELINE_OK),
base::Bind(&FFmpegAudioDecoderTest::OnDecoderOutput,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void SatisfyPendingDecode() {
base::RunLoop().RunUntilIdle();
}
void Decode() {
pending_decode_ = true;
scoped_refptr<DecoderBuffer> buffer(encoded_audio_.front());
encoded_audio_.pop_front();
decoder_->Decode(buffer,
base::Bind(&FFmpegAudioDecoderTest::DecodeFinished,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(pending_decode_);
EXPECT_EQ(AudioDecoder::kOk, last_decode_status_);
}
void Reset() {
pending_reset_ = true;
decoder_->Reset(base::Bind(
&FFmpegAudioDecoderTest::ResetFinished, base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Stop() {
decoder_->Stop();
base::RunLoop().RunUntilIdle();
}
void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) {
EXPECT_FALSE(buffer->end_of_stream());
decoded_audio_.push_back(buffer);
}
void DecodeFinished(AudioDecoder::Status status) {
EXPECT_TRUE(pending_decode_);
pending_decode_ = false;
last_decode_status_ = status;
}
void ResetFinished() {
EXPECT_TRUE(pending_reset_);
// Reset should always finish after Decode.
EXPECT_FALSE(pending_decode_);
pending_reset_ = false;
}
void ExpectDecodedAudio(size_t i, int64 timestamp, int64 duration) {
EXPECT_LT(i, decoded_audio_.size());
EXPECT_EQ(timestamp, decoded_audio_[i]->timestamp().InMicroseconds());
EXPECT_EQ(duration, decoded_audio_[i]->duration().InMicroseconds());
}
base::MessageLoop message_loop_;
scoped_ptr<FFmpegAudioDecoder> decoder_;
bool pending_decode_;
bool pending_reset_;
scoped_refptr<DecoderBuffer> vorbis_extradata_;
std::deque<scoped_refptr<DecoderBuffer> > encoded_audio_;
std::deque<scoped_refptr<AudioBuffer> > decoded_audio_;
AudioDecoder::Status last_decode_status_;
};
TEST_F(FFmpegAudioDecoderTest, Initialize) {
AudioDecoderConfig config(kCodecVorbis,
kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO,
44100,
vorbis_extradata_->data(),
vorbis_extradata_->data_size(),
false); // Not encrypted.
Stop();
}
TEST_F(FFmpegAudioDecoderTest, ProduceAudioSamples) {
// Vorbis requires N+1 packets to produce audio data for N packets.
//
// This will should result in the demuxer receiving three reads for two
// requests to produce audio samples.
Decode();
Decode();
Decode();
Decode();
ASSERT_EQ(3u, decoded_audio_.size());
ExpectDecodedAudio(0, 0, 2902);
ExpectDecodedAudio(1, 2902, 13061);
ExpectDecodedAudio(2, 15963, 23219);
// Call one more time with EOS.
Decode();
ASSERT_EQ(3u, decoded_audio_.size());
Stop();
}
TEST_F(FFmpegAudioDecoderTest, PendingDecode_Stop) {
Decode();
Stop();
SatisfyPendingDecode();
}
TEST_F(FFmpegAudioDecoderTest, PendingDecode_Reset) {
Decode();
Reset();
SatisfyPendingDecode();
Stop();
}
TEST_F(FFmpegAudioDecoderTest, PendingDecode_ResetStop) {
Decode();
Reset();
Stop();
SatisfyPendingDecode();
}
} // namespace media
......@@ -292,15 +292,16 @@ void OpusAudioDecoder::Stop() {
CloseDecoder();
}
OpusAudioDecoder::~OpusAudioDecoder() {}
OpusAudioDecoder::~OpusAudioDecoder() {
DCHECK(!opus_decoder_);
}
void OpusAudioDecoder::DecodeBuffer(
const scoped_refptr<DecoderBuffer>& input,
const DecodeCB& decode_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!decode_cb.is_null());
DCHECK(input.get());
DCHECK(input);
// Libopus does not buffer output. Decoding is complete when an end of stream
// input buffer is received.
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <deque>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "media/base/audio_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/audio_file_reader.h"
#include "media/filters/in_memory_url_protocol.h"
#include "media/filters/opus_audio_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class OpusAudioDecoderTest : public testing::Test {
public:
OpusAudioDecoderTest()
: decoder_(new OpusAudioDecoder(message_loop_.message_loop_proxy())),
pending_decode_(false),
pending_reset_(false) {}
virtual ~OpusAudioDecoderTest() {
EXPECT_FALSE(pending_decode_);
EXPECT_FALSE(pending_reset_);
}
protected:
void SatisfyPendingDecode() { base::RunLoop().RunUntilIdle(); }
void SendEndOfStream() {
pending_decode_ = true;
decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
base::Bind(&OpusAudioDecoderTest::DecodeFinished,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Initialize() {
// Load the test data file.
data_ = ReadTestDataFile("bear-opus.ogg");
protocol_.reset(
new InMemoryUrlProtocol(data_->data(), data_->data_size(), false));
reader_.reset(new AudioFileReader(protocol_.get()));
reader_->Open();
AudioDecoderConfig config;
AVCodecContextToAudioDecoderConfig(
reader_->codec_context_for_testing(), false, &config, false);
InitializeDecoder(config);
}
void InitializeDecoder(const AudioDecoderConfig& config) {
decoder_->Initialize(config,
NewExpectedStatusCB(PIPELINE_OK),
base::Bind(&OpusAudioDecoderTest::OnDecoderOutput,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Decode() {
pending_decode_ = true;
AVPacket packet;
ASSERT_TRUE(reader_->ReadPacketForTesting(&packet));
scoped_refptr<DecoderBuffer> buffer =
DecoderBuffer::CopyFrom(packet.data, packet.size);
buffer->set_timestamp(ConvertFromTimeBase(
reader_->codec_context_for_testing()->time_base, packet.pts));
buffer->set_duration(ConvertFromTimeBase(
reader_->codec_context_for_testing()->time_base, packet.duration));
decoder_->Decode(buffer,
base::Bind(&OpusAudioDecoderTest::DecodeFinished,
base::Unretained(this)));
av_free_packet(&packet);
base::RunLoop().RunUntilIdle();
}
void Reset() {
pending_reset_ = true;
decoder_->Reset(base::Bind(&OpusAudioDecoderTest::ResetFinished,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Stop() {
decoder_->Stop();
base::RunLoop().RunUntilIdle();
}
void OnDecoderOutput(const scoped_refptr<AudioBuffer>& buffer) {
decoded_audio_.push_back(buffer);
}
void DecodeFinished(AudioDecoder::Status status) {
EXPECT_TRUE(pending_decode_);
pending_decode_ = false;
// If we have a pending reset, we expect an abort.
if (pending_reset_) {
EXPECT_EQ(status, AudioDecoder::kAborted);
return;
}
EXPECT_EQ(status, AudioDecoder::kOk);
}
void ResetFinished() {
EXPECT_TRUE(pending_reset_);
// Reset should always finish after Decode.
EXPECT_FALSE(pending_decode_);
pending_reset_ = false;
}
void ExpectDecodedAudio(size_t i, int64 timestamp, int64 duration) {
EXPECT_LT(i, decoded_audio_.size());
EXPECT_EQ(timestamp, decoded_audio_[i]->timestamp().InMicroseconds());
EXPECT_EQ(duration, decoded_audio_[i]->duration().InMicroseconds());
EXPECT_FALSE(decoded_audio_[i]->end_of_stream());
}
size_t decoded_audio_size() const {
return decoded_audio_.size();
}
private:
base::MessageLoop message_loop_;
scoped_refptr<DecoderBuffer> data_;
scoped_ptr<InMemoryUrlProtocol> protocol_;
scoped_ptr<AudioFileReader> reader_;
scoped_ptr<OpusAudioDecoder> decoder_;
bool pending_decode_;
bool pending_reset_;
std::deque<scoped_refptr<AudioBuffer> > decoded_audio_;
DISALLOW_COPY_AND_ASSIGN(OpusAudioDecoderTest);
};
TEST_F(OpusAudioDecoderTest, Initialize) {
Initialize();
Stop();
}
TEST_F(OpusAudioDecoderTest, InitializeWithNoCodecDelay) {
const uint8_t kOpusExtraData[] = {
0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x02,
// The next two bytes represent the codec delay.
0x00, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00};
AudioDecoderConfig decoder_config;
decoder_config.Initialize(kCodecOpus,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
48000,
kOpusExtraData,
ARRAYSIZE_UNSAFE(kOpusExtraData),
false,
false,
base::TimeDelta::FromMilliseconds(80),
0);
InitializeDecoder(decoder_config);
Stop();
}
TEST_F(OpusAudioDecoderTest, ProduceAudioSamples) {
Initialize();
Decode();
Decode();
Decode();
ASSERT_EQ(3u, decoded_audio_size());
ExpectDecodedAudio(0, 0, 3500);
ExpectDecodedAudio(1, 3500, 10000);
ExpectDecodedAudio(2, 13500, 10000);
// Call one more time with EOS.
SendEndOfStream();
ASSERT_EQ(3u, decoded_audio_size());
Stop();
}
TEST_F(OpusAudioDecoderTest, DecodeAbort) {
Initialize();
Decode();
Stop();
}
TEST_F(OpusAudioDecoderTest, PendingDecode_Stop) {
Initialize();
Decode();
Stop();
SatisfyPendingDecode();
}
TEST_F(OpusAudioDecoderTest, PendingDecode_Reset) {
Initialize();
Decode();
Reset();
SatisfyPendingDecode();
Stop();
}
TEST_F(OpusAudioDecoderTest, PendingDecode_ResetStop) {
Initialize();
Decode();
Reset();
Stop();
SatisfyPendingDecode();
}
} // namespace media
......@@ -1095,6 +1095,7 @@
'cdm/json_web_key_unittest.cc',
'ffmpeg/ffmpeg_common_unittest.cc',
'filters/audio_clock_unittest.cc',
'filters/audio_decoder_unittest.cc',
'filters/audio_decoder_selector_unittest.cc',
'filters/audio_file_reader_unittest.cc',
'filters/audio_renderer_algorithm_unittest.cc',
......@@ -1110,7 +1111,6 @@
'filters/fake_video_decoder.cc',
'filters/fake_video_decoder.h',
'filters/fake_video_decoder_unittest.cc',
'filters/ffmpeg_audio_decoder_unittest.cc',
'filters/ffmpeg_demuxer_unittest.cc',
'filters/ffmpeg_glue_unittest.cc',
'filters/ffmpeg_video_decoder_unittest.cc',
......@@ -1119,7 +1119,6 @@
'filters/h264_bit_reader_unittest.cc',
'filters/h264_parser_unittest.cc',
'filters/in_memory_url_protocol_unittest.cc',
'filters/opus_audio_decoder_unittest.cc',
'filters/pipeline_integration_test.cc',
'filters/pipeline_integration_test_base.cc',
'filters/skcanvas_video_renderer_unittest.cc',
......@@ -1193,15 +1192,14 @@
'audio/audio_input_volume_unittest.cc',
'base/container_names_unittest.cc',
'ffmpeg/ffmpeg_common_unittest.cc',
'filters/audio_decoder_unittest.cc',
'filters/audio_file_reader_unittest.cc',
'filters/blocking_url_protocol_unittest.cc',
'filters/ffmpeg_audio_decoder_unittest.cc',
'filters/ffmpeg_demuxer_unittest.cc',
'filters/ffmpeg_glue_unittest.cc',
'filters/ffmpeg_h264_to_annex_b_bitstream_converter_unittest.cc',
'filters/ffmpeg_video_decoder_unittest.cc',
'filters/in_memory_url_protocol_unittest.cc',
'filters/opus_audio_decoder_unittest.cc',
'filters/pipeline_integration_test.cc',
'filters/pipeline_integration_test_base.cc',
],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment