diff options
author | simonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-28 06:40:46 +0000 |
---|---|---|
committer | simonmorris@chromium.org <simonmorris@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-28 06:40:46 +0000 |
commit | 1d65f4851332253abd79619e25266e70a837e1df (patch) | |
tree | 4f3f29183106cb009ed59c4d4721ad8d8d4bf8ef /remoting/base | |
parent | aacecdcf2253de1959ad8462443d5d5bd5d2bac5 (diff) | |
download | chromium_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.cc | 172 | ||||
-rw-r--r-- | remoting/base/codec_test.h | 7 | ||||
-rw-r--r-- | remoting/base/decoder_vp8_unittest.cc | 62 |
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 |