OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <deque> | 5 #include <deque> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 | 7 |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "media/base/video_frame.h" | 11 #include "media/base/video_frame.h" |
12 #include "remoting/codec/codec_test.h" | 12 #include "remoting/codec/codec_test.h" |
13 #include "remoting/codec/video_decoder.h" | 13 #include "remoting/codec/video_decoder.h" |
14 #include "remoting/codec/video_encoder.h" | 14 #include "remoting/codec/video_encoder.h" |
15 #include "remoting/base/util.h" | 15 #include "remoting/base/util.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 17 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
18 | 18 |
19 using webrtc::BasicDesktopFrame; | 19 using webrtc::BasicDesktopFrame; |
20 using webrtc::DesktopFrame; | 20 using webrtc::DesktopFrame; |
21 using webrtc::DesktopRect; | 21 using webrtc::DesktopRect; |
22 using webrtc::DesktopRegion; | 22 using webrtc::DesktopRegion; |
23 using webrtc::DesktopSize; | 23 using webrtc::DesktopSize; |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 const int kBytesPerPixel = 4; | 27 const int kBytesPerPixel = 4; |
28 | 28 |
29 // Some sample rects for testing. | 29 // Some sample rects for testing. |
30 std::vector<std::vector<DesktopRect> > MakeTestRectLists(DesktopSize size) { | 30 std::vector<DesktopRegion> MakeTestRegionLists(DesktopSize size) { |
31 std::vector<std::vector<DesktopRect> > rect_lists; | 31 std::vector<DesktopRegion> region_lists; |
32 std::vector<DesktopRect> rects; | 32 DesktopRegion region; |
33 rects.push_back(DesktopRect::MakeXYWH(0, 0, size.width(), size.height())); | 33 region.AddRect(DesktopRect::MakeXYWH(0, 0, size.width(), size.height())); |
34 rect_lists.push_back(rects); | 34 region_lists.push_back(region); |
35 rects.clear(); | 35 region.Clear(); |
36 rects.push_back(DesktopRect::MakeXYWH( | 36 region.AddRect( |
37 0, 0, size.width() / 2, size.height() / 2)); | 37 DesktopRect::MakeXYWH(0, 0, size.width() / 2, size.height() / 2)); |
38 rect_lists.push_back(rects); | 38 region_lists.push_back(region); |
39 rects.clear(); | 39 region.Clear(); |
40 rects.push_back(DesktopRect::MakeXYWH( | 40 region.AddRect(DesktopRect::MakeXYWH(size.width() / 2, size.height() / 2, |
41 size.width() / 2, size.height() / 2, | 41 size.width() / 2, size.height() / 2)); |
42 size.width() / 2, size.height() / 2)); | 42 region_lists.push_back(region); |
43 rect_lists.push_back(rects); | 43 region.Clear(); |
44 rects.clear(); | 44 region.AddRect(DesktopRect::MakeXYWH(16, 16, 16, 16)); |
45 rects.push_back(DesktopRect::MakeXYWH(16, 16, 16, 16)); | 45 region.AddRect(DesktopRect::MakeXYWH(32, 32, 32, 32)); |
46 rects.push_back(DesktopRect::MakeXYWH(128, 64, 32, 32)); | 46 region.IntersectWith(DesktopRect::MakeSize(size)); |
47 rect_lists.push_back(rects); | 47 region_lists.push_back(region); |
48 return rect_lists; | 48 return region_lists; |
49 } | 49 } |
50 | 50 |
51 } // namespace | 51 } // namespace |
52 | 52 |
53 namespace remoting { | 53 namespace remoting { |
54 | 54 |
55 class VideoDecoderTester { | 55 class VideoDecoderTester { |
56 public: | 56 public: |
57 VideoDecoderTester(VideoDecoder* decoder, | 57 VideoDecoderTester(VideoDecoder* decoder, |
58 const DesktopSize& screen_size, | 58 const DesktopSize& screen_size, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 } | 98 } |
99 | 99 |
100 void set_strict(bool strict) { | 100 void set_strict(bool strict) { |
101 strict_ = strict; | 101 strict_ = strict; |
102 } | 102 } |
103 | 103 |
104 void set_frame(DesktopFrame* frame) { | 104 void set_frame(DesktopFrame* frame) { |
105 frame_ = frame; | 105 frame_ = frame; |
106 } | 106 } |
107 | 107 |
108 void AddRects(const DesktopRect* rects, int count) { | |
109 for (int i = 0; i < count; ++i) { | |
110 expected_region_.AddRect(rects[i]); | |
111 } | |
112 } | |
113 | |
114 void AddRegion(const DesktopRegion& region) { | 108 void AddRegion(const DesktopRegion& region) { |
115 expected_region_.AddRegion(region); | 109 expected_region_.AddRegion(region); |
116 } | 110 } |
117 | 111 |
118 void VerifyResults() { | 112 void VerifyResults() { |
119 if (!strict_) | 113 if (!strict_) |
120 return; | 114 return; |
121 | 115 |
122 ASSERT_TRUE(frame_); | 116 ASSERT_TRUE(frame_); |
123 | 117 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 for (int i = 0; i < memory_size; ++i) { | 232 for (int i = 0; i < memory_size; ++i) { |
239 frame->data()[i] = rand() % 256; | 233 frame->data()[i] = rand() % 256; |
240 } | 234 } |
241 | 235 |
242 return frame.Pass(); | 236 return frame.Pass(); |
243 } | 237 } |
244 | 238 |
245 static void TestEncodingRects(VideoEncoder* encoder, | 239 static void TestEncodingRects(VideoEncoder* encoder, |
246 VideoEncoderTester* tester, | 240 VideoEncoderTester* tester, |
247 DesktopFrame* frame, | 241 DesktopFrame* frame, |
248 const DesktopRect* rects, | 242 const DesktopRegion& region) { |
249 int count) { | 243 *frame->mutable_updated_region() = region; |
250 frame->mutable_updated_region()->Clear(); | |
251 for (int i = 0; i < count; ++i) { | |
252 frame->mutable_updated_region()->AddRect(rects[i]); | |
253 } | |
254 | |
255 scoped_ptr<VideoPacket> packet = encoder->Encode(*frame); | 244 scoped_ptr<VideoPacket> packet = encoder->Encode(*frame); |
256 tester->DataAvailable(packet.Pass()); | 245 tester->DataAvailable(packet.Pass()); |
257 } | 246 } |
258 | 247 |
259 void TestVideoEncoder(VideoEncoder* encoder, bool strict) { | 248 void TestVideoEncoder(VideoEncoder* encoder, bool strict) { |
260 const int kSizes[] = {320, 319, 317, 150}; | 249 const int kSizes[] = {80, 79, 77, 54}; |
261 | 250 |
262 VideoEncoderTester tester; | 251 VideoEncoderTester tester; |
263 | 252 |
264 for (size_t xi = 0; xi < arraysize(kSizes); ++xi) { | 253 for (size_t xi = 0; xi < arraysize(kSizes); ++xi) { |
265 for (size_t yi = 0; yi < arraysize(kSizes); ++yi) { | 254 for (size_t yi = 0; yi < arraysize(kSizes); ++yi) { |
266 DesktopSize size = DesktopSize(kSizes[xi], kSizes[yi]); | 255 DesktopSize size(kSizes[xi], kSizes[yi]); |
267 scoped_ptr<DesktopFrame> frame = PrepareFrame(size); | 256 scoped_ptr<DesktopFrame> frame = PrepareFrame(size); |
268 std::vector<std::vector<DesktopRect> > test_rect_lists = | 257 for (const DesktopRegion& region : MakeTestRegionLists(size)) { |
269 MakeTestRectLists(size); | 258 TestEncodingRects(encoder, &tester, frame.get(), region); |
270 for (size_t i = 0; i < test_rect_lists.size(); ++i) { | |
271 const std::vector<DesktopRect>& test_rects = test_rect_lists[i]; | |
272 TestEncodingRects(encoder, &tester, frame.get(), | |
273 &test_rects[0], test_rects.size()); | |
274 } | 259 } |
275 | 260 |
276 // Pass some empty frames through the encoder. | 261 // Pass some empty frames through the encoder. |
277 for (int i = 0; i < 10; ++i) { | 262 for (int i = 0; i < 5; ++i) { |
278 TestEncodingRects(encoder, &tester, frame.get(), nullptr, 0); | 263 TestEncodingRects(encoder, &tester, frame.get(), DesktopRegion()); |
279 } | 264 } |
280 } | 265 } |
281 } | 266 } |
282 } | 267 } |
283 | 268 |
284 void TestVideoEncoderEmptyFrames(VideoEncoder* encoder, | 269 void TestVideoEncoderEmptyFrames(VideoEncoder* encoder, |
285 int max_topoff_frames) { | 270 int max_topoff_frames) { |
286 const DesktopSize kSize(640, 480); | 271 const DesktopSize kSize(100, 100); |
287 scoped_ptr<DesktopFrame> frame(PrepareFrame(kSize)); | 272 scoped_ptr<DesktopFrame> frame(PrepareFrame(kSize)); |
288 | 273 |
289 frame->mutable_updated_region()->SetRect( | 274 frame->mutable_updated_region()->SetRect( |
290 webrtc::DesktopRect::MakeSize(kSize)); | 275 webrtc::DesktopRect::MakeSize(kSize)); |
291 EXPECT_TRUE(encoder->Encode(*frame)); | 276 EXPECT_TRUE(encoder->Encode(*frame)); |
292 | 277 |
293 int topoff_frames = 0; | 278 int topoff_frames = 0; |
294 frame->mutable_updated_region()->Clear(); | 279 frame->mutable_updated_region()->Clear(); |
295 for (int i = 0; i < max_topoff_frames + 1; ++i) { | 280 for (int i = 0; i < max_topoff_frames + 1; ++i) { |
296 if (!encoder->Encode(*frame)) | 281 if (!encoder->Encode(*frame)) |
297 break; | 282 break; |
298 topoff_frames++; | 283 topoff_frames++; |
299 } | 284 } |
300 | 285 |
301 // If top-off is enabled then our random frame contents should always | 286 // If top-off is enabled then our random frame contents should always |
302 // trigger it, so expect at least one top-off frame - strictly, though, | 287 // trigger it, so expect at least one top-off frame - strictly, though, |
303 // an encoder may not always need to top-off. | 288 // an encoder may not always need to top-off. |
304 EXPECT_GE(topoff_frames, max_topoff_frames ? 1 : 0); | 289 EXPECT_GE(topoff_frames, max_topoff_frames ? 1 : 0); |
305 EXPECT_LE(topoff_frames, max_topoff_frames); | 290 EXPECT_LE(topoff_frames, max_topoff_frames); |
306 } | 291 } |
307 | 292 |
308 static void TestEncodeDecodeRects(VideoEncoder* encoder, | 293 static void TestEncodeDecodeRects(VideoEncoder* encoder, |
309 VideoEncoderTester* encoder_tester, | 294 VideoEncoderTester* encoder_tester, |
310 VideoDecoderTester* decoder_tester, | 295 VideoDecoderTester* decoder_tester, |
311 DesktopFrame* frame, | 296 DesktopFrame* frame, |
312 const DesktopRect* rects, int count) { | 297 const DesktopRegion& region) { |
313 frame->mutable_updated_region()->Clear(); | 298 *frame->mutable_updated_region() = region; |
314 for (int i = 0; i < count; ++i) { | 299 decoder_tester->AddRegion(region); |
315 frame->mutable_updated_region()->AddRect(rects[i]); | |
316 } | |
317 decoder_tester->AddRects(rects, count); | |
318 | 300 |
319 // Generate random data for the updated region. | 301 // Generate random data for the updated region. |
320 srand(0); | 302 srand(0); |
321 for (int i = 0; i < count; ++i) { | 303 for (DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { |
322 const int row_size = | 304 const int row_size = DesktopFrame::kBytesPerPixel * i.rect().width(); |
323 DesktopFrame::kBytesPerPixel * rects[i].width(); | 305 uint8* memory = frame->data() + frame->stride() * i.rect().top() + |
324 uint8* memory = frame->data() + | 306 DesktopFrame::kBytesPerPixel * i.rect().left(); |
325 frame->stride() * rects[i].top() + | 307 for (int y = 0; y < i.rect().height(); ++y) { |
326 DesktopFrame::kBytesPerPixel * rects[i].left(); | |
327 for (int y = 0; y < rects[i].height(); ++y) { | |
328 for (int x = 0; x < row_size; ++x) | 308 for (int x = 0; x < row_size; ++x) |
329 memory[x] = rand() % 256; | 309 memory[x] = rand() % 256; |
330 memory += frame->stride(); | 310 memory += frame->stride(); |
331 } | 311 } |
332 } | 312 } |
333 | 313 |
334 scoped_ptr<VideoPacket> packet = encoder->Encode(*frame); | 314 scoped_ptr<VideoPacket> packet = encoder->Encode(*frame); |
335 encoder_tester->DataAvailable(packet.Pass()); | 315 encoder_tester->DataAvailable(packet.Pass()); |
336 decoder_tester->VerifyResults(); | 316 decoder_tester->VerifyResults(); |
337 decoder_tester->Reset(); | 317 decoder_tester->Reset(); |
338 } | 318 } |
339 | 319 |
340 void TestVideoEncoderDecoder( | 320 void TestVideoEncoderDecoder(VideoEncoder* encoder, |
341 VideoEncoder* encoder, VideoDecoder* decoder, bool strict) { | 321 VideoDecoder* decoder, |
342 DesktopSize kSize = DesktopSize(320, 240); | 322 bool strict) { |
| 323 DesktopSize kSize = DesktopSize(160, 120); |
343 | 324 |
344 VideoEncoderTester encoder_tester; | 325 VideoEncoderTester encoder_tester; |
345 | 326 |
346 scoped_ptr<DesktopFrame> frame = PrepareFrame(kSize); | 327 scoped_ptr<DesktopFrame> frame = PrepareFrame(kSize); |
347 | 328 |
348 VideoDecoderTester decoder_tester(decoder, kSize, kSize); | 329 VideoDecoderTester decoder_tester(decoder, kSize, kSize); |
349 decoder_tester.set_strict(strict); | 330 decoder_tester.set_strict(strict); |
350 decoder_tester.set_frame(frame.get()); | 331 decoder_tester.set_frame(frame.get()); |
351 encoder_tester.set_decoder_tester(&decoder_tester); | 332 encoder_tester.set_decoder_tester(&decoder_tester); |
352 | 333 |
353 std::vector<std::vector<DesktopRect> > test_rect_lists = | 334 for (const DesktopRegion& region : MakeTestRegionLists(kSize)) { |
354 MakeTestRectLists(kSize); | |
355 for (size_t i = 0; i < test_rect_lists.size(); ++i) { | |
356 const std::vector<DesktopRect> test_rects = test_rect_lists[i]; | |
357 TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, | 335 TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, |
358 frame.get(), &test_rects[0], test_rects.size()); | 336 frame.get(), region); |
359 } | 337 } |
360 } | 338 } |
361 | 339 |
362 static void FillWithGradient(DesktopFrame* frame) { | 340 static void FillWithGradient(DesktopFrame* frame) { |
363 for (int j = 0; j < frame->size().height(); ++j) { | 341 for (int j = 0; j < frame->size().height(); ++j) { |
364 uint8* p = frame->data() + j * frame->stride(); | 342 uint8* p = frame->data() + j * frame->stride(); |
365 for (int i = 0; i < frame->size().width(); ++i) { | 343 for (int i = 0; i < frame->size().width(); ++i) { |
366 *p++ = (255.0 * i) / frame->size().width(); | 344 *p++ = (255.0 * i) / frame->size().width(); |
367 *p++ = (164.0 * j) / frame->size().height(); | 345 *p++ = (164.0 * j) / frame->size().height(); |
368 *p++ = (82.0 * (i + j)) / | 346 *p++ = (82.0 * (i + j)) / |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 | 425 |
448 if (frame_count >= kWarmUpFrameCount) { | 426 if (frame_count >= kWarmUpFrameCount) { |
449 elapsed = base::TimeTicks::Now() - start_time; | 427 elapsed = base::TimeTicks::Now() - start_time; |
450 } | 428 } |
451 } | 429 } |
452 | 430 |
453 return (frame_count * base::TimeDelta::FromSeconds(1)) / elapsed; | 431 return (frame_count * base::TimeDelta::FromSeconds(1)) / elapsed; |
454 } | 432 } |
455 | 433 |
456 } // namespace remoting | 434 } // namespace remoting |
OLD | NEW |