diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-16 01:23:58 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-16 01:23:58 +0000 |
commit | db64fc3c269b8bcab976c21735437855a3c95637 (patch) | |
tree | c8ead48f6594374077a9e0bb11afb08b7876fad9 /media | |
parent | cae0e51976085db08f0f52266a864bfa439fe802 (diff) | |
download | chromium_src-db64fc3c269b8bcab976c21735437855a3c95637.zip chromium_src-db64fc3c269b8bcab976c21735437855a3c95637.tar.gz chromium_src-db64fc3c269b8bcab976c21735437855a3c95637.tar.bz2 |
Write tests for FFmpegAudioDecoder so I can rewrite the class sans regressions.
TEST=media_unittests
BUG=96773
Review URL: http://codereview.chromium.org/7891050
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@101429 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/test_data_util.cc | 6 | ||||
-rw-r--r-- | media/base/test_data_util.h | 2 | ||||
-rw-r--r-- | media/filters/ffmpeg_audio_decoder_unittest.cc | 199 | ||||
-rw-r--r-- | media/media.gyp | 1 |
4 files changed, 206 insertions, 2 deletions
diff --git a/media/base/test_data_util.cc b/media/base/test_data_util.cc index fc30744..45a3735 100644 --- a/media/base/test_data_util.cc +++ b/media/base/test_data_util.cc @@ -7,6 +7,7 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" +#include "media/ffmpeg/ffmpeg_common.h" namespace media { @@ -24,8 +25,11 @@ void ReadTestDataFile(const std::string& name, scoped_array<uint8>* buffer, CHECK(file_util::GetFileSize(file_path, &tmp)) << "Failed to get file size for '" << name << "'"; + // Why FF_INPUT_BUFFER_PADDING_SIZE? FFmpeg assumes all input buffers are + // padded. Since most of our test data is passed to FFmpeg, it makes sense + // to do the padding here instead of scattering it around test code. int file_size = static_cast<int>(tmp); - buffer->reset(new uint8[file_size]); + buffer->reset(new uint8[file_size + FF_INPUT_BUFFER_PADDING_SIZE]); CHECK(file_size == file_util::ReadFile(file_path, reinterpret_cast<char*>(buffer->get()), diff --git a/media/base/test_data_util.h b/media/base/test_data_util.h index 42878ae..f57b39d 100644 --- a/media/base/test_data_util.h +++ b/media/base/test_data_util.h @@ -23,7 +23,7 @@ void ReadTestDataFile(const std::string& name, scoped_array<uint8>* buffer, int* size); -// Reads a test file from media/test/data directory and stored it in +// Reads a test file from media/test/data directory and stores it in // a Buffer. // // |name| - The name of the file. diff --git a/media/filters/ffmpeg_audio_decoder_unittest.cc b/media/filters/ffmpeg_audio_decoder_unittest.cc new file mode 100644 index 0000000..885ef5a --- /dev/null +++ b/media/filters/ffmpeg_audio_decoder_unittest.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2011 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 <queue> + +#include "base/bind.h" +#include "base/message_loop.h" +#include "base/stringprintf.h" +#include "media/base/mock_callback.h" +#include "media/base/mock_filters.h" +#include "media/base/test_data_util.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::Return; + +namespace media { + +ACTION_P(InvokeReadPacket, test) { + test->ReadPacket(arg0); +} + +class FFmpegAudioDecoderTest : public testing::Test { + public: + FFmpegAudioDecoderTest() + : decoder_(new FFmpegAudioDecoder(&message_loop_)), + demuxer_(new MockDemuxerStream()), + codec_context_(avcodec_alloc_context()) { + CHECK(FFmpegGlue::GetInstance()); + + ReadTestDataFile("vorbis-extradata", + &vorbis_extradata_, + &vorbis_extradata_size_); + + // Refer to media/test/data/README for details on vorbis test data. + for (int i = 0; i < 4; ++i) { + scoped_refptr<Buffer> buffer; + ReadTestDataFile(base::StringPrintf("vorbis-packet-%d", i), &buffer); + + if (i < 3) { + buffer->SetTimestamp(base::TimeDelta()); + } else { + buffer->SetTimestamp(base::TimeDelta::FromMicroseconds(2902)); + } + + buffer->SetDuration(base::TimeDelta()); + encoded_audio_.push_back(buffer); + } + + // Push in an EOS buffer. + encoded_audio_.push_back(new DataBuffer(0)); + + decoder_->set_consume_audio_samples_callback( + base::Bind(&FFmpegAudioDecoderTest::DecodeFinished, + base::Unretained(this))); + + memset(&stream_, 0, sizeof(stream_)); + + stream_.codec = codec_context_; + codec_context_->codec_id = CODEC_ID_VORBIS; + codec_context_->codec_type = AVMEDIA_TYPE_AUDIO; + codec_context_->channels = 2; + codec_context_->channel_layout = AV_CH_LAYOUT_STEREO; + codec_context_->sample_fmt = AV_SAMPLE_FMT_S16; + codec_context_->sample_rate = 44100; + codec_context_->extradata = vorbis_extradata_.get(); + codec_context_->extradata_size = vorbis_extradata_size_; + } + + virtual ~FFmpegAudioDecoderTest() { + // TODO(scherkus): currently FFmpegAudioDecoder assumes FFmpegDemuxer will + // call avcodec_close(). + if (codec_context_->codec) { + avcodec_close(codec_context_); + } + av_free(codec_context_); + } + + void Initialize() { + EXPECT_CALL(*demuxer_, GetAVStream()) + .WillOnce(Return(&stream_)); + + decoder_->Initialize(demuxer_, + NewExpectedCallback(), + NewCallback(&statistics_callback_, + &MockStatisticsCallback::OnStatistics)); + + message_loop_.RunAllPending(); + } + + void Stop() { + decoder_->Stop(NewExpectedCallback()); + message_loop_.RunAllPending(); + } + + void ReadPacket(const DemuxerStream::ReadCallback& read_callback) { + CHECK(!encoded_audio_.empty()) << "ReadPacket() called too many times"; + + scoped_refptr<Buffer> buffer(encoded_audio_.front()); + encoded_audio_.pop_front(); + read_callback.Run(buffer); + } + + void DecodeFinished(scoped_refptr<Buffer> buffer) { + decoded_audio_.push_back(buffer); + } + + void ExpectDecodedAudio(size_t i, int64 timestamp, int64 duration) { + EXPECT_LT(i, decoded_audio_.size()); + EXPECT_EQ(timestamp, decoded_audio_[i]->GetTimestamp().InMicroseconds()); + EXPECT_EQ(duration, decoded_audio_[i]->GetDuration().InMicroseconds()); + EXPECT_FALSE(decoded_audio_[i]->IsEndOfStream()); + } + + void ExpectEndOfStream(size_t i) { + EXPECT_LT(i, decoded_audio_.size()); + EXPECT_EQ(0, decoded_audio_[i]->GetTimestamp().InMicroseconds()); + EXPECT_EQ(0, decoded_audio_[i]->GetDuration().InMicroseconds()); + EXPECT_TRUE(decoded_audio_[i]->IsEndOfStream()); + } + + MessageLoop message_loop_; + scoped_refptr<FFmpegAudioDecoder> decoder_; + scoped_refptr<MockDemuxerStream> demuxer_; + MockStatisticsCallback statistics_callback_; + + scoped_array<uint8> vorbis_extradata_; + int vorbis_extradata_size_; + + std::deque<scoped_refptr<Buffer> > encoded_audio_; + std::deque<scoped_refptr<Buffer> > decoded_audio_; + + AVStream stream_; + AVCodecContext* codec_context_; // Allocated via avcodec_alloc_context(). +}; + +TEST_F(FFmpegAudioDecoderTest, Initialize) { + Initialize(); + + EXPECT_EQ(16, decoder_->config().bits_per_channel); + EXPECT_EQ(CHANNEL_LAYOUT_STEREO, decoder_->config().channel_layout); + EXPECT_EQ(44100, decoder_->config().sample_rate); + + Stop(); +} + +TEST_F(FFmpegAudioDecoderTest, Flush) { + Initialize(); + + decoder_->Flush(NewExpectedCallback()); + message_loop_.RunAllPending(); + + Stop(); +} + +TEST_F(FFmpegAudioDecoderTest, ProduceAudioSamples) { + Initialize(); + + // 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. + EXPECT_CALL(*demuxer_, Read(_)) + .Times(5) + .WillRepeatedly(InvokeReadPacket(this)); + EXPECT_CALL(statistics_callback_, OnStatistics(_)) + .Times(5); + + // We have to use a buffer to trigger a read. Silly. + scoped_refptr<DataBuffer> buffer(0); + decoder_->ProduceAudioSamples(buffer); + decoder_->ProduceAudioSamples(buffer); + decoder_->ProduceAudioSamples(buffer); + message_loop_.RunAllPending(); + + // We should have three decoded audio buffers. + // + // TODO(scherkus): timestamps are off by one packet due to decoder delay. + ASSERT_EQ(3u, decoded_audio_.size()); + ExpectDecodedAudio(0, 0, 2902); + ExpectDecodedAudio(1, 0, 13061); + ExpectDecodedAudio(2, 2902, 23219); + + // Call one more time to trigger EOS. + // + // TODO(scherkus): EOS should flush data, not overwrite timestamps with zero. + decoder_->ProduceAudioSamples(buffer); + message_loop_.RunAllPending(); + ASSERT_EQ(4u, decoded_audio_.size()); + ExpectEndOfStream(3); + + Stop(); +} + +} // namespace media diff --git a/media/media.gyp b/media/media.gyp index 60a192ab..de685ea 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -574,6 +574,7 @@ 'filters/bitstream_converter_unittest.cc', 'filters/chunk_demuxer_unittest.cc', 'filters/decoder_base_unittest.cc', + 'filters/ffmpeg_audio_decoder_unittest.cc', 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', 'filters/ffmpeg_h264_bitstream_converter_unittest.cc', |