// 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. #include #include "remoting/base/util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkSize.h" static const int kWidth = 32 ; static const int kHeight = 24 ; static const int kBytesPerPixel = 4; static const int kYStride = kWidth; static const int kUvStride = kWidth / 2; static const int kRgbStride = kWidth * kBytesPerPixel; static const uint32 kFillColor = 0xffffff; namespace remoting { class YuvToRgbTester { public: YuvToRgbTester() { yuv_buffer_size_ = (kYStride + kUvStride) * kHeight; yuv_buffer_.reset(new uint8[yuv_buffer_size_]); yplane_ = yuv_buffer_.get(); uplane_ = yplane_ + (kYStride * kHeight); vplane_ = uplane_ + (kUvStride * kHeight / 2); rgb_buffer_size_ = kWidth * kHeight * kBytesPerPixel; rgb_buffer_.reset(new uint8[rgb_buffer_size_]); ResetYuvBuffer(); ResetRgbBuffer(); } ~YuvToRgbTester() {} void ResetYuvBuffer() { memset(yuv_buffer_.get(), 0, yuv_buffer_size_); } void ResetRgbBuffer() { memset(rgb_buffer_.get(), 0, rgb_buffer_size_); } void FillRgbBuffer(const SkIRect& rect) { uint32* ptr = reinterpret_cast( rgb_buffer_.get() + (rect.top() * kRgbStride) + (rect.left() * kBytesPerPixel)); int width = rect.width(); for (int height = rect.height(); height > 0; --height) { std::fill(ptr, ptr + width, kFillColor); ptr += kRgbStride / kBytesPerPixel; } } // Check the the desination buffer is filled within expected bounds. void CheckRgbBuffer(const SkIRect& rect) { uint32* ptr = reinterpret_cast(rgb_buffer_.get()); for (int y = 0; y < kHeight; ++y) { if (y < rect.top() || rect.bottom() <= y) { // The whole line should be intact. EXPECT_EQ((ptrdiff_t)kWidth, std::count(ptr, ptr + kWidth, 0u)); } else { // The space before the painted rectangle should be intact. EXPECT_EQ((ptrdiff_t)rect.left(), std::count(ptr, ptr + rect.left(), 0u)); // All pixels of the target rectangle should be touched. EXPECT_EQ(ptr + rect.right(), std::find(ptr + rect.left(), ptr + rect.right(), 0u)); // The space after the painted rectangle should be intact. EXPECT_EQ((ptrdiff_t)kWidth - rect.right(), std::count(ptr + rect.right(), ptr + kWidth, 0u)); } ptr += kRgbStride / kBytesPerPixel; } } void RunTest(const SkISize dest_size, const SkIRect& rect) { ASSERT_TRUE(SkIRect::MakeSize(dest_size).contains(rect)); // Reset buffers. ResetYuvBuffer(); ResetRgbBuffer(); FillRgbBuffer(rect); // RGB -> YUV ConvertRGB32ToYUVWithRect(rgb_buffer_.get(), yplane_, uplane_, vplane_, 0, 0, kWidth, kHeight, kRgbStride, kYStride, kUvStride); // Reset RGB buffer and do opposite conversion. ResetRgbBuffer(); ConvertAndScaleYUVToRGB32Rect(yplane_, uplane_, vplane_, kYStride, kUvStride, SkISize::Make(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight), rgb_buffer_.get(), kRgbStride, dest_size, SkIRect::MakeSize(dest_size), rect); // Check if it worked out. CheckRgbBuffer(rect); } void TestBasicConversion() { // Whole buffer. RunTest(SkISize::Make(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight)); } private: size_t yuv_buffer_size_; scoped_array yuv_buffer_; uint8* yplane_; uint8* uplane_; uint8* vplane_; size_t rgb_buffer_size_; scoped_array rgb_buffer_; DISALLOW_COPY_AND_ASSIGN(YuvToRgbTester); }; TEST(YuvToRgbTest, BasicConversion) { YuvToRgbTester tester; tester.TestBasicConversion(); } TEST(YuvToRgbTest, Clipping) { YuvToRgbTester tester; SkISize dest_size = SkISize::Make(kWidth, kHeight); SkIRect rect = SkIRect::MakeLTRB(0, 0, kWidth - 1, kHeight - 1); for (int i = 0; i < 16; ++i) { SkIRect dest_rect = rect; if ((i & 1) != 0) dest_rect.fLeft += 1; if ((i & 2) != 0) dest_rect.fTop += 1; if ((i & 4) != 0) dest_rect.fRight += 1; if ((i & 8) != 0) dest_rect.fBottom += 1; tester.RunTest(dest_size, dest_rect); } } TEST(YuvToRgbTest, ClippingAndScaling) { YuvToRgbTester tester; SkISize dest_size = SkISize::Make(kWidth - 10, kHeight - 10); SkIRect rect = SkIRect::MakeLTRB(5, 5, kWidth - 11, kHeight - 11); for (int i = 0; i < 16; ++i) { SkIRect dest_rect = rect; if ((i & 1) != 0) dest_rect.fLeft += 1; if ((i & 2) != 0) dest_rect.fTop += 1; if ((i & 4) != 0) dest_rect.fRight += 1; if ((i & 8) != 0) dest_rect.fBottom += 1; tester.RunTest(dest_size, dest_rect); } } } // namespace remoting