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