OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "remoting/host/video_frame_recorder.h" | |
6 | |
7 #include "base/message_loop/message_loop.h" | |
8 #include "base/run_loop.h" | |
9 #include "remoting/codec/video_encoder_verbatim.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
12 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" | |
13 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | |
14 | |
15 namespace webrtc { | |
16 | |
17 // Define equality operator for DesktopFrame to allow use of EXPECT_EQ(). | |
18 static bool operator==(const DesktopFrame& a, | |
19 const DesktopFrame& b) { | |
20 if ((a.size().equals(b.size())) && | |
21 (a.updated_region().Equals(b.updated_region())) && | |
22 (a.dpi().equals(b.dpi()))) { | |
23 for (int i = 0; i < a.size().height(); ++i) { | |
24 if (memcmp(a.data() + a.stride() * i, | |
25 b.data() + b.stride() * i, | |
26 a.size().width() * DesktopFrame::kBytesPerPixel) != 0) { | |
27 return false; | |
28 } | |
29 } | |
30 return true; | |
31 } | |
32 return false; | |
33 } | |
34 | |
35 } // namespace | |
36 | |
37 namespace remoting { | |
38 | |
39 const int64_t kMaxContentBytes = 10 * 1024 * 1024; | |
40 const int kWidth = 640; | |
41 const int kHeight = 480; | |
42 const int kTestFrameCount = 6; | |
43 | |
44 class VideoFrameRecorderTest : public testing::Test { | |
45 public: | |
46 VideoFrameRecorderTest(); | |
47 | |
48 virtual void SetUp() OVERRIDE; | |
49 virtual void TearDown() OVERRIDE; | |
50 | |
51 void CreateAndWrapEncoder(); | |
52 scoped_ptr<webrtc::DesktopFrame> CreateNextFrame(); | |
53 void CreateTestFrames(); | |
54 void EncodeTestFrames(); | |
55 void EncodeDummyFrame(); | |
56 void StartRecording(); | |
57 void VerifyTestFrames(); | |
58 | |
59 protected: | |
60 base::MessageLoop message_loop_; | |
61 | |
62 scoped_ptr<VideoFrameRecorder> recorder_; | |
63 scoped_ptr<VideoEncoder> encoder_; | |
64 | |
65 std::list<webrtc::DesktopFrame*> test_frames_; | |
66 int frame_count_; | |
67 }; | |
68 | |
69 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {} | |
70 | |
71 void VideoFrameRecorderTest::SetUp() { | |
72 recorder_.reset(new VideoFrameRecorder()); | |
73 recorder_->SetMaxContentBytes(kMaxContentBytes); | |
74 } | |
75 | |
76 void VideoFrameRecorderTest::TearDown() { | |
77 // Allow events posted to the recorder_, if still valid, to be processed. | |
78 base::RunLoop().RunUntilIdle(); | |
79 | |
80 // Tear down the recorder, if necessary. | |
81 recorder_.reset(); | |
82 | |
83 // Process any events resulting from recorder teardown. | |
84 base::RunLoop().RunUntilIdle(); | |
85 } | |
86 | |
87 void VideoFrameRecorderTest::CreateAndWrapEncoder() { | |
88 scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim()); | |
89 encoder_ = recorder_->WrapVideoEncoder(encoder.Pass()); | |
90 | |
91 // Encode a dummy frame to bind the wrapper to the TaskRunner. | |
92 EncodeDummyFrame(); | |
93 } | |
94 | |
95 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() { | |
96 scoped_ptr<webrtc::DesktopFrame> frame( | |
97 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); | |
98 | |
99 // Fill content, DPI and updated-region based on |frame_count_| so that each | |
100 // generated frame is different. | |
101 memset(frame->data(), frame_count_, frame->stride() * kHeight); | |
102 frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_)); | |
103 frame->mutable_updated_region()->SetRect( | |
104 webrtc::DesktopRect::MakeWH(frame_count_, frame_count_)); | |
105 ++frame_count_; | |
106 | |
107 return frame.Pass(); | |
108 } | |
109 | |
110 void VideoFrameRecorderTest::CreateTestFrames() { | |
111 for (int i=0; i < kTestFrameCount; ++i) { | |
112 test_frames_.push_back(CreateNextFrame().release()); | |
113 } | |
114 } | |
115 | |
116 void VideoFrameRecorderTest::EncodeTestFrames() { | |
117 std::list<webrtc::DesktopFrame*>::iterator i; | |
118 for (i = test_frames_.begin(); i != test_frames_.end(); ++i) { | |
119 scoped_ptr<VideoPacket> packet = encoder_->Encode(*(*i)); | |
120 | |
121 // Process tasks to let the recorder pick up the frame. | |
122 base::RunLoop().RunUntilIdle(); | |
123 } | |
124 } | |
125 | |
126 void VideoFrameRecorderTest::EncodeDummyFrame() { | |
127 webrtc::BasicDesktopFrame dummy_frame(webrtc::DesktopSize(kWidth, kHeight)); | |
128 scoped_ptr<VideoPacket> packet = encoder_->Encode(dummy_frame); | |
129 base::RunLoop().RunUntilIdle(); | |
130 } | |
131 | |
132 void VideoFrameRecorderTest::StartRecording() { | |
133 // Start the recorder and pump events to let things initialize. | |
134 recorder_->SetEnableRecording(true); | |
135 base::RunLoop().RunUntilIdle(); | |
136 } | |
137 | |
138 void VideoFrameRecorderTest::VerifyTestFrames() { | |
139 // Verify that the recorded frames match the ones passed to the encoder. | |
140 while (!test_frames_.empty()) { | |
141 scoped_ptr<webrtc::DesktopFrame> recorded_frame(recorder_->NextFrame()); | |
142 ASSERT_TRUE(recorded_frame); | |
143 | |
144 scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front()); | |
145 test_frames_.pop_front(); | |
146 | |
147 EXPECT_EQ(*recorded_frame, *expected_frame); | |
148 } | |
149 | |
150 EXPECT_FALSE(recorder_->NextFrame()); | |
151 } | |
152 | |
153 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash. | |
154 TEST_F(VideoFrameRecorderTest, CreateDestroy) { | |
155 } | |
156 | |
157 // Basic test that creating, starting, stopping and destroying a | |
158 // VideoFrameRecorder don't end the world. | |
159 TEST_F(VideoFrameRecorderTest, StartStop) { | |
160 StartRecording(); | |
161 recorder_->SetEnableRecording(false); | |
162 } | |
163 | |
164 // Test that tearing down the VideoFrameRecorder while the VideoEncoder | |
165 // wrapper exists doesn't crash. | |
166 TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) { | |
167 CreateAndWrapEncoder(); | |
168 | |
169 // Start the recorder, so that the wrapper will push frames to it. | |
170 StartRecording(); | |
171 | |
172 // Tear down the recorder. | |
173 recorder_.reset(); | |
174 | |
175 // Encode a dummy frame via the wrapper to ensure we don't crash. | |
176 EncodeDummyFrame(); | |
177 } | |
178 | |
179 // Test that creating & tearing down the wrapper while the | |
180 // VideoFrameRecorder still exists doesn't crash. | |
181 TEST_F(VideoFrameRecorderTest, DestroyVideoEncoderWrapperFirst) { | |
182 CreateAndWrapEncoder(); | |
183 | |
184 // Start the recorder, so that the wrapper will push frames to it. | |
185 StartRecording(); | |
186 | |
187 // Encode a dummy frame via the wrapper to ensure we don't crash. | |
188 EncodeDummyFrame(); | |
189 | |
190 // Tear down the encoder wrapper. | |
191 encoder_.reset(); | |
192 | |
193 // Test teardown will stop the recorder and process pending events. | |
194 } | |
195 | |
196 // Test that when asked to encode a short sequence of frames, those frames are | |
197 // all recorded, in sequence. | |
198 TEST_F(VideoFrameRecorderTest, RecordFrames) { | |
199 CreateAndWrapEncoder(); | |
200 | |
201 // Start the recorder, so that the wrapper will push frames to it. | |
202 StartRecording(); | |
203 | |
204 // Create frames, store them and pass them to the encoder. | |
205 CreateTestFrames(); | |
206 EncodeTestFrames(); | |
207 | |
208 // Verify that the recorded frames match the ones passed to the encoder. | |
209 VerifyTestFrames(); | |
210 } | |
211 | |
212 // Test that when asked to record more frames than the maximum content bytes | |
213 // limit allows, the first encoded frames are dropped. | |
214 TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) { | |
215 CreateAndWrapEncoder(); | |
216 | |
217 // Configure a maximum content size sufficient for five and a half frames. | |
218 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | |
219 recorder_->SetMaxContentBytes((frame_bytes * 11) / 2); | |
220 | |
221 // Start the recorder, so that the wrapper will push frames to it. | |
222 StartRecording(); | |
223 | |
224 // Create frames, store them and pass them to the encoder. | |
225 CreateTestFrames(); | |
226 EncodeTestFrames(); | |
227 | |
228 // Only five of the supplied frames should have been recorded. | |
229 while (test_frames_.size() > 5) { | |
230 scoped_ptr<webrtc::DesktopFrame> frame(test_frames_.front()); | |
231 test_frames_.pop_front(); | |
232 } | |
233 | |
234 // Verify that the recorded frames match the ones passed to the encoder. | |
235 VerifyTestFrames(); | |
236 } | |
237 | |
238 // Test that when asked to record more frames than the maximum content bytes | |
239 // limit allows, the first encoded frames are dropped. | |
240 TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) { | |
241 CreateAndWrapEncoder(); | |
242 | |
243 // Configure a maximum content size sufficient for kTestFrameCount frames. | |
244 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | |
245 recorder_->SetMaxContentBytes(frame_bytes * kTestFrameCount); | |
246 | |
247 // Start the recorder, so that the wrapper will push frames to it. | |
248 StartRecording(); | |
249 | |
250 // Encode a frame, to record it, and consume it from the recorder. | |
251 EncodeDummyFrame(); | |
252 scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame(); | |
253 EXPECT_TRUE(frame); | |
254 | |
255 // Create frames, store them and pass them to the encoder. | |
256 CreateTestFrames(); | |
257 EncodeTestFrames(); | |
258 | |
259 // Verify that the recorded frames match the ones passed to the encoder. | |
260 VerifyTestFrames(); | |
261 } | |
262 | |
263 // Test that when asked to encode a short sequence of frames, none are recorded | |
264 // if recording was not enabled. | |
265 TEST_F(VideoFrameRecorderTest, EncodeButDontRecord) { | |
266 CreateAndWrapEncoder(); | |
267 | |
268 // Create frames, store them and pass them to the encoder. | |
269 CreateTestFrames(); | |
270 EncodeTestFrames(); | |
271 | |
272 // Clear the list of expected test frames, since none should be recorded. | |
273 test_frames_.clear(); | |
274 | |
275 // Verify that the recorded frames match the ones passed to the encoder. | |
276 VerifyTestFrames(); | |
277 } | |
278 | |
279 } // namespace remoting | |
OLD | NEW |