OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/video_frame_recorder.h" | 5 #include "remoting/host/video_frame_recorder.h" |
6 | 6 |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "base/run_loop.h" | 8 #include "base/run_loop.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "remoting/codec/video_encoder_verbatim.h" | 10 #include "remoting/codec/video_encoder_verbatim.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
13 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" | 13 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
14 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | 14 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" |
15 | 15 |
16 namespace webrtc { | 16 namespace webrtc { |
17 | 17 |
18 // Define equality operator for DesktopFrame to allow use of EXPECT_EQ(). | 18 // Define equality operator for DesktopFrame to allow use of EXPECT_EQ(). |
19 static bool operator==(const DesktopFrame& a, | 19 static bool operator==(const DesktopFrame& a, |
20 const DesktopFrame& b) { | 20 const DesktopFrame& b) { |
21 if ((a.size().equals(b.size())) && | 21 if ((!a.size().equals(b.size())) || |
22 (a.updated_region().Equals(b.updated_region())) && | 22 (!a.updated_region().Equals(b.updated_region())) || |
23 (a.dpi().equals(b.dpi()))) { | 23 (!a.dpi().equals(b.dpi()))) { |
24 for (int i = 0; i < a.size().height(); ++i) { | 24 return false; |
25 if (memcmp(a.data() + a.stride() * i, | 25 } |
26 b.data() + b.stride() * i, | 26 |
27 a.size().width() * DesktopFrame::kBytesPerPixel) != 0) { | 27 for (int i = 0; i < a.size().height(); ++i) { |
28 return false; | 28 if (memcmp(a.data() + a.stride() * i, |
29 } | 29 b.data() + b.stride() * i, |
30 a.size().width() * DesktopFrame::kBytesPerPixel) != 0) { | |
31 return false; | |
30 } | 32 } |
31 return true; | |
32 } | 33 } |
33 return false; | 34 |
35 return true; | |
34 } | 36 } |
35 | 37 |
36 } // namespace | 38 } // namespace |
37 | 39 |
38 namespace remoting { | 40 namespace remoting { |
39 | 41 |
40 const int64_t kMaxContentBytes = 10 * 1024 * 1024; | |
41 const int kWidth = 640; | |
42 const int kHeight = 480; | |
43 const int kTestFrameCount = 6; | |
44 | |
45 class VideoFrameRecorderTest : public testing::Test { | 42 class VideoFrameRecorderTest : public testing::Test { |
46 public: | 43 public: |
47 VideoFrameRecorderTest(); | 44 VideoFrameRecorderTest(); |
48 | 45 |
49 virtual void SetUp() OVERRIDE; | 46 virtual void SetUp() OVERRIDE; |
50 virtual void TearDown() OVERRIDE; | 47 virtual void TearDown() OVERRIDE; |
51 | 48 |
49 // Creates a new VideoEncoder, wraps it using |recorder_|, and stores the | |
50 // newly wrapped encoder in |encoder_|. | |
52 void CreateAndWrapEncoder(); | 51 void CreateAndWrapEncoder(); |
52 | |
53 // Creates the next test frame to pass to |encoder_|. Each test frame's pixel | |
54 // values are set uniquely, so that tests can verify that the correct set of | |
55 // frames were recorded. | |
53 scoped_ptr<webrtc::DesktopFrame> CreateNextFrame(); | 56 scoped_ptr<webrtc::DesktopFrame> CreateNextFrame(); |
57 | |
58 // Calls CreateNextFrame() to create kTextFrameCount test frames, and stores | |
59 // them to |test_frames_|. | |
54 void CreateTestFrames(); | 60 void CreateTestFrames(); |
61 | |
62 // Passes the frames in |test_frames_| to |encoder_|, in order, to encode. | |
55 void EncodeTestFrames(); | 63 void EncodeTestFrames(); |
64 | |
65 // Creates a frame and passes it to |encoder_| without adding it to | |
66 // |test_frames_|. | |
56 void EncodeDummyFrame(); | 67 void EncodeDummyFrame(); |
68 | |
69 // Configures |recorder_| to start recording, and pumps events to ensure that | |
70 // |encoder_| is ready to record frames. | |
57 void StartRecording(); | 71 void StartRecording(); |
72 | |
73 // Reads frames from |recorder_| and compares them to the |test_frames_|. | |
58 void VerifyTestFrames(); | 74 void VerifyTestFrames(); |
59 | 75 |
60 protected: | 76 protected: |
77 typedef std::list<webrtc::DesktopFrame*> DesktopFrames; | |
78 | |
79 const int kFrameWidth = 640; | |
Peter Kasting
2014/08/26 20:58:15
These should be static consts since they're not in
Wez
2014/08/28 00:13:21
I was consistent until you asked me to move the co
Peter Kasting
2014/08/28 00:31:02
Sorry...
| |
80 const int kFrameHeight = 480; | |
81 const size_t kTestFrameCount = 6; | |
82 const int64 kTestFrameBytes = | |
83 kFrameWidth * kFrameHeight * webrtc::DesktopFrame::kBytesPerPixel; | |
84 | |
61 base::MessageLoop message_loop_; | 85 base::MessageLoop message_loop_; |
62 | 86 |
63 scoped_ptr<VideoFrameRecorder> recorder_; | 87 scoped_ptr<VideoFrameRecorder> recorder_; |
64 scoped_ptr<VideoEncoder> encoder_; | 88 scoped_ptr<VideoEncoder> encoder_; |
65 | 89 |
66 std::list<webrtc::DesktopFrame*> test_frames_; | 90 DesktopFrames test_frames_; |
67 int frame_count_; | 91 int frame_count_; |
92 | |
93 DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderTest); | |
68 }; | 94 }; |
69 | 95 |
70 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {} | 96 VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {} |
71 | 97 |
72 void VideoFrameRecorderTest::SetUp() { | 98 void VideoFrameRecorderTest::SetUp() { |
99 const int64_t kMaxContentBytes = 10 * 1024 * 1024; | |
73 recorder_.reset(new VideoFrameRecorder()); | 100 recorder_.reset(new VideoFrameRecorder()); |
74 recorder_->SetMaxContentBytes(kMaxContentBytes); | 101 recorder_->SetMaxContentBytes(kMaxContentBytes); |
75 } | 102 } |
76 | 103 |
77 void VideoFrameRecorderTest::TearDown() { | 104 void VideoFrameRecorderTest::TearDown() { |
78 ASSERT_TRUE(test_frames_.empty()); | 105 ASSERT_TRUE(test_frames_.empty()); |
79 | 106 |
80 // Allow events posted to the recorder_, if still valid, to be processed. | 107 // Allow events posted to the recorder_, if still valid, to be processed. |
81 base::RunLoop().RunUntilIdle(); | 108 base::RunLoop().RunUntilIdle(); |
82 | 109 |
83 // Tear down the recorder, if necessary. | 110 // Tear down the recorder, if necessary. |
84 recorder_.reset(); | 111 recorder_.reset(); |
85 | 112 |
86 // Process any events resulting from recorder teardown. | 113 // Process any events resulting from recorder teardown. |
87 base::RunLoop().RunUntilIdle(); | 114 base::RunLoop().RunUntilIdle(); |
88 } | 115 } |
89 | 116 |
90 void VideoFrameRecorderTest::CreateAndWrapEncoder() { | 117 void VideoFrameRecorderTest::CreateAndWrapEncoder() { |
91 scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim()); | 118 scoped_ptr<VideoEncoder> encoder(new VideoEncoderVerbatim()); |
92 encoder_ = recorder_->WrapVideoEncoder(encoder.Pass()); | 119 encoder_ = recorder_->WrapVideoEncoder(encoder.Pass()); |
93 | 120 |
94 // Encode a dummy frame to bind the wrapper to the TaskRunner. | 121 // Encode a dummy frame to bind the wrapper to the TaskRunner. |
95 EncodeDummyFrame(); | 122 EncodeDummyFrame(); |
96 } | 123 } |
97 | 124 |
98 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() { | 125 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorderTest::CreateNextFrame() { |
99 scoped_ptr<webrtc::DesktopFrame> frame( | 126 scoped_ptr<webrtc::DesktopFrame> frame( |
100 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); | 127 new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kFrameWidth, |
128 kFrameHeight))); | |
101 | 129 |
102 // Fill content, DPI and updated-region based on |frame_count_| so that each | 130 // Fill content, DPI and updated-region based on |frame_count_| so that each |
103 // generated frame is different. | 131 // generated frame is different. |
104 memset(frame->data(), frame_count_, frame->stride() * kHeight); | 132 memset(frame->data(), frame_count_, frame->stride() * kFrameHeight); |
105 frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_)); | 133 frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_)); |
106 frame->mutable_updated_region()->SetRect( | 134 frame->mutable_updated_region()->SetRect( |
107 webrtc::DesktopRect::MakeWH(frame_count_, frame_count_)); | 135 webrtc::DesktopRect::MakeWH(frame_count_, frame_count_)); |
108 ++frame_count_; | 136 ++frame_count_; |
109 | 137 |
110 return frame.Pass(); | 138 return frame.Pass(); |
111 } | 139 } |
112 | 140 |
113 void VideoFrameRecorderTest::CreateTestFrames() { | 141 void VideoFrameRecorderTest::CreateTestFrames() { |
114 for (int i=0; i < kTestFrameCount; ++i) { | 142 for (size_t i = 0; i < kTestFrameCount; ++i) { |
115 test_frames_.push_back(CreateNextFrame().release()); | 143 test_frames_.push_back(CreateNextFrame().release()); |
116 } | 144 } |
117 } | 145 } |
118 | 146 |
119 void VideoFrameRecorderTest::EncodeTestFrames() { | 147 void VideoFrameRecorderTest::EncodeTestFrames() { |
120 std::list<webrtc::DesktopFrame*>::iterator i; | 148 for (DesktopFrames::iterator i = test_frames_.begin(); |
121 for (i = test_frames_.begin(); i != test_frames_.end(); ++i) { | 149 i != test_frames_.end(); ++i) { |
122 scoped_ptr<VideoPacket> packet = encoder_->Encode(*(*i)); | 150 ASSERT_TRUE(encoder_->Encode(*(*i))); |
Peter Kasting
2014/08/26 20:58:15
Nit: Could just write (**i)
Wez
2014/08/28 00:13:21
Done.
| |
123 | 151 |
124 // Process tasks to let the recorder pick up the frame. | 152 // Process tasks to let the recorder pick up the frame. |
125 base::RunLoop().RunUntilIdle(); | 153 base::RunLoop().RunUntilIdle(); |
126 } | 154 } |
127 } | 155 } |
128 | 156 |
129 void VideoFrameRecorderTest::EncodeDummyFrame() { | 157 void VideoFrameRecorderTest::EncodeDummyFrame() { |
130 webrtc::BasicDesktopFrame dummy_frame(webrtc::DesktopSize(kWidth, kHeight)); | 158 webrtc::BasicDesktopFrame dummy_frame( |
131 scoped_ptr<VideoPacket> packet = encoder_->Encode(dummy_frame); | 159 webrtc::DesktopSize(kFrameWidth, kFrameHeight)); |
160 ASSERT_TRUE(encoder_->Encode(dummy_frame)); | |
132 base::RunLoop().RunUntilIdle(); | 161 base::RunLoop().RunUntilIdle(); |
133 } | 162 } |
134 | 163 |
135 void VideoFrameRecorderTest::StartRecording() { | 164 void VideoFrameRecorderTest::StartRecording() { |
136 // Start the recorder and pump events to let things initialize. | 165 // Start the recorder and pump events to let things initialize. |
137 recorder_->SetEnableRecording(true); | 166 recorder_->SetEnableRecording(true); |
138 base::RunLoop().RunUntilIdle(); | 167 base::RunLoop().RunUntilIdle(); |
139 } | 168 } |
140 | 169 |
141 void VideoFrameRecorderTest::VerifyTestFrames() { | 170 void VideoFrameRecorderTest::VerifyTestFrames() { |
142 // Verify that the recorded frames match the ones passed to the encoder. | 171 // Verify that the recorded frames match the ones passed to the encoder. |
143 while (!test_frames_.empty()) { | 172 while (!test_frames_.empty()) { |
144 scoped_ptr<webrtc::DesktopFrame> recorded_frame(recorder_->NextFrame()); | 173 scoped_ptr<webrtc::DesktopFrame> recorded_frame(recorder_->NextFrame()); |
145 ASSERT_TRUE(recorded_frame); | 174 ASSERT_TRUE(recorded_frame); |
146 | 175 |
147 scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front()); | 176 scoped_ptr<webrtc::DesktopFrame> expected_frame(test_frames_.front()); |
148 test_frames_.pop_front(); | 177 test_frames_.pop_front(); |
149 | 178 |
150 EXPECT_EQ(*recorded_frame, *expected_frame); | 179 EXPECT_EQ(*recorded_frame, *expected_frame); |
151 } | 180 } |
152 | 181 |
153 EXPECT_FALSE(recorder_->NextFrame()); | 182 EXPECT_FALSE(recorder_->NextFrame()); |
154 } | 183 } |
155 | 184 |
156 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash. | 185 // Basic test that creating & tearing down VideoFrameRecorder doesn't crash. |
157 TEST_F(VideoFrameRecorderTest, CreateDestroy) { | 186 TEST_F(VideoFrameRecorderTest, CreateDestroy) { |
158 } | 187 } |
159 | 188 |
160 // Basic test that creating, starting, stopping and destroying a | 189 // Basic test that creating, starting, stopping and destroying a |
161 // VideoFrameRecorder don't end the world. | 190 // VideoFrameRecorder succeeds (e.g. does not crash or DCHECK). |
162 TEST_F(VideoFrameRecorderTest, StartStop) { | 191 TEST_F(VideoFrameRecorderTest, StartStop) { |
163 StartRecording(); | 192 StartRecording(); |
164 recorder_->SetEnableRecording(false); | 193 recorder_->SetEnableRecording(false); |
165 } | 194 } |
166 | 195 |
167 // Test that tearing down the VideoFrameRecorder while the VideoEncoder | 196 // Test that tearing down the VideoFrameRecorder while the VideoEncoder |
168 // wrapper exists doesn't crash. | 197 // wrapper exists doesn't crash. |
169 TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) { | 198 TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) { |
170 CreateAndWrapEncoder(); | 199 CreateAndWrapEncoder(); |
171 | 200 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 // Verify that the recorded frames match the ones passed to the encoder. | 240 // Verify that the recorded frames match the ones passed to the encoder. |
212 VerifyTestFrames(); | 241 VerifyTestFrames(); |
213 } | 242 } |
214 | 243 |
215 // Test that when asked to record more frames than the maximum content bytes | 244 // Test that when asked to record more frames than the maximum content bytes |
216 // limit allows, the first encoded frames are dropped. | 245 // limit allows, the first encoded frames are dropped. |
217 TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) { | 246 TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) { |
218 CreateAndWrapEncoder(); | 247 CreateAndWrapEncoder(); |
219 | 248 |
220 // Configure a maximum content size sufficient for five and a half frames. | 249 // Configure a maximum content size sufficient for five and a half frames. |
221 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | 250 recorder_->SetMaxContentBytes((kTestFrameBytes * 11) / 2); |
222 recorder_->SetMaxContentBytes((frame_bytes * 11) / 2); | |
223 | 251 |
224 // Start the recorder, so that the wrapper will push frames to it. | 252 // Start the recorder, so that the wrapper will push frames to it. |
225 StartRecording(); | 253 StartRecording(); |
226 | 254 |
227 // Create frames, store them and pass them to the encoder. | 255 // Create frames, store them and pass them to the encoder. |
228 CreateTestFrames(); | 256 CreateTestFrames(); |
229 EncodeTestFrames(); | 257 EncodeTestFrames(); |
230 | 258 |
231 // Only five of the supplied frames should have been recorded. | 259 // Only five of the supplied frames should have been recorded. |
232 while (test_frames_.size() > 5) { | 260 while (test_frames_.size() > 5) { |
233 scoped_ptr<webrtc::DesktopFrame> frame(test_frames_.front()); | 261 scoped_ptr<webrtc::DesktopFrame> frame(test_frames_.front()); |
234 test_frames_.pop_front(); | 262 test_frames_.pop_front(); |
235 } | 263 } |
236 | 264 |
237 // Verify that the recorded frames match the ones passed to the encoder. | 265 // Verify that the recorded frames match the ones passed to the encoder. |
238 VerifyTestFrames(); | 266 VerifyTestFrames(); |
239 } | 267 } |
240 | 268 |
241 // Test that when asked to record more frames than the maximum content bytes | 269 // Test that when frames are consumed the corresponding space is freed up in |
242 // limit allows, the first encoded frames are dropped. | 270 // the content buffer, allowing subsequent frames to be recorded. |
243 TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) { | 271 TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) { |
244 CreateAndWrapEncoder(); | 272 CreateAndWrapEncoder(); |
245 | 273 |
246 // Configure a maximum content size sufficient for kTestFrameCount frames. | 274 // Configure a maximum content size sufficient for kTestFrameCount frames. |
247 int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; | 275 recorder_->SetMaxContentBytes(kTestFrameBytes * kTestFrameCount); |
248 recorder_->SetMaxContentBytes(frame_bytes * kTestFrameCount); | |
249 | 276 |
250 // Start the recorder, so that the wrapper will push frames to it. | 277 // Start the recorder, so that the wrapper will push frames to it. |
251 StartRecording(); | 278 StartRecording(); |
252 | 279 |
253 // Encode a frame, to record it, and consume it from the recorder. | 280 // Encode a frame, to record it, and consume it from the recorder. |
254 EncodeDummyFrame(); | 281 EncodeDummyFrame(); |
255 scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame(); | 282 scoped_ptr<webrtc::DesktopFrame> frame = recorder_->NextFrame(); |
256 EXPECT_TRUE(frame); | 283 EXPECT_TRUE(frame); |
257 | 284 |
258 // Create frames, store them and pass them to the encoder. | 285 // Create frames, store them and pass them to the encoder. |
(...skipping 14 matching lines...) Expand all Loading... | |
273 EncodeTestFrames(); | 300 EncodeTestFrames(); |
274 | 301 |
275 // Clear the list of expected test frames, since none should be recorded. | 302 // Clear the list of expected test frames, since none should be recorded. |
276 STLDeleteElements(&test_frames_); | 303 STLDeleteElements(&test_frames_); |
277 | 304 |
278 // Verify that the recorded frames match the ones passed to the encoder. | 305 // Verify that the recorded frames match the ones passed to the encoder. |
279 VerifyTestFrames(); | 306 VerifyTestFrames(); |
280 } | 307 } |
281 | 308 |
282 } // namespace remoting | 309 } // namespace remoting |
OLD | NEW |