summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/clock.cc6
-rw-r--r--media/base/clock.h5
-rw-r--r--media/base/pipeline_impl.cc48
-rw-r--r--media/base/pipeline_impl.h2
-rw-r--r--media/base/test_data_util.cc11
-rw-r--r--media/base/test_data_util.h5
-rw-r--r--media/filters/audio_renderer_base.cc4
-rw-r--r--media/filters/null_audio_renderer.cc73
-rw-r--r--media/filters/null_audio_renderer.h20
-rw-r--r--media/filters/pipeline_integration_test.cc219
-rw-r--r--media/media.gyp3
-rw-r--r--tools/valgrind/tsan/suppressions.txt17
-rw-r--r--tools/valgrind/tsan/suppressions_win32.txt19
13 files changed, 350 insertions, 82 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 7f709e4..e322299 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -231,9 +231,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();
}
@@ -241,9 +238,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;
}
@@ -486,9 +483,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);
@@ -899,8 +895,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(
@@ -923,12 +918,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()) {
@@ -937,6 +930,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_);
}
@@ -963,6 +962,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() {
@@ -1028,9 +1031,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;
@@ -1429,4 +1432,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 c7a8e9f..36a9175 100644
--- a/media/base/pipeline_impl.h
+++ b/media/base/pipeline_impl.h
@@ -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 a7fb78e..43890da 100644
--- a/media/base/test_data_util.cc
+++ b/media/base/test_data_util.cc
@@ -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..decadd4
--- /dev/null
+++ b/media/filters/pipeline_integration_test.cc
@@ -0,0 +1,219 @@
+// 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();
+ }
+
+ scoped_ptr<FilterCollection> CreateFilterCollection() {
+ scoped_ptr<FilterCollection> collection(
+ new FilterCollection());
+ collection->SetDemuxerFactory(scoped_ptr<DemuxerFactory>(
+ new FFmpegDemuxerFactory(
+ scoped_ptr<DataSourceFactory>(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.Pass();
+ }
+
+ 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',
diff --git a/tools/valgrind/tsan/suppressions.txt b/tools/valgrind/tsan/suppressions.txt
index fb60856..a5ec928 100644
--- a/tools/valgrind/tsan/suppressions.txt
+++ b/tools/valgrind/tsan/suppressions.txt
@@ -556,6 +556,23 @@
fun:media::FFmpegVideoDecoder::Decode*
}
{
+ bug_93932_f
+ ThreadSanitizer:Race
+ fun:update_context_from_thread
+ fun:ff_thread_flush
+ ...
+ fun:media::FFmpegVideoDecoder::Flush
+}
+{
+ bug_93932_g
+ ThreadSanitizer:Race
+ fun:frame_thread_free
+ ...
+ fun:avcodec_close
+ ...
+ fun:media::FFmpegVideoDecoder::ReleaseFFmpegResources
+}
+{
bug_95509
ThreadSanitizer:Race
fun:base::SyncSocket::Close
diff --git a/tools/valgrind/tsan/suppressions_win32.txt b/tools/valgrind/tsan/suppressions_win32.txt
index 11889de..97ddad4 100644
--- a/tools/valgrind/tsan/suppressions_win32.txt
+++ b/tools/valgrind/tsan/suppressions_win32.txt
@@ -83,15 +83,7 @@
...
fun:ff_mpeg4video_split
fun:avcodec_close
- fun:media::FFmpegVideoDecodeEngine::~FFmpegVideoDecodeEngine
-}
-{
- bug_93932c
- ThreadSanitizer:Race
- ...
- fun:ff_thread_decode_frame
- fun:avcodec_decode_video2
- fun:media::FFmpegVideoDecodeEngine::DecodeFrame
+ fun:media::FFmpegVideoDecoder::ReleaseFFmpegResources
}
{
bug_93932d
@@ -106,3 +98,12 @@
fun:ff_thread_finish_setup
fun:ptw32_threadStart@4
}
+{
+ bug_93932f
+ ThreadSanitizer:Race
+ ...
+ fun:ff_vp3_h_loop_filter_c
+ ...
+ fun:ff_thread_flush
+ fun:media::FFmpegVideoDecoder::Flush
+}