OLD | NEW |
---|---|
(Empty) | |
1 // 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 | |
5 #include "base/bind.h" | |
6 #include "base/callback_helpers.h" | |
7 #include "base/message_loop/message_loop.h" | |
8 #include "base/run_loop.h" | |
9 #include "base/test/simple_test_tick_clock.h" | |
10 #include "media/base/null_video_sink.h" | |
11 #include "media/base/test_helpers.h" | |
12 #include "testing/gmock/include/gmock/gmock.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 using testing::_; | |
16 using testing::DoAll; | |
17 using testing::Return; | |
18 | |
19 namespace media { | |
20 | |
21 ACTION_P(RunClosure, closure) { | |
22 closure.Run(); | |
23 } | |
24 | |
25 class NullVideoSinkTest : public testing::Test, | |
26 public VideoRendererSink::RenderCallback { | |
27 public: | |
28 NullVideoSinkTest() { | |
29 // Never use null TimeTicks since they have special connotations. | |
30 tick_clock_.Advance(base::TimeDelta::FromMicroseconds(12345)); | |
31 } | |
32 ~NullVideoSinkTest() override {} | |
33 | |
34 base::TimeDelta default_interval() const { | |
35 return base::TimeDelta::FromMilliseconds(25); | |
36 } | |
37 | |
38 base::TimeTicks current_time() { | |
39 return tick_clock_.NowTicks(); | |
40 } | |
41 | |
42 base::TimeTicks current_interval_end() { | |
43 return tick_clock_.NowTicks() + default_interval(); | |
44 } | |
xhwang
2015/04/28 23:12:07
style nit: These are not getters and should use no
DaleCurtis
2015/04/29 00:54:07
Removed since they were only in one test.
| |
45 | |
46 scoped_ptr<NullVideoSink> ConstructSink(bool clockless, | |
47 base::TimeDelta interval) { | |
48 scoped_ptr<NullVideoSink> new_sink(new NullVideoSink( | |
49 clockless, interval, | |
50 base::Bind(&NullVideoSinkTest::FrameReceived, base::Unretained(this)), | |
51 message_loop_.task_runner())); | |
52 new_sink->set_tick_clock_for_testing(&tick_clock_); | |
53 return new_sink; | |
xhwang
2015/04/28 23:12:06
.Pass()?
DaleCurtis
2015/04/29 00:54:07
Not necessary in this case, it's automatically mov
xhwang
2015/04/29 03:49:13
Cool. TIL!
| |
54 } | |
55 | |
56 scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) { | |
57 const gfx::Size natural_size(8, 8); | |
58 return VideoFrame::CreateFrame(VideoFrame::YV12, natural_size, | |
59 gfx::Rect(natural_size), natural_size, | |
60 timestamp); | |
61 } | |
62 | |
63 // VideoRendererSink::RenderCallback implementation. | |
64 MOCK_METHOD2(Render, | |
65 scoped_refptr<VideoFrame>(base::TimeTicks, base::TimeTicks)); | |
66 MOCK_METHOD0(OnFrameDropped, void()); | |
67 | |
68 MOCK_METHOD1(FrameReceived, void(const scoped_refptr<VideoFrame>&)); | |
69 | |
70 protected: | |
71 base::MessageLoop message_loop_; | |
72 base::SimpleTestTickClock tick_clock_; | |
73 | |
74 DISALLOW_COPY_AND_ASSIGN(NullVideoSinkTest); | |
75 }; | |
76 | |
77 | |
78 TEST_F(NullVideoSinkTest, BasicFunctionality) { | |
79 scoped_ptr<NullVideoSink> sink = ConstructSink(false, default_interval()); | |
80 scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta()); | |
81 | |
82 // The sink shouldn't have to be started to use the paint method. | |
83 EXPECT_CALL(*this, FrameReceived(test_frame)); | |
84 sink->PaintFrameUsingOldRenderingPath(test_frame); | |
85 | |
86 { | |
87 SCOPED_TRACE("Waiting for sink startup."); | |
88 sink->Start(this); | |
89 EXPECT_CALL(*this, Render(current_time(), current_interval_end())) | |
90 .WillOnce(Return(test_frame)); | |
91 base::RunLoop run_loop; | |
92 EXPECT_CALL(*this, FrameReceived(test_frame)) | |
93 .WillOnce(RunClosure(run_loop.QuitClosure())); | |
94 run_loop.Run(); | |
95 } | |
96 | |
97 // A second call returning the same frame should not result in a new call to | |
98 // FrameReceived(). | |
99 { | |
100 SCOPED_TRACE("Waiting for second render call."); | |
101 WaitableMessageLoopEvent event; | |
102 EXPECT_CALL(*this, Render(_, _)) | |
103 .WillOnce(Return(test_frame)) | |
104 .WillOnce(Return(nullptr)); | |
105 EXPECT_CALL(*this, FrameReceived(test_frame)).Times(0); | |
106 EXPECT_CALL(*this, FrameReceived(scoped_refptr<VideoFrame>())) | |
107 .WillOnce(RunClosure(event.GetClosure())); | |
108 event.RunAndWait(); | |
109 } | |
110 | |
111 { | |
112 SCOPED_TRACE("Waiting for stop event."); | |
113 WaitableMessageLoopEvent event; | |
114 sink->set_stop_callback(event.GetClosure()); | |
115 sink->Stop(); | |
116 event.RunAndWait(); | |
117 } | |
118 } | |
119 | |
120 TEST_F(NullVideoSinkTest, ClocklessFunctionality) { | |
121 // Construct the sink with a huge interval, it should still complete quickly. | |
122 const base::TimeDelta interval = base::TimeDelta::FromSeconds(10); | |
123 scoped_ptr<NullVideoSink> sink = ConstructSink(true, interval); | |
124 | |
125 scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta()); | |
126 sink->Start(this); | |
127 | |
128 EXPECT_CALL(*this, FrameReceived(test_frame)).Times(1); | |
129 EXPECT_CALL(*this, FrameReceived(scoped_refptr<VideoFrame>())).Times(1); | |
130 | |
131 const int kTestRuns = 6; | |
132 const base::TimeTicks now = base::TimeTicks::Now(); | |
133 const base::TimeTicks current_time = tick_clock_.NowTicks(); | |
134 | |
135 // Use a RunLoop instead of WaitableMessageLoopEvent() since it will only quit | |
136 // the loop when it's idle, instead of quitting immediately which is required | |
137 // when clockless playback is enabled (otherwise the loop is never idle). | |
138 base::RunLoop run_loop; | |
139 for (int i = 0; i < kTestRuns; ++i) { | |
140 if (i < kTestRuns - 1) { | |
141 EXPECT_CALL(*this, Render(current_time + i * interval, | |
142 current_time + (i + 1) * interval)) | |
143 .WillOnce(Return(test_frame)); | |
144 } else { | |
145 EXPECT_CALL(*this, Render(current_time + i * interval, | |
146 current_time + (i + 1) * interval)) | |
147 .WillOnce(DoAll(RunClosure(run_loop.QuitClosure()), Return(nullptr))); | |
148 } | |
149 } | |
150 | |
151 run_loop.Run(); | |
152 ASSERT_LT(base::TimeTicks::Now() - now, kTestRuns * interval); | |
153 sink->Stop(); | |
154 } | |
155 | |
xhwang
2015/04/28 23:12:06
Is it interesting to test the case where Render()
DaleCurtis
2015/04/29 00:54:07
Not particularly in this case, it was more importa
xhwang
2015/04/29 03:49:13
Can you just call tick_clock_.Advance() in Render(
| |
156 } | |
OLD | NEW |