blob: cf5ee0a3d45181c971f0614d5e1fa6a38bdf7c0c [file] [log] [blame]
// Copyright 2014 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/message_loop/message_loop.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/base/test_helpers.h"
#include "media/base/video_frame.h"
#include "media/filters/video_frame_scheduler_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
using testing::_;
// NOTE: millisecond-level resolution is used for times as real delayed tasks
// are posted. Don't use large values if you want to keep tests running fast.
class VideoFrameSchedulerImplTest : public testing::Test {
public:
VideoFrameSchedulerImplTest()
: scheduler_(message_loop_.message_loop_proxy(),
base::Bind(&VideoFrameSchedulerImplTest::OnDisplay,
base::Unretained(this))),
tick_clock_(new base::SimpleTestTickClock()) {
scheduler_.SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_));
}
virtual ~VideoFrameSchedulerImplTest() {}
MOCK_METHOD1(OnDisplay, void(const scoped_refptr<VideoFrame>&));
MOCK_METHOD2(OnFrameDone,
void(const scoped_refptr<VideoFrame>&,
VideoFrameScheduler::Reason));
void Schedule(const scoped_refptr<VideoFrame>& frame, int64 target_ms) {
scheduler_.ScheduleVideoFrame(
frame,
base::TimeTicks() + base::TimeDelta::FromMilliseconds(target_ms),
base::Bind(&VideoFrameSchedulerImplTest::OnFrameDone,
base::Unretained(this)));
}
void RunUntilTimeHasElapsed(int64 ms) {
WaitableMessageLoopEvent waiter;
message_loop_.PostDelayedTask(
FROM_HERE, waiter.GetClosure(), base::TimeDelta::FromMilliseconds(ms));
waiter.RunAndWait();
}
void AdvanceTime(int64 ms) {
tick_clock_->Advance(base::TimeDelta::FromMilliseconds(ms));
}
void Reset() {
scheduler_.Reset();
}
private:
base::MessageLoop message_loop_;
VideoFrameSchedulerImpl scheduler_;
base::SimpleTestTickClock* tick_clock_; // Owned by |scheduler_|.
DISALLOW_COPY_AND_ASSIGN(VideoFrameSchedulerImplTest);
};
TEST_F(VideoFrameSchedulerImplTest, ImmediateDisplay) {
scoped_refptr<VideoFrame> frame =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(frame, 0);
EXPECT_CALL(*this, OnDisplay(frame));
EXPECT_CALL(*this, OnFrameDone(frame, VideoFrameScheduler::DISPLAYED));
RunUntilTimeHasElapsed(0);
}
TEST_F(VideoFrameSchedulerImplTest, EventualDisplay) {
scoped_refptr<VideoFrame> frame =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(frame, 10);
// Nothing should happen.
RunUntilTimeHasElapsed(10);
// Now we should get the frame.
EXPECT_CALL(*this, OnDisplay(frame));
EXPECT_CALL(*this, OnFrameDone(frame, VideoFrameScheduler::DISPLAYED));
AdvanceTime(10);
RunUntilTimeHasElapsed(10);
}
TEST_F(VideoFrameSchedulerImplTest, DroppedFrame) {
scoped_refptr<VideoFrame> dropped =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
scoped_refptr<VideoFrame> displayed =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(dropped, 10);
Schedule(displayed, 20);
// The frame past its deadline will get dropped.
EXPECT_CALL(*this, OnDisplay(displayed));
EXPECT_CALL(*this, OnFrameDone(dropped, VideoFrameScheduler::DROPPED));
EXPECT_CALL(*this, OnFrameDone(displayed, VideoFrameScheduler::DISPLAYED));
AdvanceTime(20);
RunUntilTimeHasElapsed(20);
}
TEST_F(VideoFrameSchedulerImplTest, SingleFrameLate) {
scoped_refptr<VideoFrame> frame =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(frame, 10);
// Despite frame being late it should still get displayed as it's the only
// one.
EXPECT_CALL(*this, OnDisplay(frame));
EXPECT_CALL(*this, OnFrameDone(frame, VideoFrameScheduler::DISPLAYED));
AdvanceTime(20);
RunUntilTimeHasElapsed(20);
}
TEST_F(VideoFrameSchedulerImplTest, ManyFramesLate) {
scoped_refptr<VideoFrame> dropped =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
scoped_refptr<VideoFrame> displayed =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(dropped, 10);
Schedule(displayed, 20);
// Despite both being late, the scheduler should always displays the latest
// expired frame.
EXPECT_CALL(*this, OnDisplay(displayed));
EXPECT_CALL(*this, OnFrameDone(dropped, VideoFrameScheduler::DROPPED));
EXPECT_CALL(*this, OnFrameDone(displayed, VideoFrameScheduler::DISPLAYED));
AdvanceTime(30);
RunUntilTimeHasElapsed(30);
}
TEST_F(VideoFrameSchedulerImplTest, Reset) {
scoped_refptr<VideoFrame> frame =
VideoFrame::CreateBlackFrame(gfx::Size(8, 8));
Schedule(frame, 10);
// Despite being on time, frame callback isn't run.
EXPECT_CALL(*this, OnFrameDone(_, _)).Times(0);
AdvanceTime(10);
Reset();
RunUntilTimeHasElapsed(10);
}
} // namespace media