summaryrefslogtreecommitdiffstats
path: root/remoting/base
diff options
context:
space:
mode:
authorsimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-28 06:40:46 +0000
committersimonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-28 06:40:46 +0000
commit1d65f4851332253abd79619e25266e70a837e1df (patch)
tree4f3f29183106cb009ed59c4d4721ad8d8d4bf8ef /remoting/base
parentaacecdcf2253de1959ad8462443d5d5bd5d2bac5 (diff)
downloadchromium_src-1d65f4851332253abd79619e25266e70a837e1df.zip
chromium_src-1d65f4851332253abd79619e25266e70a837e1df.tar.gz
chromium_src-1d65f4851332253abd79619e25266e70a837e1df.tar.bz2
[Chromoting] Add unit tests for up- and down-scaling.
Review URL: https://chromiumcodereview.appspot.com/10828058 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148888 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/base')
-rw-r--r--remoting/base/codec_test.cc172
-rw-r--r--remoting/base/codec_test.h7
-rw-r--r--remoting/base/decoder_vp8_unittest.cc62
3 files changed, 164 insertions, 77 deletions
diff --git a/remoting/base/codec_test.cc b/remoting/base/codec_test.cc
index 5a67ba0..6813c66 100644
--- a/remoting/base/codec_test.cc
+++ b/remoting/base/codec_test.cc
@@ -16,18 +16,31 @@
#include "remoting/base/util.h"
#include "testing/gtest/include/gtest/gtest.h"
-static const int kWidth = 320;
-static const int kHeight = 240;
-static const int kBytesPerPixel = 4;
+namespace {
+
+const int kBytesPerPixel = 4;
// Some sample rects for testing.
-static const SkIRect kTestRects[] = {
- SkIRect::MakeXYWH(0, 0, kWidth, kHeight),
- SkIRect::MakeXYWH(0, 0, kWidth / 2, kHeight / 2),
- SkIRect::MakeXYWH(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2),
- SkIRect::MakeXYWH(16, 16, 16, 16),
- SkIRect::MakeXYWH(128, 64, 32, 32),
-};
+std::vector<std::vector<SkIRect> > MakeTestRectLists(const SkISize& size) {
+ std::vector<std::vector<SkIRect> > rect_lists;
+ std::vector<SkIRect> rects;
+ rects.push_back(SkIRect::MakeXYWH(0, 0, size.width(), size.height()));
+ rect_lists.push_back(rects);
+ rects.clear();
+ rects.push_back(SkIRect::MakeXYWH(0, 0, size.width() / 2, size.height() / 2));
+ rect_lists.push_back(rects);
+ rects.clear();
+ rects.push_back(SkIRect::MakeXYWH(size.width() / 2, size.height() / 2,
+ size.width() / 2, size.height() / 2));
+ rect_lists.push_back(rects);
+ rects.clear();
+ rects.push_back(SkIRect::MakeXYWH(16, 16, 16, 16));
+ rects.push_back(SkIRect::MakeXYWH(128, 64, 32, 32));
+ rect_lists.push_back(rects);
+ return rect_lists;
+}
+
+} // namespace
namespace remoting {
@@ -120,12 +133,16 @@ class EncoderMessageTester {
class DecoderTester {
public:
- DecoderTester(Decoder* decoder)
- : strict_(false),
+ DecoderTester(Decoder* decoder, const SkISize& screen_size,
+ const SkISize& view_size)
+ : screen_size_(screen_size),
+ view_size_(view_size),
+ strict_(false),
decoder_(decoder) {
- image_data_.reset(new uint8[kWidth * kHeight * kBytesPerPixel]);
+ image_data_.reset(new uint8[
+ view_size_.width() * view_size_.height() * kBytesPerPixel]);
EXPECT_TRUE(image_data_.get());
- decoder_->Initialize(SkISize::Make(kWidth, kHeight));
+ decoder_->Initialize(screen_size_);
}
void Reset() {
@@ -133,20 +150,29 @@ class DecoderTester {
update_region_.setEmpty();
}
+ void ResetRenderedData() {
+ memset(image_data_.get(), 0,
+ view_size_.width() * view_size_.height() * kBytesPerPixel);
+ }
+
void ReceivedPacket(VideoPacket* packet) {
Decoder::DecodeResult result = decoder_->DecodePacket(packet);
ASSERT_NE(Decoder::DECODE_ERROR, result);
if (result == Decoder::DECODE_DONE) {
- decoder_->RenderFrame(SkISize::Make(kWidth, kHeight),
- SkIRect::MakeXYWH(0, 0, kWidth, kHeight),
- image_data_.get(),
- kWidth * kBytesPerPixel,
- &update_region_);
+ RenderFrame();
}
}
+ void RenderFrame() {
+ decoder_->RenderFrame(view_size_,
+ SkIRect::MakeSize(view_size_),
+ image_data_.get(),
+ view_size_.width() * kBytesPerPixel,
+ &update_region_);
+ }
+
void ReceivedScopedPacket(scoped_ptr<VideoPacket> packet) {
ReceivedPacket(packet.get());
}
@@ -178,7 +204,7 @@ class DecoderTester {
// Test the content of the update region.
EXPECT_EQ(expected_region_, update_region_);
for (SkRegion::Iterator i(update_region_); !i.done(); i.next()) {
- const int stride = kWidth * kBytesPerPixel;
+ const int stride = view_size_.width() * kBytesPerPixel;
EXPECT_EQ(stride, capture_data_->data_planes().strides[0]);
const int offset = stride * i.rect().top() +
kBytesPerPixel * i.rect().left();
@@ -197,29 +223,25 @@ 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_);
+void VerifyResultsApprox(const uint8* expected_view_data,
+ double max_error_limit, double mean_error_limit) {
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 stride = view_size_.width() * kBytesPerPixel;
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;
+ const uint8* expected = expected_view_data + offset;
+ const uint8* actual = 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);
+ double error = CalculateError(expected, actual);
max_error = std::max(max_error, error);
sum_error += error;
++error_num;
- original += 4;
- decoded += 4;
+ expected += 4;
+ actual += 4;
}
}
}
@@ -244,6 +266,8 @@ class DecoderTester {
}
private:
+ SkISize screen_size_;
+ SkISize view_size_;
bool strict_;
SkRegion expected_region_;
SkRegion update_region_;
@@ -294,15 +318,16 @@ class EncoderTester {
DISALLOW_COPY_AND_ASSIGN(EncoderTester);
};
-scoped_refptr<CaptureData> PrepareEncodeData(media::VideoFrame::Format format,
+scoped_refptr<CaptureData> PrepareEncodeData(const SkISize& size,
+ media::VideoFrame::Format format,
uint8** memory) {
// TODO(hclam): Support also YUV format.
CHECK_EQ(format, media::VideoFrame::RGB32);
- int size = kWidth * kHeight * kBytesPerPixel;
+ int memory_size = size.width() * size.height() * kBytesPerPixel;
- *memory = new uint8[size];
+ *memory = new uint8[memory_size];
srand(0);
- for (int i = 0; i < size; ++i) {
+ for (int i = 0; i < memory_size; ++i) {
(*memory)[i] = rand() % 256;
}
@@ -310,10 +335,10 @@ scoped_refptr<CaptureData> PrepareEncodeData(media::VideoFrame::Format format,
memset(planes.data, 0, sizeof(planes.data));
memset(planes.strides, 0, sizeof(planes.strides));
planes.data[0] = *memory;
- planes.strides[0] = kWidth * kBytesPerPixel;
+ planes.strides[0] = size.width() * kBytesPerPixel;
scoped_refptr<CaptureData> data =
- new CaptureData(planes, SkISize::Make(kWidth, kHeight), format);
+ new CaptureData(planes, size, format);
return data;
}
@@ -332,6 +357,8 @@ static void TestEncodingRects(Encoder* encoder,
}
void TestEncoder(Encoder* encoder, bool strict) {
+ SkISize kSize = SkISize::Make(320, 240);
+
EncoderMessageTester message_tester;
message_tester.set_strict(strict);
@@ -339,13 +366,15 @@ void TestEncoder(Encoder* encoder, bool strict) {
uint8* memory;
scoped_refptr<CaptureData> data =
- PrepareEncodeData(media::VideoFrame::RGB32, &memory);
+ PrepareEncodeData(kSize, media::VideoFrame::RGB32, &memory);
scoped_array<uint8> memory_wrapper(memory);
- TestEncodingRects(encoder, &tester, data, kTestRects, 1);
- TestEncodingRects(encoder, &tester, data, kTestRects + 1, 1);
- TestEncodingRects(encoder, &tester, data, kTestRects + 2, 1);
- TestEncodingRects(encoder, &tester, data, kTestRects + 3, 2);
+ std::vector<std::vector<SkIRect> > test_rect_lists = MakeTestRectLists(kSize);
+ for (size_t i = 0; i < test_rect_lists.size(); ++i) {
+ const std::vector<SkIRect>& test_rects = test_rect_lists[i];
+ TestEncodingRects(encoder, &tester, data,
+ &test_rects[0], test_rects.size());
+ }
}
static void TestEncodeDecodeRects(Encoder* encoder,
@@ -380,6 +409,8 @@ static void TestEncodeDecodeRects(Encoder* encoder,
}
void TestEncoderDecoder(Encoder* encoder, Decoder* decoder, bool strict) {
+ SkISize kSize = SkISize::Make(320, 240);
+
EncoderMessageTester message_tester;
message_tester.set_strict(strict);
@@ -387,22 +418,20 @@ void TestEncoderDecoder(Encoder* encoder, Decoder* decoder, bool strict) {
uint8* memory;
scoped_refptr<CaptureData> data =
- PrepareEncodeData(media::VideoFrame::RGB32, &memory);
+ PrepareEncodeData(kSize, media::VideoFrame::RGB32, &memory);
scoped_array<uint8> memory_wrapper(memory);
- DecoderTester decoder_tester(decoder);
+ DecoderTester decoder_tester(decoder, kSize, kSize);
decoder_tester.set_strict(strict);
decoder_tester.set_capture_data(data);
encoder_tester.set_decoder_tester(&decoder_tester);
- TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
- kTestRects, 1);
- TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
- kTestRects + 1, 1);
- TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
- kTestRects + 2, 1);
- TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
- kTestRects + 3, 2);
+ std::vector<std::vector<SkIRect> > test_rect_lists = MakeTestRectLists(kSize);
+ for (size_t i = 0; i < test_rect_lists.size(); ++i) {
+ const std::vector<SkIRect> test_rects = test_rect_lists[i];
+ TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
+ &test_rects[0], test_rects.size());
+ }
}
static void FillWithGradient(uint8* memory, const SkISize& frame_size,
@@ -421,25 +450,31 @@ static void FillWithGradient(uint8* memory, const SkISize& frame_size,
void TestEncoderDecoderGradient(Encoder* encoder,
Decoder* decoder,
+ const SkISize& screen_size,
+ const SkISize& view_size,
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);
+ SkIRect screen_rect = SkIRect::MakeSize(screen_size);
+ scoped_array<uint8> screen_data(new uint8[
+ screen_size.width() * screen_size.height() * kBytesPerPixel]);
+ FillWithGradient(screen_data.get(), screen_size, screen_rect);
+
+ SkIRect view_rect = SkIRect::MakeSize(view_size);
+ scoped_array<uint8> expected_view_data(new uint8[
+ view_size.width() * view_size.height() * kBytesPerPixel]);
+ FillWithGradient(expected_view_data.get(), view_size, view_rect);
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;
+ planes.data[0] = screen_data.get();
+ planes.strides[0] = screen_size.width() * 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);
+ new CaptureData(planes, screen_size, media::VideoFrame::RGB32);
+ capture_data->mutable_dirty_region().op(screen_rect, SkRegion::kUnion_Op);
- DecoderTester decoder_tester(decoder);
+ DecoderTester decoder_tester(decoder, screen_size, view_size);
decoder_tester.set_capture_data(capture_data);
decoder_tester.AddRegion(capture_data->dirty_region());
@@ -447,7 +482,16 @@ void TestEncoderDecoderGradient(Encoder* encoder,
base::Bind(&DecoderTester::ReceivedScopedPacket,
base::Unretained(&decoder_tester)));
- decoder_tester.VerifyResultsApprox(max_error_limit, mean_error_limit);
+ decoder_tester.VerifyResultsApprox(expected_view_data.get(),
+ max_error_limit, mean_error_limit);
+
+ // Check that the decoder correctly re-renders the frame if its client
+ // invalidates the frame.
+ decoder_tester.ResetRenderedData();
+ decoder->Invalidate(view_size, SkRegion(view_rect));
+ decoder_tester.RenderFrame();
+ decoder_tester.VerifyResultsApprox(expected_view_data.get(),
+ max_error_limit, mean_error_limit);
}
} // namespace remoting
diff --git a/remoting/base/codec_test.h b/remoting/base/codec_test.h
index 004fbfb..ba71dad 100644
--- a/remoting/base/codec_test.h
+++ b/remoting/base/codec_test.h
@@ -14,11 +14,6 @@ namespace remoting {
class Decoder;
class Encoder;
-// Prepare testing data for encoding. Memory created is written to |memory|.
-// Returns randomly generated data in CaptureData.
-scoped_refptr<CaptureData> PrepareEncodeData(media::VideoFrame::Format format,
- uint8** memory);
-
// Generate test data and test the encoder for a regular encoding sequence.
// This will test encoder test and the sequence of messages sent.
//
@@ -35,6 +30,8 @@ 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,
+ const SkISize& screen_size,
+ const SkISize& view_size,
double max_error_limit,
double mean_error_limit);
diff --git a/remoting/base/decoder_vp8_unittest.cc b/remoting/base/decoder_vp8_unittest.cc
index e750714..ab0607f 100644
--- a/remoting/base/decoder_vp8_unittest.cc
+++ b/remoting/base/decoder_vp8_unittest.cc
@@ -10,19 +10,65 @@
namespace remoting {
-TEST(DecoderVp8Test, EncodeAndDecode) {
- EncoderVp8 encoder;
- DecoderVp8 decoder;
- TestEncoderDecoder(&encoder, &decoder, false);
+class DecoderVp8Test : public testing::Test {
+ protected:
+ EncoderVp8 encoder_;
+ DecoderVp8 decoder_;
+
+ void TestGradient(int screen_width, int screen_height,
+ int view_width, int view_height,
+ double max_error_limit, double mean_error_limit) {
+ TestEncoderDecoderGradient(&encoder_, &decoder_,
+ SkISize::Make(screen_width, screen_height),
+ SkISize::Make(view_width, view_height),
+ max_error_limit, mean_error_limit);
+ }
+};
+
+TEST_F(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);
+TEST_F(DecoderVp8Test, Gradient) {
+ TestGradient(320, 240, 320, 240, 0.03, 0.01);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleUpEvenToEven) {
+ TestGradient(320, 240, 640, 480, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleUpEvenToOdd) {
+ TestGradient(320, 240, 641, 481, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleUpOddToEven) {
+ TestGradient(321, 241, 640, 480, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleUpOddToOdd) {
+ TestGradient(321, 241, 641, 481, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleDownEvenToEven) {
+ TestGradient(320, 240, 160, 120, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleDownEvenToOdd) {
+ // TODO(simonmorris): The maximum error is non-deterministic.
+ // The mean error is not too high, which suggests that the problem is
+ // restricted to a small area of the output image. See crbug.com/139437.
+ TestGradient(320, 240, 161, 121, 1.0, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleDownOddToEven) {
+ TestGradient(321, 241, 160, 120, 0.04, 0.02);
+}
+
+TEST_F(DecoderVp8Test, GradientScaleDownOddToOdd) {
+ TestGradient(321, 241, 161, 121, 0.04, 0.02);
}
} // namespace remoting