blob: 24e628daf19064d66e36df7391626a4609dbda28 [file] [log] [blame]
// 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 <algorithm>
#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<uint32*>(
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<uint32*>(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<uint8> yuv_buffer_;
uint8* yplane_;
uint8* uplane_;
uint8* vplane_;
size_t rgb_buffer_size_;
scoped_array<uint8> 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