summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-27 18:35:32 +0000
committersimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-27 18:35:32 +0000
commit36b967f39fcb6f6512f139a93825bb1d9251779c (patch)
tree1678ce2d0f5fe8802864231bd9943fb4d46db309 /remoting
parent80fae6304b5a162e09fee1333adefd894ebb287f (diff)
downloadchromium_src-36b967f39fcb6f6512f139a93825bb1d9251779c.zip
chromium_src-36b967f39fcb6f6512f139a93825bb1d9251779c.tar.gz
chromium_src-36b967f39fcb6f6512f139a93825bb1d9251779c.tar.bz2
[Chromoting] Add a unit test to verify that the VP8 codec doesn't change color values too much.
Review URL: https://chromiumcodereview.appspot.com/10833022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148779 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/base/codec_test.cc104
-rw-r--r--remoting/base/codec_test.h8
-rw-r--r--remoting/base/decoder_vp8_unittest.cc11
3 files changed, 120 insertions, 3 deletions
diff --git a/remoting/base/codec_test.cc b/remoting/base/codec_test.cc
index 381fdf4..5a67ba0 100644
--- a/remoting/base/codec_test.cc
+++ b/remoting/base/codec_test.cc
@@ -147,6 +147,10 @@ class DecoderTester {
}
}
+ void ReceivedScopedPacket(scoped_ptr<VideoPacket> packet) {
+ ReceivedPacket(packet.get());
+ }
+
void set_strict(bool strict) {
strict_ = strict;
}
@@ -158,7 +162,11 @@ class DecoderTester {
void AddRects(const SkIRect* rects, int count) {
SkRegion new_rects;
new_rects.setRects(rects, count);
- expected_region_.op(new_rects, SkRegion::kUnion_Op);
+ AddRegion(new_rects);
+ }
+
+ void AddRegion(const SkRegion& region) {
+ expected_region_.op(region, SkRegion::kUnion_Op);
}
void VerifyResults() {
@@ -186,6 +194,55 @@ class DecoderTester {
}
}
+ // The error at each pixel is the root mean square of the errors in
+ // the R, G, and B components, each normalized to [0, 1]. This routine
+ // checks that the maximum and mean pixel errors do not exceed given limits.
+ void VerifyResultsApprox(double max_error_limit, double mean_error_limit) {
+ ASSERT_TRUE(capture_data_.get());
+
+ // Test the content of the update region.
+ EXPECT_EQ(expected_region_, update_region_);
+ double max_error = 0.0;
+ double sum_error = 0.0;
+ int error_num = 0;
+ for (SkRegion::Iterator i(update_region_); !i.done(); i.next()) {
+ const int stride = kWidth * kBytesPerPixel;
+ EXPECT_EQ(stride, capture_data_->data_planes().strides[0]);
+ const int offset = stride * i.rect().top() +
+ kBytesPerPixel * i.rect().left();
+ const uint8* original = capture_data_->data_planes().data[0] + offset;
+ const uint8* decoded = image_data_.get() + offset;
+ for (int y = 0; y < i.rect().height(); ++y) {
+ for (int x = 0; x < i.rect().width(); ++x) {
+ double error = CalculateError(original, decoded);
+ max_error = std::max(max_error, error);
+ sum_error += error;
+ ++error_num;
+ original += 4;
+ decoded += 4;
+ }
+ }
+ }
+ EXPECT_LE(max_error, max_error_limit);
+ double mean_error = sum_error / error_num;
+ EXPECT_LE(mean_error, mean_error_limit);
+ LOG(INFO) << "Max error: " << max_error;
+ LOG(INFO) << "Mean error: " << mean_error;
+ }
+
+ double CalculateError(const uint8* original, const uint8* decoded) {
+ double error_sum_squares = 0.0;
+ for (int i = 0; i < 3; i++) {
+ double error = static_cast<double>(*original++) -
+ static_cast<double>(*decoded++);
+ error /= 255.0;
+ error_sum_squares += error * error;
+ }
+ original++;
+ decoded++;
+ return sqrt(error_sum_squares / 3.0);
+ }
+
private:
bool strict_;
SkRegion expected_region_;
@@ -348,4 +405,49 @@ void TestEncoderDecoder(Encoder* encoder, Decoder* decoder, bool strict) {
kTestRects + 3, 2);
}
+static void FillWithGradient(uint8* memory, const SkISize& frame_size,
+ const SkIRect& rect) {
+ for (int j = rect.top(); j < rect.bottom(); ++j) {
+ uint8* p = memory + ((j * frame_size.width()) + rect.left()) * 4;
+ for (int i = rect.left(); i < rect.right(); ++i) {
+ *p++ = static_cast<uint8>((255.0 * i) / frame_size.width());
+ *p++ = static_cast<uint8>((164.0 * j) / frame_size.height());
+ *p++ = static_cast<uint8>((82.0 * (i + j)) /
+ (frame_size.width() + frame_size.height()));
+ *p++ = 0;
+ }
+ }
+}
+
+void TestEncoderDecoderGradient(Encoder* encoder,
+ Decoder* decoder,
+ double max_error_limit,
+ double mean_error_limit) {
+ SkIRect full_frame = SkIRect::MakeWH(kWidth, kHeight);
+ scoped_array<uint8> frame_data(new uint8[kWidth * kHeight * kBytesPerPixel]);
+ FillWithGradient(frame_data.get(), SkISize::Make(kWidth, kHeight),
+ full_frame);
+
+ DataPlanes planes;
+ memset(planes.data, 0, sizeof(planes.data));
+ memset(planes.strides, 0, sizeof(planes.strides));
+ planes.data[0] = frame_data.get();
+ planes.strides[0] = kWidth * kBytesPerPixel;
+
+ scoped_refptr<CaptureData> capture_data =
+ new CaptureData(planes, SkISize::Make(kWidth, kHeight),
+ media::VideoFrame::RGB32);
+ capture_data->mutable_dirty_region().op(full_frame, SkRegion::kUnion_Op);
+
+ DecoderTester decoder_tester(decoder);
+ decoder_tester.set_capture_data(capture_data);
+ decoder_tester.AddRegion(capture_data->dirty_region());
+
+ encoder->Encode(capture_data, true,
+ base::Bind(&DecoderTester::ReceivedScopedPacket,
+ base::Unretained(&decoder_tester)));
+
+ decoder_tester.VerifyResultsApprox(max_error_limit, mean_error_limit);
+}
+
} // namespace remoting
diff --git a/remoting/base/codec_test.h b/remoting/base/codec_test.h
index 40f02e2..004fbfb 100644
--- a/remoting/base/codec_test.h
+++ b/remoting/base/codec_test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -32,6 +32,12 @@ void TestEncoder(Encoder* encoder, bool strict);
// are correct.
void TestEncoderDecoder(Encoder* encoder, Decoder* decoder, bool strict);
+// Generate a frame containing a gradient, and test the encoder and decoder
+// pair.
+void TestEncoderDecoderGradient(Encoder* encoder, Decoder* decoder,
+ double max_error_limit,
+ double mean_error_limit);
+
} // namespace remoting
#endif // REMOTING_BASE_CODEC_TEST_H_
diff --git a/remoting/base/decoder_vp8_unittest.cc b/remoting/base/decoder_vp8_unittest.cc
index 4cdb573..e750714 100644
--- a/remoting/base/decoder_vp8_unittest.cc
+++ b/remoting/base/decoder_vp8_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,4 +16,13 @@ TEST(DecoderVp8Test, EncodeAndDecode) {
TestEncoderDecoder(&encoder, &decoder, false);
}
+// Check that encoding and decoding a particular frame doesn't change the
+// frame too much. The frame used is a gradient, which does not contain sharp
+// transitions, so encoding lossiness should not be too high.
+TEST(DecoderVp8Test, Gradient) {
+ EncoderVp8 encoder;
+ DecoderVp8 decoder;
+ TestEncoderDecoderGradient(&encoder, &decoder, 0.03, 0.01);
+}
+
} // namespace remoting