| 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 2e6cc1219fe39d2e69014d36060bfadf4ef796a6..90f42fe18e9e488c8b112dcb4d5c621d20e60afc 100644
|
| --- a/media/filters/video_renderer_base_unittest.cc
|
| +++ b/media/filters/video_renderer_base_unittest.cc
|
| @@ -2,21 +2,19 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <algorithm>
|
| -
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "base/message_loop.h"
|
| #include "base/stl_util.h"
|
| #include "base/stringprintf.h"
|
| -#include "base/synchronization/condition_variable.h"
|
| #include "base/synchronization/lock.h"
|
| -#include "base/synchronization/waitable_event.h"
|
| -#include "base/test/test_timeouts.h"
|
| +#include "base/timer.h"
|
| #include "media/base/data_buffer.h"
|
| #include "media/base/gmock_callback_support.h"
|
| #include "media/base/limits.h"
|
| -#include "media/base/mock_callback.h"
|
| #include "media/base/mock_filters.h"
|
| +#include "media/base/test_helpers.h"
|
| #include "media/base/video_frame.h"
|
| #include "media/filters/video_renderer_base.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| @@ -32,26 +30,17 @@ using ::testing::StrictMock;
|
|
|
| namespace media {
|
|
|
| -static const int kFrameDuration = 10;
|
| -static const int kVideoDuration = kFrameDuration * 100;
|
| -static const int kEndOfStream = -1;
|
| +static const int kFrameDurationInMs = 10;
|
| +static const int kVideoDurationInMs = kFrameDurationInMs * 100;
|
| static const gfx::Size kNaturalSize(16u, 16u);
|
|
|
| class VideoRendererBaseTest : public ::testing::Test {
|
| public:
|
| VideoRendererBaseTest()
|
| : decoder_(new MockVideoDecoder()),
|
| - demuxer_stream_(new MockDemuxerStream()),
|
| - cv_(&lock_),
|
| - event_(false, false),
|
| - timeout_(TestTimeouts::action_timeout()),
|
| - prerolling_(false),
|
| - next_frame_timestamp_(0),
|
| - paint_cv_(&lock_),
|
| - paint_was_called_(false),
|
| - should_queue_read_cb_(false) {
|
| + demuxer_stream_(new MockDemuxerStream()) {
|
| renderer_ = new VideoRendererBase(
|
| - base::Bind(&VideoRendererBaseTest::Paint, base::Unretained(this)),
|
| + base::Bind(&VideoRendererBaseTest::OnPaint, base::Unretained(this)),
|
| base::Bind(&VideoRendererBaseTest::OnSetOpaque, base::Unretained(this)),
|
| true);
|
|
|
| @@ -65,36 +54,28 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| .Times(AnyNumber());
|
| EXPECT_CALL(*this, OnTimeUpdate(_))
|
| .Times(AnyNumber());
|
| + EXPECT_CALL(*this, OnPaint())
|
| + .Times(AnyNumber());
|
| EXPECT_CALL(*this, OnSetOpaque(_))
|
| .Times(AnyNumber());
|
| }
|
|
|
| - virtual ~VideoRendererBaseTest() {
|
| - read_queue_.clear();
|
| -
|
| - if (renderer_) {
|
| - Stop();
|
| - }
|
| - }
|
| + virtual ~VideoRendererBaseTest() {}
|
|
|
| // Callbacks passed into VideoRendererBase().
|
| + MOCK_CONST_METHOD0(OnPaint, void());
|
| MOCK_CONST_METHOD1(OnSetOpaque, void(bool));
|
|
|
| // Callbacks passed into Initialize().
|
| MOCK_METHOD1(OnTimeUpdate, void(base::TimeDelta));
|
| MOCK_METHOD1(OnNaturalSizeChanged, void(const gfx::Size&));
|
| - MOCK_METHOD0(OnEnded, void());
|
| - MOCK_METHOD1(OnError, void(PipelineStatus));
|
|
|
| void Initialize() {
|
| - Initialize(kVideoDuration);
|
| + InitializeWithDuration(kVideoDurationInMs);
|
| }
|
|
|
| - void Initialize(int duration) {
|
| - duration_ = duration;
|
| -
|
| - // TODO(scherkus): really, really, really need to inject a thread into
|
| - // VideoRendererBase... it makes mocking much harder.
|
| + void InitializeWithDuration(int duration_ms) {
|
| + duration_ = base::TimeDelta::FromMilliseconds(duration_ms);
|
|
|
| // Monitor reads from the decoder.
|
| EXPECT_CALL(*decoder_, Read(_))
|
| @@ -118,87 +99,69 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| EXPECT_CALL(*this, OnNaturalSizeChanged(kNaturalSize));
|
|
|
| // Start prerolling.
|
| - Preroll(0);
|
| + QueuePrerollFrames(0);
|
| + Preroll(0, PIPELINE_OK);
|
| }
|
|
|
| - void InitializeRenderer(PipelineStatus expected_status) {
|
| + void InitializeRenderer(PipelineStatus expected) {
|
| + SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
|
| VideoRendererBase::VideoDecoderList decoders;
|
| decoders.push_back(decoder_);
|
| +
|
| + WaitableMessageLoopEvent event;
|
| renderer_->Initialize(
|
| demuxer_stream_,
|
| decoders,
|
| - NewExpectedStatusCB(expected_status),
|
| + event.GetPipelineStatusCB(),
|
| base::Bind(&MockStatisticsCB::OnStatistics,
|
| base::Unretained(&statistics_cb_object_)),
|
| base::Bind(&VideoRendererBaseTest::OnTimeUpdate,
|
| base::Unretained(this)),
|
| base::Bind(&VideoRendererBaseTest::OnNaturalSizeChanged,
|
| base::Unretained(this)),
|
| - base::Bind(&VideoRendererBaseTest::OnEnded, base::Unretained(this)),
|
| - base::Bind(&VideoRendererBaseTest::OnError, base::Unretained(this)),
|
| + ended_event_.GetClosure(),
|
| + error_event_.GetPipelineStatusCB(),
|
| base::Bind(&VideoRendererBaseTest::GetTime, base::Unretained(this)),
|
| base::Bind(&VideoRendererBaseTest::GetDuration,
|
| base::Unretained(this)));
|
| - }
|
| -
|
| - // Instead of immediately satisfying a decoder Read request, queue it up.
|
| - void QueueReadCB() {
|
| - should_queue_read_cb_ = true;
|
| - }
|
| -
|
| - void SatisfyQueuedReadCB() {
|
| - base::AutoLock l(lock_);
|
| - CHECK(should_queue_read_cb_ && !queued_read_cb_.is_null());
|
| - should_queue_read_cb_ = false;
|
| - VideoDecoder::ReadCB read_cb(queued_read_cb_);
|
| - queued_read_cb_.Reset();
|
| - base::AutoUnlock u(lock_);
|
| - read_cb.Run(VideoDecoder::kOk, VideoFrame::CreateEmptyFrame());
|
| - }
|
| -
|
| - void StartPrerolling(int timestamp, PipelineStatus expected_status) {
|
| - EXPECT_FALSE(prerolling_);
|
| -
|
| - next_frame_timestamp_ = 0;
|
| - prerolling_ = true;
|
| - renderer_->Preroll(base::TimeDelta::FromMilliseconds(timestamp),
|
| - base::Bind(&VideoRendererBaseTest::OnPrerollComplete,
|
| - base::Unretained(this), expected_status));
|
| + event.RunAndWaitForStatus(expected);
|
| }
|
|
|
| void Play() {
|
| SCOPED_TRACE("Play()");
|
| - renderer_->Play(NewWaitableClosure());
|
| - WaitForClosure();
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Play(event.GetClosure());
|
| + event.RunAndWait();
|
| }
|
|
|
| - // Preroll to the given timestamp.
|
| - //
|
| - // Use |kEndOfStream| to preroll end of stream frames.
|
| - void Preroll(int timestamp) {
|
| - SCOPED_TRACE(base::StringPrintf("Preroll(%d)", timestamp));
|
| - bool end_of_stream = (timestamp == kEndOfStream);
|
| - int preroll_timestamp = end_of_stream ? 0 : timestamp;
|
| - StartPrerolling(preroll_timestamp, PIPELINE_OK);
|
| - FinishPrerolling(end_of_stream);
|
| + void Preroll(int timestamp_ms, PipelineStatus expected) {
|
| + SCOPED_TRACE(base::StringPrintf("Preroll(%d, %d)", timestamp_ms, expected));
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Preroll(
|
| + base::TimeDelta::FromMilliseconds(timestamp_ms),
|
| + event.GetPipelineStatusCB());
|
| + event.RunAndWaitForStatus(expected);
|
| }
|
|
|
| void Pause() {
|
| SCOPED_TRACE("Pause()");
|
| - renderer_->Pause(NewWaitableClosure());
|
| - WaitForClosure();
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Pause(event.GetClosure());
|
| + event.RunAndWait();
|
| }
|
|
|
| void Flush() {
|
| SCOPED_TRACE("Flush()");
|
| - renderer_->Flush(NewWaitableClosure());
|
| - WaitForClosure();
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Flush(event.GetClosure());
|
| + event.RunAndWait();
|
| }
|
|
|
| void Stop() {
|
| SCOPED_TRACE("Stop()");
|
| - renderer_->Stop(NewWaitableClosure());
|
| - WaitForClosure();
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Stop(event.GetClosure());
|
| + event.RunAndWait();
|
| }
|
|
|
| void Shutdown() {
|
| @@ -207,122 +170,113 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| Stop();
|
| }
|
|
|
| - void DeliverNextFrame(bool end_of_stream) {
|
| - base::AutoLock l(lock_);
|
| - DeliverNextFrame_Locked(end_of_stream);
|
| + // Queues a VideoFrame with |next_frame_timestamp_|.
|
| + void QueueNextFrame() {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + DCHECK_LT(next_frame_timestamp_.InMicroseconds(),
|
| + duration_.InMicroseconds());
|
| +
|
| + scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
|
| + VideoFrame::RGB32, kNaturalSize, gfx::Rect(kNaturalSize), kNaturalSize,
|
| + next_frame_timestamp_);
|
| + decode_results_.push_back(std::make_pair(
|
| + VideoDecoder::kOk, frame));
|
| + next_frame_timestamp_ +=
|
| + base::TimeDelta::FromMilliseconds(kFrameDurationInMs);
|
| }
|
|
|
| - // Delivers the next frame to the video renderer. If |end_of_stream|
|
| - // is true then an "end or stream" frame will be returned. Otherwise
|
| - // A frame with |next_frame_timestamp_| will be returned.
|
| - void DeliverNextFrame_Locked(bool end_of_stream) {
|
| - lock_.AssertAcquired();
|
| -
|
| - VideoDecoder::ReadCB read_cb;
|
| - std::swap(read_cb, read_cb_);
|
| -
|
| - DCHECK_LT(next_frame_timestamp_, duration_);
|
| - int timestamp = next_frame_timestamp_;
|
| - next_frame_timestamp_ += kFrameDuration;
|
| -
|
| - // Unlock to deliver the frame to avoid re-entrancy issues.
|
| - base::AutoUnlock ul(lock_);
|
| - if (end_of_stream) {
|
| - read_cb.Run(VideoDecoder::kOk, VideoFrame::CreateEmptyFrame());
|
| - } else {
|
| - read_cb.Run(VideoDecoder::kOk, CreateFrame(timestamp));
|
| - }
|
| + void QueueEndOfStream() {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + decode_results_.push_back(std::make_pair(
|
| + VideoDecoder::kOk, VideoFrame::CreateEmptyFrame()));
|
| }
|
|
|
| - void DecoderError() {
|
| - // Lock+swap to avoid re-entrancy issues.
|
| - VideoDecoder::ReadCB read_cb;
|
| - {
|
| - base::AutoLock l(lock_);
|
| - std::swap(read_cb, read_cb_);
|
| - }
|
| + void QueueDecodeError() {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + scoped_refptr<VideoFrame> null_frame;
|
| + decode_results_.push_back(std::make_pair(
|
| + VideoDecoder::kDecodeError, null_frame));
|
| + }
|
|
|
| - read_cb.Run(VideoDecoder::kDecodeError, NULL);
|
| + void QueueAbortedRead() {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + scoped_refptr<VideoFrame> null_frame;
|
| + decode_results_.push_back(std::make_pair(
|
| + VideoDecoder::kOk, null_frame));
|
| }
|
|
|
| - void AbortRead() {
|
| - // Lock+swap to avoid re-entrancy issues.
|
| - VideoDecoder::ReadCB read_cb;
|
| - {
|
| - base::AutoLock l(lock_);
|
| - std::swap(read_cb, read_cb_);
|
| + void QueuePrerollFrames(int timestamp_ms) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| + next_frame_timestamp_ = base::TimeDelta();
|
| + base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(timestamp_ms);
|
| + while (next_frame_timestamp_ < timestamp) {
|
| + QueueNextFrame();
|
| }
|
|
|
| - read_cb.Run(VideoDecoder::kOk, NULL);
|
| - }
|
| -
|
| - void ExpectCurrentFrame(bool present) {
|
| - scoped_refptr<VideoFrame> frame;
|
| - renderer_->GetCurrentFrame(&frame);
|
| - if (present) {
|
| - EXPECT_TRUE(frame);
|
| - } else {
|
| - EXPECT_FALSE(frame);
|
| + // Queue the frame at |timestamp| plus additional ones for prerolling.
|
| + for (int i = 0; i < limits::kMaxVideoFrames; ++i) {
|
| + QueueNextFrame();
|
| }
|
| - renderer_->PutCurrentFrame(frame);
|
| }
|
|
|
| - void ExpectCurrentTimestamp(int timestamp) {
|
| + scoped_refptr<VideoFrame> GetCurrentFrame() {
|
| scoped_refptr<VideoFrame> frame;
|
| renderer_->GetCurrentFrame(&frame);
|
| - EXPECT_EQ(timestamp, frame->GetTimestamp().InMilliseconds());
|
| renderer_->PutCurrentFrame(frame);
|
| + return frame;
|
| }
|
|
|
| - base::Closure NewWaitableClosure() {
|
| - return base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event_));
|
| + int GetCurrentTimestampInMs() {
|
| + scoped_refptr<VideoFrame> frame = GetCurrentFrame();
|
| + if (!frame)
|
| + return -1;
|
| + return frame->GetTimestamp().InMilliseconds();
|
| }
|
|
|
| - void WaitForClosure() {
|
| - ASSERT_TRUE(event_.TimedWait(timeout_));
|
| - event_.Reset();
|
| + void WaitForError(PipelineStatus expected) {
|
| + SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
|
| + error_event_.RunAndWaitForStatus(expected);
|
| }
|
|
|
| - // Creates a frame with given timestamp.
|
| - scoped_refptr<VideoFrame> CreateFrame(int timestamp) {
|
| - scoped_refptr<VideoFrame> frame =
|
| - VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize,
|
| - gfx::Rect(kNaturalSize), kNaturalSize,
|
| - base::TimeDelta::FromMilliseconds(timestamp));
|
| - return frame;
|
| + void WaitForEnded() {
|
| + SCOPED_TRACE("WaitForEnded()");
|
| + ended_event_.RunAndWait();
|
| }
|
|
|
| - // Advances clock to |timestamp| and waits for the frame at |timestamp| to get
|
| - // rendered using |read_cb_| as the signal that the frame has rendered.
|
| - void RenderFrame(int timestamp) {
|
| - base::AutoLock l(lock_);
|
| - time_ = base::TimeDelta::FromMilliseconds(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();
|
| - }
|
| + void WaitForPendingRead() {
|
| + SCOPED_TRACE("WaitForPendingRead()");
|
| + if (!read_cb_.is_null())
|
| + return;
|
|
|
| - // Advances clock to |timestamp| (which should be the timestamp of the last
|
| - // frame plus duration) and waits for the ended signal before returning.
|
| - void RenderLastFrame(int timestamp) {
|
| - EXPECT_CALL(*this, OnEnded())
|
| - .WillOnce(Invoke(&event_, &base::WaitableEvent::Signal));
|
| - {
|
| - base::AutoLock l(lock_);
|
| - time_ = base::TimeDelta::FromMilliseconds(timestamp);
|
| - }
|
| - CHECK(event_.TimedWait(timeout_)) << "Timed out waiting for ended signal.";
|
| + DCHECK(pending_read_cb_.is_null());
|
| +
|
| + WaitableMessageLoopEvent event;
|
| + pending_read_cb_ = event.GetClosure();
|
| + event.RunAndWait();
|
| +
|
| + DCHECK(!read_cb_.is_null());
|
| + DCHECK(pending_read_cb_.is_null());
|
| }
|
|
|
| - base::WaitableEvent* event() { return &event_; }
|
| - const base::TimeDelta& timeout() { return timeout_; }
|
| + void SatisfyPendingRead() {
|
| + CHECK(!read_cb_.is_null());
|
| + CHECK(!decode_results_.empty());
|
| +
|
| + base::Closure closure = base::Bind(
|
| + read_cb_, decode_results_.front().first,
|
| + decode_results_.front().second);
|
|
|
| - void VerifyNotPrerolling() {
|
| + read_cb_.Reset();
|
| + decode_results_.pop_front();
|
| +
|
| + message_loop_.PostTask(FROM_HERE, closure);
|
| + }
|
| +
|
| + void AdvanceTimeInMs(int time_ms) {
|
| + DCHECK_EQ(&message_loop_, MessageLoop::current());
|
| base::AutoLock l(lock_);
|
| - ASSERT_FALSE(prerolling_);
|
| + time_ += base::TimeDelta::FromMilliseconds(time_ms);
|
| + DCHECK_LE(time_.InMicroseconds(), duration_.InMicroseconds());
|
| }
|
|
|
| protected:
|
| @@ -332,119 +286,80 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| scoped_refptr<MockDemuxerStream> demuxer_stream_;
|
| MockStatisticsCB statistics_cb_object_;
|
|
|
| - // Receives all the buffers that renderer had provided to |decoder_|.
|
| - std::deque<scoped_refptr<VideoFrame> > read_queue_;
|
| -
|
| private:
|
| - // Called by VideoRendererBase for accessing the current time.
|
| base::TimeDelta GetTime() {
|
| base::AutoLock l(lock_);
|
| return time_;
|
| }
|
|
|
| base::TimeDelta GetDuration() {
|
| - return base::TimeDelta::FromMilliseconds(duration_);
|
| + return duration_;
|
| }
|
|
|
| - // Called by VideoRendererBase when it wants a frame.
|
| - void FrameRequested(const VideoDecoder::ReadCB& callback) {
|
| - base::AutoLock l(lock_);
|
| - if (should_queue_read_cb_) {
|
| - CHECK(queued_read_cb_.is_null());
|
| - queued_read_cb_ = callback;
|
| + void FrameRequested(const VideoDecoder::ReadCB& read_cb) {
|
| + // TODO(scherkus): Make VideoRendererBase call on right thread.
|
| + if (&message_loop_ != MessageLoop::current()) {
|
| + message_loop_.PostTask(FROM_HERE, base::Bind(
|
| + &VideoRendererBaseTest::FrameRequested, base::Unretained(this),
|
| + read_cb));
|
| return;
|
| }
|
| - CHECK(read_cb_.is_null());
|
| - read_cb_ = callback;
|
| - cv_.Signal();
|
| - }
|
|
|
| - void FlushRequested(const base::Closure& callback) {
|
| - // Lock+swap to avoid re-entrancy issues.
|
| - VideoDecoder::ReadCB read_cb;
|
| - {
|
| - base::AutoLock l(lock_);
|
| - std::swap(read_cb, read_cb_);
|
| - }
|
| + CHECK(read_cb_.is_null());
|
| + read_cb_ = read_cb;
|
|
|
| - // Abort pending read.
|
| - if (!read_cb.is_null())
|
| - read_cb.Run(VideoDecoder::kOk, NULL);
|
| + // Wake up WaitForPendingRead() if needed.
|
| + if (!pending_read_cb_.is_null())
|
| + base::ResetAndReturn(&pending_read_cb_).Run();
|
|
|
| - callback.Run();
|
| - }
|
| + if (decode_results_.empty())
|
| + return;
|
|
|
| - void OnPrerollComplete(PipelineStatus expected_status,
|
| - PipelineStatus status) {
|
| - base::AutoLock l(lock_);
|
| - EXPECT_EQ(status, expected_status);
|
| - EXPECT_TRUE(prerolling_);
|
| - prerolling_ = false;
|
| - cv_.Signal();
|
| + SatisfyPendingRead();
|
| }
|
|
|
| - void FinishPrerolling(bool end_of_stream) {
|
| - // 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(prerolling_);
|
| - paint_was_called_ = false;
|
| - while (prerolling_) {
|
| - if (!read_cb_.is_null()) {
|
| - DeliverNextFrame_Locked(end_of_stream);
|
| - } else {
|
| - // We want to wait iff we're still prerolling but have no pending read.
|
| - cv_.TimedWait(timeout_);
|
| - CHECK(!prerolling_ || !read_cb_.is_null())
|
| - << "Timed out waiting for preroll or read to occur.";
|
| - }
|
| + void FlushRequested(const base::Closure& callback) {
|
| + // TODO(scherkus): Make VideoRendererBase call on right thread.
|
| + if (&message_loop_ != MessageLoop::current()) {
|
| + message_loop_.PostTask(FROM_HERE, base::Bind(
|
| + &VideoRendererBaseTest::FlushRequested, base::Unretained(this),
|
| + callback));
|
| + return;
|
| }
|
|
|
| - EXPECT_TRUE(read_cb_.is_null());
|
| - WaitForPaint_Locked();
|
| - }
|
| + decode_results_.clear();
|
| + if (!read_cb_.is_null()) {
|
| + QueueAbortedRead();
|
| + SatisfyPendingRead();
|
| + }
|
|
|
| - void Paint() {
|
| - base::AutoLock l(lock_);
|
| - paint_was_called_ = true;
|
| - paint_cv_.Signal();
|
| + message_loop_.PostTask(FROM_HERE, callback);
|
| }
|
|
|
| - void WaitForPaint_Locked() {
|
| - lock_.AssertAcquired();
|
| - if (paint_was_called_)
|
| - return;
|
| - paint_cv_.TimedWait(timeout_);
|
| - EXPECT_TRUE(paint_was_called_);
|
| - }
|
| + MessageLoop message_loop_;
|
|
|
| + // Used to protect |time_|.
|
| base::Lock lock_;
|
| - base::ConditionVariable cv_;
|
| - base::WaitableEvent event_;
|
| - base::TimeDelta timeout_;
|
| + base::TimeDelta time_;
|
|
|
| - // Used in conjunction with |lock_| and |cv_| for satisfying reads.
|
| - bool prerolling_;
|
| + // Used for satisfying reads.
|
| VideoDecoder::ReadCB read_cb_;
|
| - int next_frame_timestamp_;
|
| - int duration_;
|
| - base::TimeDelta time_;
|
| + base::TimeDelta next_frame_timestamp_;
|
| + base::TimeDelta duration_;
|
|
|
| - // Used in conjunction with |lock_| to wait for Paint() calls.
|
| - base::ConditionVariable paint_cv_;
|
| - bool paint_was_called_;
|
| + WaitableMessageLoopEvent error_event_;
|
| + WaitableMessageLoopEvent ended_event_;
|
| + base::Closure pending_read_cb_;
|
|
|
| - // Holding queue for Read callbacks for exercising delayed demux/decode.
|
| - bool should_queue_read_cb_;
|
| - VideoDecoder::ReadCB queued_read_cb_;
|
| + std::deque<std::pair<
|
| + VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(VideoRendererBaseTest);
|
| };
|
|
|
| TEST_F(VideoRendererBaseTest, Initialize) {
|
| Initialize();
|
| - ExpectCurrentTimestamp(0);
|
| + EXPECT_EQ(0, GetCurrentTimestampInMs());
|
| Shutdown();
|
| }
|
|
|
| @@ -458,68 +373,61 @@ TEST_F(VideoRendererBaseTest, EndOfStream_DefaultFrameDuration) {
|
| Initialize();
|
| Play();
|
|
|
| - // Finish rendering up to the next-to-last frame.
|
| - int timestamp = kFrameDuration;
|
| - for (int i = 1; i < limits::kMaxVideoFrames; ++i) {
|
| - RenderFrame(timestamp);
|
| - timestamp += kFrameDuration;
|
| - }
|
| -
|
| - // Deliver the end of stream frame.
|
| - DeliverNextFrame(true);
|
| -
|
| // Verify that the ended callback fires when the default last frame duration
|
| // has elapsed.
|
| - int end_timestamp =
|
| - timestamp + VideoRendererBase::kMaxLastFrameDuration().InMilliseconds();
|
| - EXPECT_LT(end_timestamp, kVideoDuration);
|
| - RenderLastFrame(end_timestamp);
|
| + int end_timestamp = kFrameDurationInMs * limits::kMaxVideoFrames +
|
| + VideoRendererBase::kMaxLastFrameDuration().InMilliseconds();
|
| + EXPECT_LT(end_timestamp, kVideoDurationInMs);
|
| +
|
| + QueueEndOfStream();
|
| + AdvanceTimeInMs(end_timestamp);
|
| + WaitForEnded();
|
|
|
| Shutdown();
|
| }
|
|
|
| TEST_F(VideoRendererBaseTest, EndOfStream_ClipDuration) {
|
| - int duration = kVideoDuration + kFrameDuration / 2;
|
| - Initialize(duration);
|
| + int duration = kVideoDurationInMs + kFrameDurationInMs / 2;
|
| + InitializeWithDuration(duration);
|
| Play();
|
|
|
| // Render all frames except for the last |limits::kMaxVideoFrames| frames
|
| // and deliver all the frames between the start and |duration|. The preroll
|
| // inside Initialize() makes this a little confusing, but |timestamp| is
|
| - // the current render time and DeliverNextFrame() delivers a frame with a
|
| - // timestamp that is |timestamp| + limits::kMaxVideoFrames * kFrameDuration.
|
| - int timestamp = kFrameDuration;
|
| - int end_timestamp = duration - limits::kMaxVideoFrames * kFrameDuration;
|
| - for (; timestamp < end_timestamp; timestamp += kFrameDuration) {
|
| - RenderFrame(timestamp);
|
| - DeliverNextFrame(false);
|
| + // the current render time and QueueNextFrame() delivers a frame with a
|
| + // timestamp that is |timestamp| + limits::kMaxVideoFrames *
|
| + // kFrameDurationInMs.
|
| + int timestamp = kFrameDurationInMs;
|
| + int end_timestamp = duration - limits::kMaxVideoFrames * kFrameDurationInMs;
|
| + for (; timestamp < end_timestamp; timestamp += kFrameDurationInMs) {
|
| + QueueNextFrame();
|
| }
|
|
|
| - // Render the next frame so that a Read() will get requested.
|
| - RenderFrame(timestamp);
|
| -
|
| - // Deliver the end of stream frame and wait for the last frame to be rendered.
|
| - DeliverNextFrame(true);
|
| - RenderLastFrame(duration);
|
| + // Queue the end of stream frame and wait for the last frame to be rendered.
|
| + QueueEndOfStream();
|
| + AdvanceTimeInMs(duration);
|
| + WaitForEnded();
|
|
|
| Shutdown();
|
| }
|
|
|
| -TEST_F(VideoRendererBaseTest, DecoderError) {
|
| +TEST_F(VideoRendererBaseTest, DecodeError_Playing) {
|
| Initialize();
|
| Play();
|
| - RenderFrame(kFrameDuration);
|
| - EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE));
|
| - DecoderError();
|
| +
|
| + QueueDecodeError();
|
| + AdvanceTimeInMs(kVideoDurationInMs);
|
| + WaitForError(PIPELINE_ERROR_DECODE);
|
| Shutdown();
|
| }
|
|
|
| -TEST_F(VideoRendererBaseTest, DecoderErrorDuringPreroll) {
|
| +TEST_F(VideoRendererBaseTest, DecodeError_DuringPreroll) {
|
| Initialize();
|
| Pause();
|
| Flush();
|
| - StartPrerolling(kFrameDuration * 6, PIPELINE_ERROR_DECODE);
|
| - DecoderError();
|
| +
|
| + QueueDecodeError();
|
| + Preroll(kFrameDurationInMs * 6, PIPELINE_ERROR_DECODE);
|
| Shutdown();
|
| }
|
|
|
| @@ -527,8 +435,10 @@ TEST_F(VideoRendererBaseTest, Preroll_Exact) {
|
| Initialize();
|
| Pause();
|
| Flush();
|
| - Preroll(kFrameDuration * 6);
|
| - ExpectCurrentTimestamp(kFrameDuration * 6);
|
| + QueuePrerollFrames(kFrameDurationInMs * 6);
|
| +
|
| + Preroll(kFrameDurationInMs * 6, PIPELINE_OK);
|
| + EXPECT_EQ(kFrameDurationInMs * 6, GetCurrentTimestampInMs());
|
| Shutdown();
|
| }
|
|
|
| @@ -536,8 +446,10 @@ TEST_F(VideoRendererBaseTest, Preroll_RightBefore) {
|
| Initialize();
|
| Pause();
|
| Flush();
|
| - Preroll(kFrameDuration * 6 - 1);
|
| - ExpectCurrentTimestamp(kFrameDuration * 5);
|
| + QueuePrerollFrames(kFrameDurationInMs * 6);
|
| +
|
| + Preroll(kFrameDurationInMs * 6 - 1, PIPELINE_OK);
|
| + EXPECT_EQ(kFrameDurationInMs * 5, GetCurrentTimestampInMs());
|
| Shutdown();
|
| }
|
|
|
| @@ -545,21 +457,23 @@ TEST_F(VideoRendererBaseTest, Preroll_RightAfter) {
|
| Initialize();
|
| Pause();
|
| Flush();
|
| - Preroll(kFrameDuration * 6 + 1);
|
| - ExpectCurrentTimestamp(kFrameDuration * 6);
|
| + QueuePrerollFrames(kFrameDurationInMs * 6);
|
| +
|
| + Preroll(kFrameDurationInMs * 6 + 1, PIPELINE_OK);
|
| + EXPECT_EQ(kFrameDurationInMs * 6, GetCurrentTimestampInMs());
|
| Shutdown();
|
| }
|
|
|
| TEST_F(VideoRendererBaseTest, GetCurrentFrame_Initialized) {
|
| Initialize();
|
| - ExpectCurrentFrame(true); // Due to prerolling.
|
| + EXPECT_TRUE(GetCurrentFrame()); // Due to prerolling.
|
| Shutdown();
|
| }
|
|
|
| TEST_F(VideoRendererBaseTest, GetCurrentFrame_Playing) {
|
| Initialize();
|
| Play();
|
| - ExpectCurrentFrame(true);
|
| + EXPECT_TRUE(GetCurrentFrame());
|
| Shutdown();
|
| }
|
|
|
| @@ -567,7 +481,7 @@ TEST_F(VideoRendererBaseTest, GetCurrentFrame_Paused) {
|
| Initialize();
|
| Play();
|
| Pause();
|
| - ExpectCurrentFrame(true);
|
| + EXPECT_TRUE(GetCurrentFrame());
|
| Shutdown();
|
| }
|
|
|
| @@ -576,7 +490,7 @@ TEST_F(VideoRendererBaseTest, GetCurrentFrame_Flushed) {
|
| Play();
|
| Pause();
|
| Flush();
|
| - ExpectCurrentFrame(false);
|
| + EXPECT_FALSE(GetCurrentFrame());
|
| Shutdown();
|
| }
|
|
|
| @@ -593,14 +507,13 @@ TEST_F(VideoRendererBaseTest, MAYBE_GetCurrentFrame_EndOfStream) {
|
| Flush();
|
|
|
| // Preroll only end of stream frames.
|
| - Preroll(kEndOfStream);
|
| - ExpectCurrentFrame(false);
|
| + QueueEndOfStream();
|
| + Preroll(0, PIPELINE_OK);
|
| + EXPECT_FALSE(GetCurrentFrame());
|
|
|
| // Start playing, we should immediately get notified of end of stream.
|
| - EXPECT_CALL(*this, OnEnded())
|
| - .WillOnce(Invoke(event(), &base::WaitableEvent::Signal));
|
| Play();
|
| - CHECK(event()->TimedWait(timeout())) << "Timed out waiting for ended signal.";
|
| + WaitForEnded();
|
|
|
| Shutdown();
|
| }
|
| @@ -608,14 +521,14 @@ TEST_F(VideoRendererBaseTest, MAYBE_GetCurrentFrame_EndOfStream) {
|
| TEST_F(VideoRendererBaseTest, GetCurrentFrame_Shutdown) {
|
| Initialize();
|
| Shutdown();
|
| - ExpectCurrentFrame(false);
|
| + EXPECT_FALSE(GetCurrentFrame());
|
| }
|
|
|
| // Stop() is called immediately during an error.
|
| TEST_F(VideoRendererBaseTest, GetCurrentFrame_Error) {
|
| Initialize();
|
| Stop();
|
| - ExpectCurrentFrame(false);
|
| + EXPECT_FALSE(GetCurrentFrame());
|
| }
|
|
|
| // Verify that shutdown can only proceed after we return the current frame.
|
| @@ -631,11 +544,12 @@ TEST_F(VideoRendererBaseTest, Shutdown_DuringPaint) {
|
| Pause();
|
|
|
| // Start flushing -- it won't complete until we return the frame.
|
| - renderer_->Flush(NewWaitableClosure());
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Flush(event.GetClosure());
|
|
|
| // Return the frame and wait.
|
| renderer_->PutCurrentFrame(frame);
|
| - WaitForClosure();
|
| + event.RunAndWait();
|
|
|
| Stop();
|
| }
|
| @@ -643,28 +557,37 @@ TEST_F(VideoRendererBaseTest, Shutdown_DuringPaint) {
|
| // Verify that a late decoder response doesn't break invariants in the renderer.
|
| TEST_F(VideoRendererBaseTest, StopDuringOutstandingRead) {
|
| Initialize();
|
| - Pause();
|
| - Flush();
|
| - QueueReadCB();
|
| - StartPrerolling(kFrameDuration * 6, PIPELINE_OK); // Force-decode some more.
|
| - renderer_->Stop(NewWaitableClosure());
|
| - SatisfyQueuedReadCB();
|
| - WaitForClosure(); // Finish the Stop().
|
| + Play();
|
| +
|
| + // Advance time a bit to trigger a Read().
|
| + AdvanceTimeInMs(kFrameDurationInMs);
|
| + WaitForPendingRead();
|
| +
|
| + WaitableMessageLoopEvent event;
|
| + renderer_->Stop(event.GetClosure());
|
| +
|
| + QueueEndOfStream();
|
| + SatisfyPendingRead();
|
| +
|
| + event.RunAndWait();
|
| }
|
|
|
| TEST_F(VideoRendererBaseTest, AbortPendingRead_Playing) {
|
| Initialize();
|
| Play();
|
|
|
| - // Render a frame to trigger a Read().
|
| - RenderFrame(kFrameDuration);
|
| + // Advance time a bit to trigger a Read().
|
| + AdvanceTimeInMs(kFrameDurationInMs);
|
| + WaitForPendingRead();
|
|
|
| - AbortRead();
|
| + QueueAbortedRead();
|
| + SatisfyPendingRead();
|
|
|
| Pause();
|
| Flush();
|
| - Preroll(kFrameDuration * 6);
|
| - ExpectCurrentTimestamp(kFrameDuration * 6);
|
| + QueuePrerollFrames(kFrameDurationInMs * 6);
|
| + Preroll(kFrameDurationInMs * 6, PIPELINE_OK);
|
| + EXPECT_EQ(kFrameDurationInMs * 6, GetCurrentTimestampInMs());
|
| Shutdown();
|
| }
|
|
|
| @@ -672,8 +595,9 @@ TEST_F(VideoRendererBaseTest, AbortPendingRead_Flush) {
|
| Initialize();
|
| Play();
|
|
|
| - // Render a frame to trigger a Read().
|
| - RenderFrame(kFrameDuration);
|
| + // Advance time a bit to trigger a Read().
|
| + AdvanceTimeInMs(kFrameDurationInMs);
|
| + WaitForPendingRead();
|
|
|
| Pause();
|
| Flush();
|
| @@ -684,9 +608,9 @@ TEST_F(VideoRendererBaseTest, AbortPendingRead_Preroll) {
|
| Initialize();
|
| Pause();
|
| Flush();
|
| - StartPrerolling(kFrameDuration * 6, PIPELINE_OK);
|
| - AbortRead();
|
| - VerifyNotPrerolling();
|
| +
|
| + QueueAbortedRead();
|
| + Preroll(kFrameDurationInMs * 6, PIPELINE_OK);
|
| Shutdown();
|
| }
|
|
|
| @@ -696,6 +620,8 @@ TEST_F(VideoRendererBaseTest, VideoDecoder_InitFailure) {
|
| EXPECT_CALL(*decoder_, Initialize(_, _, _))
|
| .WillOnce(RunCallback<1>(PIPELINE_ERROR_DECODE));
|
| InitializeRenderer(PIPELINE_ERROR_DECODE);
|
| +
|
| + Stop();
|
| }
|
|
|
| } // namespace media
|
|
|