Index: media/filters/video_renderer_base_unittest.cc |
diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc |
index 88a1b1a8551b3dcc0d50504fc51337a5b551e07f..7ff3f411c0d93e4d21b7fd6da1f83cd8bdba4234 100644 |
--- a/media/filters/video_renderer_base_unittest.cc |
+++ b/media/filters/video_renderer_base_unittest.cc |
@@ -48,10 +48,11 @@ class VideoRendererBaseTest : public ::testing::Test { |
event_(false, false), |
timeout_(base::TimeDelta::FromMilliseconds( |
TestTimeouts::action_timeout_ms())), |
- seeking_(false) { |
+ seeking_(false), |
+ paint_cv_(&lock_), |
+ paint_was_called_(false) { |
renderer_ = new VideoRendererBase( |
- base::Bind(&VideoRendererBaseTest::PaintCBWasCalled, |
- base::Unretained(this)), |
+ base::Bind(&VideoRendererBaseTest::Paint, base::Unretained(this)), |
base::Bind(&VideoRendererBaseTest::SetOpaqueCBWasCalled, |
base::Unretained(this))); |
renderer_->set_host(&host_); |
@@ -74,8 +75,6 @@ class VideoRendererBaseTest : public ::testing::Test { |
} |
} |
- MOCK_METHOD0(PaintCBWasCalled, void()); |
- |
MOCK_CONST_METHOD1(SetOpaqueCBWasCalled, void(bool)); |
void Initialize() { |
@@ -178,6 +177,18 @@ class VideoRendererBaseTest : public ::testing::Test { |
} |
} |
+ void AbortRead() { |
+ // Lock+swap to avoid re-entrancy issues. |
+ VideoDecoder::ReadCB read_cb; |
+ { |
+ base::AutoLock l(lock_); |
+ CHECK(!read_cb_.is_null()) << "Can't deliver a frame without a callback"; |
+ std::swap(read_cb, read_cb_); |
+ } |
+ |
+ read_cb.Run(NULL); |
+ } |
+ |
void ExpectCurrentFrame(bool present) { |
scoped_refptr<VideoFrame> frame; |
renderer_->GetCurrentFrame(&frame); |
@@ -220,10 +231,12 @@ class VideoRendererBaseTest : public ::testing::Test { |
void RenderFrame(int64 timestamp) { |
base::AutoLock l(lock_); |
time_ = base::TimeDelta::FromMicroseconds(timestamp); |
+ paint_was_called_ = false; |
if (read_cb_.is_null()) { |
cv_.TimedWait(timeout_); |
CHECK(!read_cb_.is_null()) << "Timed out waiting for read to occur."; |
} |
+ WaitForPaint_Locked(); |
} |
// Advances clock to |timestamp| (which should be the timestamp of the last |
@@ -241,6 +254,11 @@ class VideoRendererBaseTest : public ::testing::Test { |
base::WaitableEvent* event() { return &event_; } |
const base::TimeDelta& timeout() { return timeout_; } |
+ void VerifyNotSeeking() { |
+ base::AutoLock l(lock_); |
+ ASSERT_FALSE(seeking_); |
+ } |
+ |
protected: |
StatisticsCallback NewStatisticsCallback() { |
return base::Bind(&MockStatisticsCallback::OnStatistics, |
@@ -280,13 +298,12 @@ class VideoRendererBaseTest : public ::testing::Test { |
} |
void FinishSeeking(int64 timestamp) { |
- EXPECT_CALL(*this, PaintCBWasCalled()); |
- EXPECT_TRUE(seeking_); |
- |
// Satisfy the read requests. The callback must be executed in order |
// to exit the loop since VideoRendererBase can read a few extra frames |
// after |timestamp| in order to preroll. |
base::AutoLock l(lock_); |
+ EXPECT_TRUE(seeking_); |
+ paint_was_called_ = false; |
int i = 0; |
while (seeking_) { |
if (!read_cb_.is_null()) { |
@@ -310,6 +327,21 @@ class VideoRendererBaseTest : public ::testing::Test { |
} |
EXPECT_TRUE(read_cb_.is_null()); |
+ WaitForPaint_Locked(); |
+ } |
+ |
+ void Paint() { |
+ base::AutoLock l(lock_); |
+ paint_was_called_ = true; |
+ paint_cv_.Signal(); |
+ } |
+ |
+ void WaitForPaint_Locked() { |
+ lock_.AssertAcquired(); |
+ if (paint_was_called_) |
+ return; |
+ paint_cv_.TimedWait(timeout_); |
+ EXPECT_TRUE(paint_was_called_); |
} |
base::Lock lock_; |
@@ -322,6 +354,10 @@ class VideoRendererBaseTest : public ::testing::Test { |
VideoDecoder::ReadCB read_cb_; |
base::TimeDelta time_; |
+ // Used in conjunction with |lock_| to wait for Paint() calls. |
+ base::ConditionVariable paint_cv_; |
+ bool paint_was_called_; |
+ |
DISALLOW_COPY_AND_ASSIGN(VideoRendererBaseTest); |
}; |
@@ -342,13 +378,8 @@ TEST_F(VideoRendererBaseTest, EndOfStream) { |
Play(); |
// Finish rendering up to the next-to-last frame. |
- // |
- // Put the gmock expectation here to avoid racing with the rendering thread. |
- EXPECT_CALL(*this, PaintCBWasCalled()) |
- .Times(limits::kMaxVideoFrames - 1); |
- for (int i = 1; i < limits::kMaxVideoFrames; ++i) { |
+ for (int i = 1; i < limits::kMaxVideoFrames; ++i) |
RenderFrame(kFrameDuration * i); |
- } |
// Finish rendering the last frame, we should NOT get a new frame but instead |
// get notified of end of stream. |
@@ -475,4 +506,44 @@ TEST_F(VideoRendererBaseTest, Shutdown_DuringPaint) { |
Stop(); |
} |
+TEST_F(VideoRendererBaseTest, AbortPendingRead_Playing) { |
+ Initialize(); |
+ Play(); |
+ |
+ // Render a frame to trigger a Read(). |
+ RenderFrame(kFrameDuration); |
+ |
+ AbortRead(); |
+ |
+ Pause(); |
+ Flush(); |
+ Seek(kFrameDuration * 6); |
+ ExpectCurrentTimestamp(kFrameDuration * 6); |
+ Shutdown(); |
+} |
+ |
+TEST_F(VideoRendererBaseTest, AbortPendingRead_Flush) { |
+ Initialize(); |
+ Play(); |
+ |
+ // Render a frame to trigger a Read(). |
+ RenderFrame(kFrameDuration); |
+ |
+ Pause(); |
+ renderer_->Flush(NewWaitableClosure()); |
+ AbortRead(); |
+ WaitForClosure(); |
+ Shutdown(); |
+} |
+ |
+TEST_F(VideoRendererBaseTest, AbortPendingRead_Seek) { |
+ Initialize(); |
+ Pause(); |
+ Flush(); |
+ StartSeeking(kFrameDuration * 6); |
+ AbortRead(); |
+ VerifyNotSeeking(); |
+ Shutdown(); |
+} |
+ |
} // namespace media |