summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-16 01:23:58 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-16 01:23:58 +0000
commitdb64fc3c269b8bcab976c21735437855a3c95637 (patch)
treec8ead48f6594374077a9e0bb11afb08b7876fad9 /media
parentcae0e51976085db08f0f52266a864bfa439fe802 (diff)
downloadchromium_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.cc6
-rw-r--r--media/base/test_data_util.h2
-rw-r--r--media/filters/ffmpeg_audio_decoder_unittest.cc199
-rw-r--r--media/media.gyp1
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',