blob: 2b4c5e15e8ea273d058e47bb5753f9a0804ade96 [file] [log] [blame]
dalecurtis6523d602015-04-29 08:31:011// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakj6aaed6a2016-04-26 01:25:445#include <memory>
6
dalecurtis6523d602015-04-29 08:31:017#include "base/bind.h"
8#include "base/callback_helpers.h"
avi1323b9c22015-12-23 06:22:369#include "base/macros.h"
Alexander Timin4f9c35c2018-11-01 20:15:2010#include "base/message_loop/message_loop.h"
dalecurtis6523d602015-04-29 08:31:0111#include "base/test/simple_test_tick_clock.h"
servolk6cf8ecb2016-09-21 18:48:1312#include "media/base/gmock_callback_support.h"
dalecurtis6523d602015-04-29 08:31:0113#include "media/base/null_video_sink.h"
14#include "media/base/test_helpers.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using testing::_;
19using testing::DoAll;
20using testing::Return;
21
22namespace media {
23
dalecurtis6523d602015-04-29 08:31:0124class NullVideoSinkTest : public testing::Test,
25 public VideoRendererSink::RenderCallback {
26 public:
27 NullVideoSinkTest() {
28 // Never use null TimeTicks since they have special connotations.
29 tick_clock_.Advance(base::TimeDelta::FromMicroseconds(12345));
30 }
Chris Watkins2de69292017-12-01 03:08:0131 ~NullVideoSinkTest() override = default;
dalecurtis6523d602015-04-29 08:31:0132
danakj6aaed6a2016-04-26 01:25:4433 std::unique_ptr<NullVideoSink> ConstructSink(bool clockless,
34 base::TimeDelta interval) {
35 std::unique_ptr<NullVideoSink> new_sink(new NullVideoSink(
dalecurtis6523d602015-04-29 08:31:0136 clockless, interval,
37 base::Bind(&NullVideoSinkTest::FrameReceived, base::Unretained(this)),
38 message_loop_.task_runner()));
39 new_sink->set_tick_clock_for_testing(&tick_clock_);
40 return new_sink;
41 }
42
43 scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) {
44 const gfx::Size natural_size(8, 8);
Miguel Casas9e7766022018-01-08 16:13:1345 return VideoFrame::CreateFrame(PIXEL_FORMAT_I420, natural_size,
dalecurtis6523d602015-04-29 08:31:0146 gfx::Rect(natural_size), natural_size,
47 timestamp);
48 }
49
50 // VideoRendererSink::RenderCallback implementation.
dalecurtis3e8bda62015-05-05 07:23:1551 MOCK_METHOD3(Render,
52 scoped_refptr<VideoFrame>(base::TimeTicks,
53 base::TimeTicks,
54 bool));
dalecurtis6523d602015-04-29 08:31:0155 MOCK_METHOD0(OnFrameDropped, void());
56
57 MOCK_METHOD1(FrameReceived, void(const scoped_refptr<VideoFrame>&));
58
59 protected:
60 base::MessageLoop message_loop_;
61 base::SimpleTestTickClock tick_clock_;
62
63 DISALLOW_COPY_AND_ASSIGN(NullVideoSinkTest);
64};
65
66TEST_F(NullVideoSinkTest, BasicFunctionality) {
67 const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(25);
68
danakj6aaed6a2016-04-26 01:25:4469 std::unique_ptr<NullVideoSink> sink = ConstructSink(false, kInterval);
dalecurtis6523d602015-04-29 08:31:0170 scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta());
71
dalecurtis6523d602015-04-29 08:31:0172 {
73 SCOPED_TRACE("Waiting for sink startup.");
74 sink->Start(this);
75 const base::TimeTicks current_time = tick_clock_.NowTicks();
76 const base::TimeTicks current_interval_end = current_time + kInterval;
dalecurtis3e8bda62015-05-05 07:23:1577 EXPECT_CALL(*this, Render(current_time, current_interval_end, false))
dalecurtis6523d602015-04-29 08:31:0178 .WillOnce(Return(test_frame));
79 WaitableMessageLoopEvent event;
80 EXPECT_CALL(*this, FrameReceived(test_frame))
81 .WillOnce(RunClosure(event.GetClosure()));
82 event.RunAndWait();
83 }
84
dalecurtis3e8bda62015-05-05 07:23:1585 // Verify that toggling background rendering mode issues the right bit to
86 // each Render() call.
87 sink->set_background_render(true);
88
dalecurtis6523d602015-04-29 08:31:0189 // A second call returning the same frame should not result in a new call to
90 // FrameReceived().
91 {
92 SCOPED_TRACE("Waiting for second render call.");
93 WaitableMessageLoopEvent event;
dalecurtisc7aeeb22016-04-26 22:52:4394 scoped_refptr<VideoFrame> test_frame_2 = CreateFrame(kInterval);
dalecurtis3e8bda62015-05-05 07:23:1595 EXPECT_CALL(*this, Render(_, _, true))
dalecurtis6523d602015-04-29 08:31:0196 .WillOnce(Return(test_frame))
dalecurtisc7aeeb22016-04-26 22:52:4397 .WillOnce(Return(test_frame_2));
dalecurtis6523d602015-04-29 08:31:0198 EXPECT_CALL(*this, FrameReceived(test_frame)).Times(0);
dalecurtisc7aeeb22016-04-26 22:52:4399 EXPECT_CALL(*this, FrameReceived(test_frame_2))
dalecurtis6523d602015-04-29 08:31:01100 .WillOnce(RunClosure(event.GetClosure()));
101 event.RunAndWait();
102 }
103
104 {
105 SCOPED_TRACE("Waiting for stop event.");
106 WaitableMessageLoopEvent event;
107 sink->set_stop_cb(event.GetClosure());
108 sink->Stop();
109 event.RunAndWait();
110 }
dalecurtis046faf62016-06-02 18:14:28111
112 // The sink shouldn't have to be started to use the paint method.
113 EXPECT_CALL(*this, FrameReceived(test_frame));
tguilbert3a03dae2016-08-12 21:18:22114 sink->PaintSingleFrame(test_frame, false);
dalecurtis6523d602015-04-29 08:31:01115}
116
117TEST_F(NullVideoSinkTest, ClocklessFunctionality) {
118 // Construct the sink with a huge interval, it should still complete quickly.
119 const base::TimeDelta interval = base::TimeDelta::FromSeconds(10);
danakj6aaed6a2016-04-26 01:25:44120 std::unique_ptr<NullVideoSink> sink = ConstructSink(true, interval);
dalecurtis6523d602015-04-29 08:31:01121
122 scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta());
dalecurtisc7aeeb22016-04-26 22:52:43123 scoped_refptr<VideoFrame> test_frame_2 = CreateFrame(interval);
dalecurtis6523d602015-04-29 08:31:01124 sink->Start(this);
125
126 EXPECT_CALL(*this, FrameReceived(test_frame)).Times(1);
dalecurtisc7aeeb22016-04-26 22:52:43127 EXPECT_CALL(*this, FrameReceived(test_frame_2)).Times(1);
dalecurtis6523d602015-04-29 08:31:01128
129 const int kTestRuns = 6;
130 const base::TimeTicks now = base::TimeTicks::Now();
131 const base::TimeTicks current_time = tick_clock_.NowTicks();
132
dalecurtis754b1b72015-05-05 01:50:29133 SCOPED_TRACE("Waiting for multiple render callbacks");
134 WaitableMessageLoopEvent event;
dalecurtis6523d602015-04-29 08:31:01135 for (int i = 0; i < kTestRuns; ++i) {
136 if (i < kTestRuns - 1) {
137 EXPECT_CALL(*this, Render(current_time + i * interval,
dalecurtis3e8bda62015-05-05 07:23:15138 current_time + (i + 1) * interval, false))
dalecurtis6523d602015-04-29 08:31:01139 .WillOnce(Return(test_frame));
140 } else {
141 EXPECT_CALL(*this, Render(current_time + i * interval,
dalecurtis3e8bda62015-05-05 07:23:15142 current_time + (i + 1) * interval, false))
dalecurtisc7aeeb22016-04-26 22:52:43143 .WillOnce(
144 DoAll(RunClosure(event.GetClosure()), Return(test_frame_2)));
dalecurtis6523d602015-04-29 08:31:01145 }
146 }
dalecurtis754b1b72015-05-05 01:50:29147 event.RunAndWait();
dalecurtis6523d602015-04-29 08:31:01148 ASSERT_LT(base::TimeTicks::Now() - now, kTestRuns * interval);
149 sink->Stop();
150}
151
dalecurtis3e8bda62015-05-05 07:23:15152} // namespace media