diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-09 18:58:07 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-09 18:58:07 +0000 |
commit | 8ff8c5de539874d02a0614d3630de2e59d6ca1b7 (patch) | |
tree | cb139450234b9840ff97d0517fbfa26eaa606447 /media | |
parent | 127ea5b4c481048ad00af9e09617cc0d4c0ed0ba (diff) | |
download | chromium_src-8ff8c5de539874d02a0614d3630de2e59d6ca1b7.zip chromium_src-8ff8c5de539874d02a0614d3630de2e59d6ca1b7.tar.gz chromium_src-8ff8c5de539874d02a0614d3630de2e59d6ca1b7.tar.bz2 |
Creating integration tests for media pipeline that use real decoders and demuxers.
TEST=PipelineIntegrationTest
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=116349
Review URL: http://codereview.chromium.org/8968035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@116889 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/clock.cc | 6 | ||||
-rw-r--r-- | media/base/clock.h | 5 | ||||
-rw-r--r-- | media/base/pipeline_impl.cc | 50 | ||||
-rw-r--r-- | media/base/pipeline_impl.h | 4 | ||||
-rw-r--r-- | media/base/test_data_util.cc | 13 | ||||
-rw-r--r-- | media/base/test_data_util.h | 5 | ||||
-rw-r--r-- | media/filters/audio_renderer_base.cc | 4 | ||||
-rw-r--r-- | media/filters/null_audio_renderer.cc | 73 | ||||
-rw-r--r-- | media/filters/null_audio_renderer.h | 20 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test.cc | 218 | ||||
-rw-r--r-- | media/media.gyp | 3 |
11 files changed, 325 insertions, 76 deletions
diff --git a/media/base/clock.cc b/media/base/clock.cc index 61096177..aaa0c13 100644 --- a/media/base/clock.cc +++ b/media/base/clock.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -17,6 +17,10 @@ Clock::Clock(TimeProvider* time_provider) Clock::~Clock() {} +bool Clock::IsPlaying() const { + return playing_; +} + base::TimeDelta Clock::Play() { DCHECK(!playing_); reference_ = GetTimeFromProvider(); diff --git a/media/base/clock.h b/media/base/clock.h index 0acf71b..fc1be6d 100644 --- a/media/base/clock.h +++ b/media/base/clock.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -33,6 +33,9 @@ class MEDIA_EXPORT Clock { Clock(TimeProvider* time_provider); ~Clock(); + // Returns true if the clock is running. + bool IsPlaying() const; + // Starts the clock and returns the current media time, which will increase // with respect to the current playback rate. base::TimeDelta Play(); diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index 5ea444c..eec4351 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. // @@ -232,9 +232,6 @@ void PipelineImpl::SetPreload(Preload preload) { } base::TimeDelta PipelineImpl::GetCurrentTime() const { - // TODO(scherkus): perhaps replace checking state_ == kEnded with a bool that - // is set/get under the lock, because this is breaching the contract that - // |state_| is only accessed on |message_loop_|. base::AutoLock auto_lock(lock_); return GetCurrentTime_Locked(); } @@ -242,9 +239,9 @@ base::TimeDelta PipelineImpl::GetCurrentTime() const { base::TimeDelta PipelineImpl::GetCurrentTime_Locked() const { lock_.AssertAcquired(); base::TimeDelta elapsed = clock_->Elapsed(); - if (state_ == kEnded || elapsed > duration_) { + if (elapsed > duration_) return duration_; - } + return elapsed; } @@ -487,9 +484,8 @@ void PipelineImpl::SetTime(base::TimeDelta time) { if (waiting_for_clock_update_) { if (time < clock_->Elapsed()) return; - waiting_for_clock_update_ = false; clock_->SetTime(time); - clock_->Play(); + StartClockIfWaitingForTimeUpdate_Locked(); return; } clock_->SetTime(time); @@ -900,8 +896,7 @@ void PipelineImpl::SeekTask(base::TimeDelta time, // Kick off seeking! { base::AutoLock auto_lock(lock_); - // If we are waiting for a clock update, the clock hasn't been played yet. - if (!waiting_for_clock_update_) + if (clock_->IsPlaying()) clock_->Pause(); } pipeline_filter_->Pause( @@ -924,12 +919,10 @@ void PipelineImpl::NotifyEndedTask() { return; } - if (waiting_for_clock_update_) { - // Start clock since there is no more audio to - // trigger clock updates. - waiting_for_clock_update_ = false; - clock_->Play(); - } + // Start clock since there is no more audio to + // trigger clock updates. + base::AutoLock auto_lock(lock_); + StartClockIfWaitingForTimeUpdate_Locked(); } if (video_renderer_ && !video_renderer_->HasEnded()) { @@ -938,6 +931,12 @@ void PipelineImpl::NotifyEndedTask() { // Transition to ended, executing the callback if present. SetState(kEnded); + { + base::AutoLock auto_lock(lock_); + clock_->Pause(); + clock_->SetTime(duration_); + } + if (!ended_callback_.is_null()) { ended_callback_.Run(status_); } @@ -964,6 +963,10 @@ void PipelineImpl::DisableAudioRendererTask() { demuxer_->OnAudioRendererDisabled(); pipeline_filter_->OnAudioRendererDisabled(); } + + // Start clock since there is no more audio to + // trigger clock updates. + StartClockIfWaitingForTimeUpdate_Locked(); } void PipelineImpl::FilterStateTransitionTask() { @@ -1029,9 +1032,9 @@ void PipelineImpl::FilterStateTransitionTask() { base::AutoLock auto_lock(lock_); // We use audio stream to update the clock. So if there is such a stream, // we pause the clock until we receive a valid timestamp. - waiting_for_clock_update_ = has_audio_; - if (!waiting_for_clock_update_) - clock_->Play(); + waiting_for_clock_update_ = true; + if (!has_audio_) + StartClockIfWaitingForTimeUpdate_Locked(); // Start monitoring rate of downloading. int bitrate = 0; @@ -1430,4 +1433,13 @@ void PipelineImpl::NotifyCanPlayThrough() { NotifyNetworkEventTask(CAN_PLAY_THROUGH); } +void PipelineImpl::StartClockIfWaitingForTimeUpdate_Locked() { + lock_.AssertAcquired(); + if (!waiting_for_clock_update_) + return; + + waiting_for_clock_update_ = false; + clock_->Play(); +} + } // namespace media diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h index be55291..e5652f0 100644 --- a/media/base/pipeline_impl.h +++ b/media/base/pipeline_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -349,6 +349,8 @@ class MEDIA_EXPORT PipelineImpl // needing to pause to buffer. void NotifyCanPlayThrough(); + void StartClockIfWaitingForTimeUpdate_Locked(); + // Message loop used to execute pipeline tasks. MessageLoop* message_loop_; diff --git a/media/base/test_data_util.cc b/media/base/test_data_util.cc index 45a3735..3e6f3fd 100644 --- a/media/base/test_data_util.cc +++ b/media/base/test_data_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -11,6 +11,17 @@ namespace media { +std::string GetTestDataURL(const std::string& name) { + FilePath file_path; + CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); + + file_path = file_path.Append(FILE_PATH_LITERAL("media")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("data")) + .AppendASCII(name); + return file_path.MaybeAsASCII(); +} + void ReadTestDataFile(const std::string& name, scoped_array<uint8>* buffer, int* size) { FilePath file_path; diff --git a/media/base/test_data_util.h b/media/base/test_data_util.h index 19f8e7f..142780b 100644 --- a/media/base/test_data_util.h +++ b/media/base/test_data_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -13,6 +13,9 @@ namespace media { +// Returns a URL path for a file in the media/test/data directory. +std::string GetTestDataURL(const std::string& name); + // Reads a test file from media/test/data directory and stores it in // a scoped_array. // diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc index bca260a..049a39a 100644 --- a/media/filters/audio_renderer_base.cc +++ b/media/filters/audio_renderer_base.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -278,10 +278,12 @@ void AudioRendererBase::ScheduleRead_Locked() { } void AudioRendererBase::SetPlaybackRate(float playback_rate) { + base::AutoLock auto_lock(lock_); algorithm_->SetPlaybackRate(playback_rate); } float AudioRendererBase::GetPlaybackRate() { + base::AutoLock auto_lock(lock_); return algorithm_->playback_rate(); } diff --git a/media/filters/null_audio_renderer.cc b/media/filters/null_audio_renderer.cc index 0d5daf5..d4689aa 100644 --- a/media/filters/null_audio_renderer.cc +++ b/media/filters/null_audio_renderer.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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 <algorithm> #include <cmath> +#include "base/bind.h" #include "base/logging.h" #include "base/threading/platform_thread.h" #include "media/base/filter_host.h" @@ -21,45 +22,17 @@ NullAudioRenderer::NullAudioRenderer() : AudioRendererBase(), bytes_per_millisecond_(0), buffer_size_(0), - thread_(base::kNullThreadHandle), - shutdown_(false) { + thread_("AudioThread") { } NullAudioRenderer::~NullAudioRenderer() { - DCHECK_EQ(base::kNullThreadHandle, thread_); + DCHECK(!thread_.IsRunning()); } void NullAudioRenderer::SetVolume(float volume) { // Do nothing. } -void NullAudioRenderer::ThreadMain() { - // Loop until we're signaled to stop. - while (!shutdown_) { - float sleep_in_milliseconds = 0.0f; - - // Only consume buffers when actually playing. - if (GetPlaybackRate() > 0.0f) { - size_t bytes = FillBuffer(buffer_.get(), - buffer_size_, - base::TimeDelta(), - true); - - // Calculate our sleep duration, taking playback rate into consideration. - sleep_in_milliseconds = - floor(bytes / static_cast<float>(bytes_per_millisecond_)); - sleep_in_milliseconds /= GetPlaybackRate(); - } else { - // If paused, sleep for 10 milliseconds before polling again. - sleep_in_milliseconds = 10.0f; - } - - // Sleep for at least one millisecond so we don't spin the CPU. - base::PlatformThread::Sleep( - std::max(1, static_cast<int>(sleep_in_milliseconds))); - } -} - bool NullAudioRenderer::OnInitialize(int bits_per_channel, ChannelLayout channel_layout, int sample_rate) { @@ -71,17 +44,41 @@ bool NullAudioRenderer::OnInitialize(int bits_per_channel, buffer_.reset(new uint8[buffer_size_]); DCHECK(buffer_.get()); - // It's safe to start the thread now because it simply sleeps when playback - // rate is 0.0f. - return base::PlatformThread::Create(0, this, &thread_); + if (!thread_.Start()) + return false; + + thread_.message_loop()->PostTask(FROM_HERE, base::Bind( + &NullAudioRenderer::FillBufferTask, this)); + return true; } void NullAudioRenderer::OnStop() { - shutdown_ = true; - if (thread_) { - base::PlatformThread::Join(thread_); - thread_ = base::kNullThreadHandle; + thread_.Stop(); +} + +void NullAudioRenderer::FillBufferTask() { + int64 sleep_in_milliseconds = 0; + + // Only consume buffers when actually playing. + if (GetPlaybackRate() > 0.0f) { + size_t bytes = FillBuffer(buffer_.get(), + buffer_size_, + base::TimeDelta(), + true); + + // Calculate our sleep duration, taking playback rate into consideration. + sleep_in_milliseconds = + bytes / (bytes_per_millisecond_ * GetPlaybackRate()); + } else { + // If paused, sleep for 10 milliseconds before polling again. + sleep_in_milliseconds = 10; } + + // Sleep for at least one millisecond so we don't spin the CPU. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&NullAudioRenderer::FillBufferTask, this), + std::max(sleep_in_milliseconds, static_cast<int64>(1))); } } // namespace media diff --git a/media/filters/null_audio_renderer.h b/media/filters/null_audio_renderer.h index 9f4ed94..9832367 100644 --- a/media/filters/null_audio_renderer.h +++ b/media/filters/null_audio_renderer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -16,16 +16,14 @@ #include <deque> #include "base/memory/scoped_ptr.h" -#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" #include "media/base/buffers.h" #include "media/base/filters.h" #include "media/filters/audio_renderer_base.h" namespace media { -class MEDIA_EXPORT NullAudioRenderer - : public AudioRendererBase, - public base::PlatformThread::Delegate { +class MEDIA_EXPORT NullAudioRenderer : public AudioRendererBase { public: NullAudioRenderer(); virtual ~NullAudioRenderer(); @@ -33,9 +31,6 @@ class MEDIA_EXPORT NullAudioRenderer // AudioRenderer implementation. virtual void SetVolume(float volume) OVERRIDE; - // PlatformThread::Delegate implementation. - virtual void ThreadMain() OVERRIDE; - protected: // AudioRendererBase implementation. virtual bool OnInitialize(int bits_per_channel, @@ -44,6 +39,10 @@ class MEDIA_EXPORT NullAudioRenderer virtual void OnStop() OVERRIDE; private: + // Audio thread task that periodically calls FillBuffer() to consume + // audio data. + void FillBufferTask(); + // A number to convert bytes written in FillBuffer to milliseconds based on // the audio format. size_t bytes_per_millisecond_; @@ -53,10 +52,7 @@ class MEDIA_EXPORT NullAudioRenderer size_t buffer_size_; // Separate thread used to throw away data. - base::PlatformThreadHandle thread_; - - // Shutdown flag. - bool shutdown_; + base::Thread thread_; DISALLOW_COPY_AND_ASSIGN(NullAudioRenderer); }; diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc new file mode 100644 index 0000000..6f99590 --- /dev/null +++ b/media/filters/pipeline_integration_test.cc @@ -0,0 +1,218 @@ +// 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 "base/bind.h" +#include "media/base/filter_collection.h" +#include "media/base/media_log.h" +#include "media/base/message_loop_factory_impl.h" +#include "media/base/pipeline_impl.h" +#include "media/base/test_data_util.h" +#include "media/filters/ffmpeg_audio_decoder.h" +#include "media/filters/ffmpeg_demuxer_factory.h" +#include "media/filters/ffmpeg_video_decoder.h" +#include "media/filters/file_data_source_factory.h" +#include "media/filters/null_audio_renderer.h" +#include "media/filters/video_renderer_base.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::AnyNumber; + +namespace media { + +// Integration tests for PipelineImpl. Real demuxers, real decoders, and +// base renderer implementations are used to verify pipeline functionality. The +// renderers used in these tests rely heavily on the AudioRendererBase & +// VideoRendererBase implementations which contain a majority of the code used +// in the real AudioRendererImpl & VideoRendererImpl implementations used in the +// browser. The renderers in this test don't actually write data to a display or +// audio device. Both of these devices are simulated since they have little +// effect on verifying pipeline behavior and allow tests to run faster than +// real-time. +class PipelineIntegrationTest : public testing::Test { + public: + PipelineIntegrationTest() + : message_loop_factory_(new MessageLoopFactoryImpl()), + pipeline_(new PipelineImpl(&message_loop_, new MediaLog())), + ended_(false) { + pipeline_->Init( + base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), + Pipeline::NetworkEventCB()); + + EXPECT_CALL(*this, OnVideoRendererPaint()).Times(AnyNumber()); + EXPECT_CALL(*this, OnSetOpaque(true)); + } + + virtual ~PipelineIntegrationTest() { + if (!pipeline_->IsRunning()) + return; + + Stop(); + } + + void OnStatusCallback(PipelineStatus expected_status, + PipelineStatus status) { + DCHECK_EQ(status, expected_status); + message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); + } + + PipelineStatusCB QuitOnStatusCB(PipelineStatus expected_status) { + return base::Bind(&PipelineIntegrationTest::OnStatusCallback, + base::Unretained(this), + expected_status); + } + + void OnEnded(PipelineStatus status) { + DCHECK_EQ(status, PIPELINE_OK); + DCHECK(!ended_); + ended_ = true; + message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); + } + + void WaitUntilOnEnded() { + if (!ended_) { + message_loop_.Run(); + DCHECK(ended_); + } + } + + MOCK_METHOD1(OnError, void(PipelineStatus)); + + void Start(const std::string& url, PipelineStatus expected_status) { + pipeline_->Start(CreateFilterCollection(), url, + QuitOnStatusCB(expected_status)); + message_loop_.Run(); + } + + void Play() { + pipeline_->SetPlaybackRate(1); + } + + void Pause() { + pipeline_->SetPlaybackRate(0); + } + + void Seek(base::TimeDelta seek_time) { + ended_ = false; + + pipeline_->Seek(seek_time, QuitOnStatusCB(PIPELINE_OK)); + message_loop_.Run(); + } + + void Stop() { + DCHECK(pipeline_->IsRunning()); + pipeline_->Stop(QuitOnStatusCB(PIPELINE_OK)); + message_loop_.Run(); + } + + void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time) { + if (pipeline_->GetCurrentTime() >= quit_time) { + message_loop_.Quit(); + return; + } + + message_loop_.PostDelayedTask( + FROM_HERE, + base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, + base::Unretained(this), quit_time), + 10); + } + + void WaitUntilCurrentTimeIsAfter(const base::TimeDelta& wait_time) { + DCHECK(pipeline_->IsRunning()); + DCHECK_GT(pipeline_->GetPlaybackRate(), 0); + DCHECK(wait_time <= pipeline_->GetMediaDuration()); + + message_loop_.PostDelayedTask( + FROM_HERE, + base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, + base::Unretained(this), + wait_time), + 10); + message_loop_.Run(); + } + + FilterCollection* CreateFilterCollection() { + scoped_ptr<FilterCollection> collection( + new FilterCollection()); + collection->SetDemuxerFactory( + new FFmpegDemuxerFactory(new FileDataSourceFactory(), + &message_loop_)); + collection->AddAudioDecoder(new FFmpegAudioDecoder( + message_loop_factory_->GetMessageLoop("AudioDecoderThread"))); + collection->AddVideoDecoder(new FFmpegVideoDecoder( + message_loop_factory_->GetMessageLoop("VideoDecoderThread"))); + collection->AddVideoRenderer(new VideoRendererBase( + base::Bind(&PipelineIntegrationTest::OnVideoRendererPaint, + base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnSetOpaque, + base::Unretained(this)))); + collection->AddAudioRenderer(new NullAudioRenderer()); + return collection.release(); + } + + protected: + MessageLoop message_loop_; + scoped_ptr<MessageLoopFactory> message_loop_factory_; + scoped_refptr<Pipeline> pipeline_; + bool ended_; + + private: + MOCK_METHOD0(OnVideoRendererPaint, void()); + MOCK_METHOD1(OnSetOpaque, void(bool)); +}; + + +TEST_F(PipelineIntegrationTest, BasicPlayback) { + Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); + + Play(); + + WaitUntilOnEnded(); +} + +TEST_F(PipelineIntegrationTest, SeekWhilePaused) { + Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); + + base::TimeDelta duration(pipeline_->GetMediaDuration()); + base::TimeDelta start_seek_time(duration / 4); + base::TimeDelta seek_time(duration * 3 / 4); + + Play(); + WaitUntilCurrentTimeIsAfter(start_seek_time); + Pause(); + Seek(seek_time); + EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); + Play(); + WaitUntilOnEnded(); + + // Make sure seeking after reaching the end works as expected. + Pause(); + Seek(seek_time); + EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); + Play(); + WaitUntilOnEnded(); +} + +TEST_F(PipelineIntegrationTest, SeekWhilePlaying) { + Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); + + base::TimeDelta duration(pipeline_->GetMediaDuration()); + base::TimeDelta start_seek_time(duration / 4); + base::TimeDelta seek_time(duration * 3 / 4); + + Play(); + WaitUntilCurrentTimeIsAfter(start_seek_time); + Seek(seek_time); + EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); + WaitUntilOnEnded(); + + // Make sure seeking after reaching the end works as expected. + Seek(seek_time); + EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); + WaitUntilOnEnded(); +} + +} // namespace media diff --git a/media/media.gyp b/media/media.gyp index b28fdac..d218f32 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# 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. @@ -621,6 +621,7 @@ 'filters/ffmpeg_h264_bitstream_converter_unittest.cc', 'filters/ffmpeg_video_decoder_unittest.cc', 'filters/file_data_source_unittest.cc', + 'filters/pipeline_integration_test.cc', 'filters/video_renderer_base_unittest.cc', 'video/capture/video_capture_device_unittest.cc', 'webm/cluster_builder.cc', |