| 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 |