blob: f0c98140e59ea3d4acaf1dc34c5973c001667adb [file] [log] [blame]
[email protected]a9c88d12012-01-29 03:45:171// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]fb13c762010-07-24 02:22:072// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dcheng0765c492016-04-06 22:41:535#include "remoting/codec/codec_test.h"
6
avi5a080f012015-12-22 23:15:437#include <stddef.h>
8#include <stdint.h>
[email protected]fb13c762010-07-24 02:22:079#include <stdlib.h>
sergeyu42ad7c02015-12-24 00:20:5110
dcheng0765c492016-04-06 22:41:5311#include <memory>
sergeyu42ad7c02015-12-24 00:20:5112#include <utility>
[email protected]fb13c762010-07-24 02:22:0713
[email protected]1e1cb3b2011-11-10 02:07:4114#include "base/bind.h"
15#include "base/logging.h"
avi5a080f012015-12-22 23:15:4316#include "base/macros.h"
sergeyuef92de202015-08-20 22:47:3717#include "remoting/base/util.h"
[email protected]38609832012-08-23 01:36:1018#include "remoting/codec/video_decoder.h"
19#include "remoting/codec/video_encoder.h"
sergeyuef92de202015-08-20 22:47:3720#include "remoting/proto/video.pb.h"
[email protected]fb13c762010-07-24 02:22:0721#include "testing/gtest/include/gtest/gtest.h"
[email protected]b9ed58f2013-05-16 10:45:2422#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
23
[email protected]c5a0f6012014-07-01 06:44:3424using webrtc::BasicDesktopFrame;
25using webrtc::DesktopFrame;
[email protected]b9ed58f2013-05-16 10:45:2426using webrtc::DesktopRect;
[email protected]f301d7362013-06-05 00:02:0227using webrtc::DesktopRegion;
[email protected]b9ed58f2013-05-16 10:45:2428using webrtc::DesktopSize;
[email protected]fb13c762010-07-24 02:22:0729
[email protected]1d65f482012-07-28 06:40:4630namespace {
31
32const int kBytesPerPixel = 4;
[email protected]fb13c762010-07-24 02:22:0733
34// Some sample rects for testing.
sergeyufc59cb42015-07-30 22:19:2535std::vector<DesktopRegion> MakeTestRegionLists(DesktopSize size) {
36 std::vector<DesktopRegion> region_lists;
37 DesktopRegion region;
38 region.AddRect(DesktopRect::MakeXYWH(0, 0, size.width(), size.height()));
39 region_lists.push_back(region);
40 region.Clear();
41 region.AddRect(
42 DesktopRect::MakeXYWH(0, 0, size.width() / 2, size.height() / 2));
43 region_lists.push_back(region);
44 region.Clear();
45 region.AddRect(DesktopRect::MakeXYWH(size.width() / 2, size.height() / 2,
46 size.width() / 2, size.height() / 2));
47 region_lists.push_back(region);
48 region.Clear();
49 region.AddRect(DesktopRect::MakeXYWH(16, 16, 16, 16));
50 region.AddRect(DesktopRect::MakeXYWH(32, 32, 32, 32));
51 region.IntersectWith(DesktopRect::MakeSize(size));
52 region_lists.push_back(region);
53 return region_lists;
[email protected]1d65f482012-07-28 06:40:4654}
55
56} // namespace
[email protected]fb13c762010-07-24 02:22:0757
58namespace remoting {
59
[email protected]d9004e42012-08-24 01:47:3760class VideoDecoderTester {
[email protected]fb13c762010-07-24 02:22:0761 public:
sergeyuef92de202015-08-20 22:47:3762 VideoDecoderTester(VideoDecoder* decoder, const DesktopSize& screen_size)
63 : strict_(false),
[email protected]a3c1d452013-08-21 18:51:4064 decoder_(decoder),
sergeyuef92de202015-08-20 22:47:3765 frame_(new BasicDesktopFrame(screen_size)),
66 expected_frame_(nullptr) {}
[email protected]fb13c762010-07-24 02:22:0767
[email protected]137e58f12010-12-07 19:35:4368 void Reset() {
sergeyuef92de202015-08-20 22:47:3769 frame_.reset(new BasicDesktopFrame(frame_->size()));
[email protected]b9ed58f2013-05-16 10:45:2470 expected_region_.Clear();
[email protected]137e58f12010-12-07 19:35:4371 }
[email protected]cee5dba2010-12-07 03:19:4872
[email protected]1d65f482012-07-28 06:40:4673 void ResetRenderedData() {
sergeyuef92de202015-08-20 22:47:3774 memset(frame_->data(), 0,
75 frame_->size().width() * frame_->size().height() * kBytesPerPixel);
[email protected]1d65f482012-07-28 06:40:4676 }
77
dcheng0765c492016-04-06 22:41:5378 void ReceivedPacket(std::unique_ptr<VideoPacket> packet) {
sergeyuef92de202015-08-20 22:47:3779 ASSERT_TRUE(decoder_->DecodePacket(*packet, frame_.get()));
[email protected]36b967f2012-07-27 18:35:3280 }
81
[email protected]fb13c762010-07-24 02:22:0782 void set_strict(bool strict) {
83 strict_ = strict;
84 }
85
sergeyuef92de202015-08-20 22:47:3786 void set_expected_frame(DesktopFrame* frame) {
87 expected_frame_ = frame;
[email protected]fb13c762010-07-24 02:22:0788 }
89
[email protected]c5a0f6012014-07-01 06:44:3490 void AddRegion(const DesktopRegion& region) {
[email protected]b9ed58f2013-05-16 10:45:2491 expected_region_.AddRegion(region);
[email protected]fb13c762010-07-24 02:22:0792 }
93
[email protected]137e58f12010-12-07 19:35:4394 void VerifyResults() {
[email protected]fb13c762010-07-24 02:22:0795 if (!strict_)
96 return;
[email protected]66db1af92010-07-27 01:42:4697
sergeyuef92de202015-08-20 22:47:3798 ASSERT_TRUE(expected_frame_);
[email protected]137e58f12010-12-07 19:35:4399
[email protected]a9c88d12012-01-29 03:45:17100 // Test the content of the update region.
sergeyuef92de202015-08-20 22:47:37101 EXPECT_TRUE(expected_region_.Equals(frame_->updated_region()));
[email protected]b9ed58f2013-05-16 10:45:24102
sergeyuef92de202015-08-20 22:47:37103 for (DesktopRegion::Iterator i(frame_->updated_region()); !i.IsAtEnd();
[email protected]e59d6592013-09-25 22:16:21104 i.Advance()) {
sergeyuef92de202015-08-20 22:47:37105 const uint8_t* original =
106 expected_frame_->GetFrameDataAtPos(i.rect().top_left());
107 const uint8_t* decoded =
108 frame_->GetFrameDataAtPos(i.rect().top_left());
[email protected]a9c88d12012-01-29 03:45:17109 const int row_size = kBytesPerPixel * i.rect().width();
110 for (int y = 0; y < i.rect().height(); ++y) {
[email protected]66db1af92010-07-27 01:42:46111 EXPECT_EQ(0, memcmp(original, decoded, row_size))
112 << "Row " << y << " is different";
sergeyuef92de202015-08-20 22:47:37113 original += expected_frame_->stride();
114 decoded += frame_->stride();
[email protected]66db1af92010-07-27 01:42:46115 }
[email protected]fb13c762010-07-24 02:22:07116 }
117 }
118
[email protected]36b967f2012-07-27 18:35:32119 // The error at each pixel is the root mean square of the errors in
120 // the R, G, and B components, each normalized to [0, 1]. This routine
121 // checks that the maximum and mean pixel errors do not exceed given limits.
sergeyuef92de202015-08-20 22:47:37122 void VerifyResultsApprox(double max_error_limit, double mean_error_limit) {
[email protected]36b967f2012-07-27 18:35:32123 double max_error = 0.0;
124 double sum_error = 0.0;
125 int error_num = 0;
sergeyuef92de202015-08-20 22:47:37126 for (DesktopRegion::Iterator i(frame_->updated_region()); !i.IsAtEnd();
[email protected]e59d6592013-09-25 22:16:21127 i.Advance()) {
sergeyuef92de202015-08-20 22:47:37128 const uint8_t* expected =
129 expected_frame_->GetFrameDataAtPos(i.rect().top_left());
130 const uint8_t* actual =
131 frame_->GetFrameDataAtPos(i.rect().top_left());
[email protected]36b967f2012-07-27 18:35:32132 for (int y = 0; y < i.rect().height(); ++y) {
133 for (int x = 0; x < i.rect().width(); ++x) {
sergeyuef92de202015-08-20 22:47:37134 double error = CalculateError(expected + x * kBytesPerPixel,
135 actual + x * kBytesPerPixel);
[email protected]36b967f2012-07-27 18:35:32136 max_error = std::max(max_error, error);
137 sum_error += error;
138 ++error_num;
[email protected]36b967f2012-07-27 18:35:32139 }
sergeyuef92de202015-08-20 22:47:37140 expected += expected_frame_->stride();
141 actual += frame_->stride();
[email protected]36b967f2012-07-27 18:35:32142 }
143 }
144 EXPECT_LE(max_error, max_error_limit);
145 double mean_error = sum_error / error_num;
146 EXPECT_LE(mean_error, mean_error_limit);
[email protected]5cbe3cf2013-11-25 17:05:04147 VLOG(0) << "Max error: " << max_error;
148 VLOG(0) << "Mean error: " << mean_error;
[email protected]36b967f2012-07-27 18:35:32149 }
150
sergeyuef92de202015-08-20 22:47:37151 double CalculateError(const uint8_t* original, const uint8_t* decoded) {
[email protected]36b967f2012-07-27 18:35:32152 double error_sum_squares = 0.0;
153 for (int i = 0; i < 3; i++) {
154 double error = static_cast<double>(*original++) -
155 static_cast<double>(*decoded++);
156 error /= 255.0;
157 error_sum_squares += error * error;
158 }
159 original++;
160 decoded++;
161 return sqrt(error_sum_squares / 3.0);
162 }
163
[email protected]137e58f12010-12-07 19:35:43164 private:
[email protected]fb13c762010-07-24 02:22:07165 bool strict_;
[email protected]c5a0f6012014-07-01 06:44:34166 DesktopRegion expected_region_;
[email protected]d9004e42012-08-24 01:47:37167 VideoDecoder* decoder_;
dcheng0765c492016-04-06 22:41:53168 std::unique_ptr<DesktopFrame> frame_;
sergeyuef92de202015-08-20 22:47:37169 DesktopFrame* expected_frame_;
[email protected]fb13c762010-07-24 02:22:07170
[email protected]d9004e42012-08-24 01:47:37171 DISALLOW_COPY_AND_ASSIGN(VideoDecoderTester);
[email protected]fb13c762010-07-24 02:22:07172};
173
[email protected]92b45b8e2012-08-24 19:46:47174// The VideoEncoderTester provides a hook for retrieving the data, and passing
175// the message to other subprograms for validaton.
176class VideoEncoderTester {
[email protected]fb13c762010-07-24 02:22:07177 public:
wez070889b2015-07-17 03:19:15178 VideoEncoderTester() : decoder_tester_(nullptr), data_available_(0) {}
[email protected]fb13c762010-07-24 02:22:07179
[email protected]92b45b8e2012-08-24 19:46:47180 ~VideoEncoderTester() {
[email protected]fb13c762010-07-24 02:22:07181 EXPECT_GT(data_available_, 0);
182 }
183
dcheng0765c492016-04-06 22:41:53184 void DataAvailable(std::unique_ptr<VideoPacket> packet) {
[email protected]fb13c762010-07-24 02:22:07185 ++data_available_;
[email protected]d9004e42012-08-24 01:47:37186 // Send the message to the VideoDecoderTester.
[email protected]fb13c762010-07-24 02:22:07187 if (decoder_tester_) {
sergeyu42ad7c02015-12-24 00:20:51188 decoder_tester_->ReceivedPacket(std::move(packet));
[email protected]cee5dba2010-12-07 03:19:48189 }
[email protected]fb13c762010-07-24 02:22:07190 }
191
[email protected]d9004e42012-08-24 01:47:37192 void set_decoder_tester(VideoDecoderTester* decoder_tester) {
[email protected]fb13c762010-07-24 02:22:07193 decoder_tester_ = decoder_tester;
194 }
195
196 private:
[email protected]d9004e42012-08-24 01:47:37197 VideoDecoderTester* decoder_tester_;
[email protected]fb13c762010-07-24 02:22:07198 int data_available_;
199
[email protected]92b45b8e2012-08-24 19:46:47200 DISALLOW_COPY_AND_ASSIGN(VideoEncoderTester);
[email protected]fb13c762010-07-24 02:22:07201};
202
dcheng0765c492016-04-06 22:41:53203std::unique_ptr<DesktopFrame> PrepareFrame(const DesktopSize& size) {
204 std::unique_ptr<DesktopFrame> frame(new BasicDesktopFrame(size));
[email protected]04499fb2012-08-25 00:33:50205
[email protected]fb13c762010-07-24 02:22:07206 srand(0);
[email protected]b9ed58f2013-05-16 10:45:24207 int memory_size = size.width() * size.height() * kBytesPerPixel;
[email protected]1d65f482012-07-28 06:40:46208 for (int i = 0; i < memory_size; ++i) {
[email protected]b9ed58f2013-05-16 10:45:24209 frame->data()[i] = rand() % 256;
[email protected]fb13c762010-07-24 02:22:07210 }
211
sergeyu42ad7c02015-12-24 00:20:51212 return frame;
[email protected]fb13c762010-07-24 02:22:07213}
214
[email protected]92b45b8e2012-08-24 19:46:47215static void TestEncodingRects(VideoEncoder* encoder,
216 VideoEncoderTester* tester,
wez43ac2662015-06-10 18:22:29217 DesktopFrame* frame,
sergeyufc59cb42015-07-30 22:19:25218 const DesktopRegion& region) {
219 *frame->mutable_updated_region() = region;
sergeyu2becb6012016-09-13 18:41:32220 tester->DataAvailable(encoder->Encode(*frame));
[email protected]fb13c762010-07-24 02:22:07221}
222
[email protected]92b45b8e2012-08-24 19:46:47223void TestVideoEncoder(VideoEncoder* encoder, bool strict) {
sergeyufc59cb42015-07-30 22:19:25224 const int kSizes[] = {80, 79, 77, 54};
[email protected]1d65f482012-07-28 06:40:46225
[email protected]8b6d3d02013-09-13 22:43:41226 VideoEncoderTester tester;
[email protected]fb13c762010-07-24 02:22:07227
[email protected]8c6d71d2012-10-23 21:20:04228 for (size_t xi = 0; xi < arraysize(kSizes); ++xi) {
229 for (size_t yi = 0; yi < arraysize(kSizes); ++yi) {
sergeyufc59cb42015-07-30 22:19:25230 DesktopSize size(kSizes[xi], kSizes[yi]);
dcheng0765c492016-04-06 22:41:53231 std::unique_ptr<DesktopFrame> frame = PrepareFrame(size);
sergeyufc59cb42015-07-30 22:19:25232 for (const DesktopRegion& region : MakeTestRegionLists(size)) {
233 TestEncodingRects(encoder, &tester, frame.get(), region);
[email protected]8c6d71d2012-10-23 21:20:04234 }
wez43ac2662015-06-10 18:22:29235
236 // Pass some empty frames through the encoder.
sergeyufc59cb42015-07-30 22:19:25237 for (int i = 0; i < 5; ++i) {
238 TestEncodingRects(encoder, &tester, frame.get(), DesktopRegion());
wez43ac2662015-06-10 18:22:29239 }
[email protected]8c6d71d2012-10-23 21:20:04240 }
[email protected]1d65f482012-07-28 06:40:46241 }
[email protected]fb13c762010-07-24 02:22:07242}
243
wez9242f6c2015-07-10 21:43:33244void TestVideoEncoderEmptyFrames(VideoEncoder* encoder,
245 int max_topoff_frames) {
sergeyufc59cb42015-07-30 22:19:25246 const DesktopSize kSize(100, 100);
dcheng0765c492016-04-06 22:41:53247 std::unique_ptr<DesktopFrame> frame(PrepareFrame(kSize));
wez43ac2662015-06-10 18:22:29248
249 frame->mutable_updated_region()->SetRect(
250 webrtc::DesktopRect::MakeSize(kSize));
sergeyu2becb6012016-09-13 18:41:32251 EXPECT_TRUE(encoder->Encode(*frame));
wez43ac2662015-06-10 18:22:29252
wez9242f6c2015-07-10 21:43:33253 int topoff_frames = 0;
wez43ac2662015-06-10 18:22:29254 frame->mutable_updated_region()->Clear();
wez9242f6c2015-07-10 21:43:33255 for (int i = 0; i < max_topoff_frames + 1; ++i) {
sergeyu2becb6012016-09-13 18:41:32256 if (!encoder->Encode(*frame))
wez9242f6c2015-07-10 21:43:33257 break;
258 topoff_frames++;
wez43ac2662015-06-10 18:22:29259 }
260
wez9242f6c2015-07-10 21:43:33261 // If top-off is enabled then our random frame contents should always
262 // trigger it, so expect at least one top-off frame - strictly, though,
263 // an encoder may not always need to top-off.
264 EXPECT_GE(topoff_frames, max_topoff_frames ? 1 : 0);
265 EXPECT_LE(topoff_frames, max_topoff_frames);
wez43ac2662015-06-10 18:22:29266}
267
[email protected]92b45b8e2012-08-24 19:46:47268static void TestEncodeDecodeRects(VideoEncoder* encoder,
269 VideoEncoderTester* encoder_tester,
[email protected]d9004e42012-08-24 01:47:37270 VideoDecoderTester* decoder_tester,
[email protected]c5a0f6012014-07-01 06:44:34271 DesktopFrame* frame,
sergeyufc59cb42015-07-30 22:19:25272 const DesktopRegion& region) {
273 *frame->mutable_updated_region() = region;
274 decoder_tester->AddRegion(region);
[email protected]fb13c762010-07-24 02:22:07275
[email protected]a9c88d12012-01-29 03:45:17276 // Generate random data for the updated region.
[email protected]66db1af92010-07-27 01:42:46277 srand(0);
sergeyufc59cb42015-07-30 22:19:25278 for (DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
279 const int row_size = DesktopFrame::kBytesPerPixel * i.rect().width();
sergeyuef92de202015-08-20 22:47:37280 uint8_t* memory = frame->data() + frame->stride() * i.rect().top() +
sergeyufc59cb42015-07-30 22:19:25281 DesktopFrame::kBytesPerPixel * i.rect().left();
282 for (int y = 0; y < i.rect().height(); ++y) {
[email protected]66db1af92010-07-27 01:42:46283 for (int x = 0; x < row_size; ++x)
284 memory[x] = rand() % 256;
[email protected]b9ed58f2013-05-16 10:45:24285 memory += frame->stride();
[email protected]66db1af92010-07-27 01:42:46286 }
287 }
288
sergeyu2becb6012016-09-13 18:41:32289 encoder_tester->DataAvailable(encoder->Encode(*frame));
[email protected]137e58f12010-12-07 19:35:43290 decoder_tester->VerifyResults();
291 decoder_tester->Reset();
[email protected]fb13c762010-07-24 02:22:07292}
293
sergeyufc59cb42015-07-30 22:19:25294void TestVideoEncoderDecoder(VideoEncoder* encoder,
295 VideoDecoder* decoder,
296 bool strict) {
297 DesktopSize kSize = DesktopSize(160, 120);
[email protected]1d65f482012-07-28 06:40:46298
[email protected]8b6d3d02013-09-13 22:43:41299 VideoEncoderTester encoder_tester;
[email protected]fb13c762010-07-24 02:22:07300
dcheng0765c492016-04-06 22:41:53301 std::unique_ptr<DesktopFrame> frame = PrepareFrame(kSize);
[email protected]dc454a7c2011-08-12 22:01:13302
sergeyuef92de202015-08-20 22:47:37303 VideoDecoderTester decoder_tester(decoder, kSize);
[email protected]fb13c762010-07-24 02:22:07304 decoder_tester.set_strict(strict);
sergeyuef92de202015-08-20 22:47:37305 decoder_tester.set_expected_frame(frame.get());
[email protected]fb13c762010-07-24 02:22:07306 encoder_tester.set_decoder_tester(&decoder_tester);
307
sergeyufc59cb42015-07-30 22:19:25308 for (const DesktopRegion& region : MakeTestRegionLists(kSize)) {
[email protected]b9ed58f2013-05-16 10:45:24309 TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester,
sergeyufc59cb42015-07-30 22:19:25310 frame.get(), region);
[email protected]1d65f482012-07-28 06:40:46311 }
[email protected]fb13c762010-07-24 02:22:07312}
313
[email protected]c5a0f6012014-07-01 06:44:34314static void FillWithGradient(DesktopFrame* frame) {
[email protected]b9ed58f2013-05-16 10:45:24315 for (int j = 0; j < frame->size().height(); ++j) {
sergeyuef92de202015-08-20 22:47:37316 uint8_t* p = frame->data() + j * frame->stride();
[email protected]b9ed58f2013-05-16 10:45:24317 for (int i = 0; i < frame->size().width(); ++i) {
318 *p++ = (255.0 * i) / frame->size().width();
319 *p++ = (164.0 * j) / frame->size().height();
320 *p++ = (82.0 * (i + j)) /
321 (frame->size().width() + frame->size().height());
[email protected]36b967f2012-07-27 18:35:32322 *p++ = 0;
323 }
324 }
325}
326
[email protected]92b45b8e2012-08-24 19:46:47327void TestVideoEncoderDecoderGradient(VideoEncoder* encoder,
328 VideoDecoder* decoder,
[email protected]b9ed58f2013-05-16 10:45:24329 const DesktopSize& screen_size,
[email protected]92b45b8e2012-08-24 19:46:47330 double max_error_limit,
331 double mean_error_limit) {
dcheng0765c492016-04-06 22:41:53332 std::unique_ptr<BasicDesktopFrame> frame(new BasicDesktopFrame(screen_size));
[email protected]b9ed58f2013-05-16 10:45:24333 FillWithGradient(frame.get());
334 frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(screen_size));
[email protected]1d65f482012-07-28 06:40:46335
sergeyuef92de202015-08-20 22:47:37336 VideoDecoderTester decoder_tester(decoder, screen_size);
337 decoder_tester.set_expected_frame(frame.get());
[email protected]b9ed58f2013-05-16 10:45:24338 decoder_tester.AddRegion(frame->updated_region());
sergeyu2becb6012016-09-13 18:41:32339 decoder_tester.ReceivedPacket(encoder->Encode(*frame));
[email protected]36b967f2012-07-27 18:35:32340
sergeyuef92de202015-08-20 22:47:37341 decoder_tester.VerifyResultsApprox(max_error_limit, mean_error_limit);
[email protected]36b967f2012-07-27 18:35:32342}
343
[email protected]fb13c762010-07-24 02:22:07344} // namespace remoting