| 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 d08670ebf347b749becafe58194f0e3d7e9ae202..2c3a54651f7ae8c60d2d930a5f03004e667d137d 100644
|
| --- a/media/filters/video_renderer_base_unittest.cc
|
| +++ b/media/filters/video_renderer_base_unittest.cc
|
| @@ -4,7 +4,6 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| -#include "base/format_macros.h"
|
| #include "base/stl_util.h"
|
| #include "base/stringprintf.h"
|
| #include "base/synchronization/condition_variable.h"
|
| @@ -30,9 +29,9 @@ using ::testing::StrictMock;
|
|
|
| namespace media {
|
|
|
| -static const int64 kFrameDuration = 10;
|
| -static const int64 kVideoDuration = kFrameDuration * 100;
|
| -static const int64 kEndOfStream = kint64min;
|
| +static const int kFrameDuration = 10;
|
| +static const int kVideoDuration = kFrameDuration * 100;
|
| +static const int kEndOfStream = -1;
|
| static const gfx::Size kNaturalSize(16u, 16u);
|
|
|
| class VideoRendererBaseTest : public ::testing::Test {
|
| @@ -43,6 +42,7 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| 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) {
|
| @@ -52,8 +52,6 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| true);
|
|
|
| // We expect these to be called but we don't care how/when.
|
| - EXPECT_CALL(*decoder_, natural_size())
|
| - .WillRepeatedly(ReturnRef(kNaturalSize));
|
| EXPECT_CALL(*decoder_, Stop(_))
|
| .WillRepeatedly(RunClosure());
|
| EXPECT_CALL(statistics_cb_object_, OnStatistics(_))
|
| @@ -82,6 +80,12 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| MOCK_METHOD1(OnError, void(PipelineStatus));
|
|
|
| void Initialize() {
|
| + Initialize(kVideoDuration);
|
| + }
|
| +
|
| + void Initialize(int duration) {
|
| + duration_ = duration;
|
| +
|
| // TODO(scherkus): really, really, really need to inject a thread into
|
| // VideoRendererBase... it makes mocking much harder.
|
|
|
| @@ -135,11 +139,12 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| read_cb.Run(VideoDecoder::kOk, VideoFrame::CreateEmptyFrame());
|
| }
|
|
|
| - void StartPrerolling(int64 timestamp, PipelineStatus expected_status) {
|
| + void StartPrerolling(int timestamp, PipelineStatus expected_status) {
|
| EXPECT_FALSE(prerolling_);
|
|
|
| + next_frame_timestamp_ = 0;
|
| prerolling_ = true;
|
| - renderer_->Preroll(base::TimeDelta::FromMicroseconds(timestamp),
|
| + renderer_->Preroll(base::TimeDelta::FromMilliseconds(timestamp),
|
| base::Bind(&VideoRendererBaseTest::OnPrerollComplete,
|
| base::Unretained(this), expected_status));
|
| }
|
| @@ -153,10 +158,12 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| // Preroll to the given timestamp.
|
| //
|
| // Use |kEndOfStream| to preroll end of stream frames.
|
| - void Preroll(int64 timestamp) {
|
| - SCOPED_TRACE(base::StringPrintf("Preroll(%" PRId64 ")", timestamp));
|
| - StartPrerolling(timestamp, PIPELINE_OK);
|
| - FinishPrerolling(timestamp);
|
| + 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 Pause() {
|
| @@ -183,18 +190,27 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| Stop();
|
| }
|
|
|
| - // Delivers a frame with the given timestamp to the video renderer.
|
| - //
|
| - // Use |kEndOfStream| to pass in an end of stream frame.
|
| - void DeliverFrame(int64 timestamp) {
|
| - // Lock+swap to avoid re-entrancy issues.
|
| + void DeliverNextFrame(bool end_of_stream) {
|
| + base::AutoLock l(lock_);
|
| + DeliverNextFrame_Locked(end_of_stream);
|
| + }
|
| +
|
| + // 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;
|
| - {
|
| - base::AutoLock l(lock_);
|
| - std::swap(read_cb, read_cb_);
|
| - }
|
| + std::swap(read_cb, read_cb_);
|
| +
|
| + DCHECK_LT(next_frame_timestamp_, duration_);
|
| + int timestamp = next_frame_timestamp_;
|
| + next_frame_timestamp_ += kFrameDuration;
|
|
|
| - if (timestamp == kEndOfStream) {
|
| + // 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));
|
| @@ -234,10 +250,10 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| renderer_->PutCurrentFrame(frame);
|
| }
|
|
|
| - void ExpectCurrentTimestamp(int64 timestamp) {
|
| + void ExpectCurrentTimestamp(int timestamp) {
|
| scoped_refptr<VideoFrame> frame;
|
| renderer_->GetCurrentFrame(&frame);
|
| - EXPECT_EQ(timestamp, frame->GetTimestamp().InMicroseconds());
|
| + EXPECT_EQ(timestamp, frame->GetTimestamp().InMilliseconds());
|
| renderer_->PutCurrentFrame(frame);
|
| }
|
|
|
| @@ -251,18 +267,18 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| }
|
|
|
| // Creates a frame with given timestamp.
|
| - scoped_refptr<VideoFrame> CreateFrame(int64 timestamp) {
|
| + scoped_refptr<VideoFrame> CreateFrame(int timestamp) {
|
| scoped_refptr<VideoFrame> frame =
|
| VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize, kNaturalSize,
|
| - base::TimeDelta::FromMicroseconds(timestamp));
|
| + base::TimeDelta::FromMilliseconds(timestamp));
|
| return frame;
|
| }
|
|
|
| // 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(int64 timestamp) {
|
| + void RenderFrame(int timestamp) {
|
| base::AutoLock l(lock_);
|
| - time_ = base::TimeDelta::FromMicroseconds(timestamp);
|
| + time_ = base::TimeDelta::FromMilliseconds(timestamp);
|
| paint_was_called_ = false;
|
| if (read_cb_.is_null()) {
|
| cv_.TimedWait(timeout_);
|
| @@ -273,12 +289,12 @@ class VideoRendererBaseTest : public ::testing::Test {
|
|
|
| // 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(int64 timestamp) {
|
| + void RenderLastFrame(int timestamp) {
|
| EXPECT_CALL(*this, OnEnded())
|
| .WillOnce(Invoke(&event_, &base::WaitableEvent::Signal));
|
| {
|
| base::AutoLock l(lock_);
|
| - time_ = base::TimeDelta::FromMicroseconds(timestamp);
|
| + time_ = base::TimeDelta::FromMilliseconds(timestamp);
|
| }
|
| CHECK(event_.TimedWait(timeout_)) << "Timed out waiting for ended signal.";
|
| }
|
| @@ -308,7 +324,7 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| }
|
|
|
| base::TimeDelta GetDuration() {
|
| - return base::TimeDelta::FromMicroseconds(kVideoDuration);
|
| + return base::TimeDelta::FromMilliseconds(duration_);
|
| }
|
|
|
| // Called by VideoRendererBase when it wants a frame.
|
| @@ -348,28 +364,16 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| cv_.Signal();
|
| }
|
|
|
| - void FinishPrerolling(int64 timestamp) {
|
| + 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;
|
| - int i = 0;
|
| while (prerolling_) {
|
| if (!read_cb_.is_null()) {
|
| - VideoDecoder::ReadCB read_cb;
|
| - std::swap(read_cb, read_cb_);
|
| -
|
| - // Unlock to deliver the frame to avoid re-entrancy issues.
|
| - base::AutoUnlock ul(lock_);
|
| - if (timestamp == kEndOfStream) {
|
| - read_cb.Run(VideoDecoder::kOk, VideoFrame::CreateEmptyFrame());
|
| - } else {
|
| - read_cb.Run(VideoDecoder::kOk,
|
| - CreateFrame(i * kFrameDuration));
|
| - i++;
|
| - }
|
| + DeliverNextFrame_Locked(end_of_stream);
|
| } else {
|
| // We want to wait iff we're still prerolling but have no pending read.
|
| cv_.TimedWait(timeout_);
|
| @@ -404,6 +408,8 @@ class VideoRendererBaseTest : public ::testing::Test {
|
| // Used in conjunction with |lock_| and |cv_| for satisfying reads.
|
| bool prerolling_;
|
| VideoDecoder::ReadCB read_cb_;
|
| + int next_frame_timestamp_;
|
| + int duration_;
|
| base::TimeDelta time_;
|
|
|
| // Used in conjunction with |lock_| to wait for Paint() calls.
|
| @@ -429,18 +435,53 @@ TEST_F(VideoRendererBaseTest, Play) {
|
| Shutdown();
|
| }
|
|
|
| -TEST_F(VideoRendererBaseTest, EndOfStream) {
|
| +TEST_F(VideoRendererBaseTest, EndOfStream_DefaultFrameDuration) {
|
| Initialize();
|
| Play();
|
|
|
| // Finish rendering up to the next-to-last frame.
|
| - for (int i = 1; i < limits::kMaxVideoFrames; ++i)
|
| - RenderFrame(kFrameDuration * i);
|
| + 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);
|
| +
|
| + Shutdown();
|
| +}
|
| +
|
| +TEST_F(VideoRendererBaseTest, EndOfStream_ClipDuration) {
|
| + int duration = kVideoDuration + kFrameDuration / 2;
|
| + Initialize(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);
|
| + }
|
| +
|
| + // Render the next frame so that a Read() will get requested.
|
| + RenderFrame(timestamp);
|
|
|
| - // Finish rendering the last frame, we should NOT get a new frame but instead
|
| - // get notified of end of stream.
|
| - DeliverFrame(kEndOfStream);
|
| - RenderLastFrame(kVideoDuration);
|
| + // Deliver the end of stream frame and wait for the last frame to be rendered.
|
| + DeliverNextFrame(true);
|
| + RenderLastFrame(duration);
|
|
|
| Shutdown();
|
| }
|
|
|