1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <algorithm> 6 7 #include "remoting/base/util.h" 8 #include "testing/gtest/include/gtest/gtest.h" 9 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" 10 11 static const int kWidth = 32 ; 12 static const int kHeight = 24 ; 13 static const int kBytesPerPixel = 4; 14 static const int kYStride = kWidth; 15 static const int kUvStride = kWidth / 2; 16 static const int kRgbStride = kWidth * kBytesPerPixel; 17 static const uint32 kFillColor = 0xffffff; 18 19 namespace remoting { 20 21 class YuvToRgbTester { 22 public: 23 YuvToRgbTester() { 24 yuv_buffer_size_ = (kYStride + kUvStride) * kHeight; 25 yuv_buffer_.reset(new uint8[yuv_buffer_size_]); 26 yplane_ = yuv_buffer_.get(); 27 uplane_ = yplane_ + (kYStride * kHeight); 28 vplane_ = uplane_ + (kUvStride * kHeight / 2); 29 30 rgb_buffer_size_ = kWidth * kHeight * kBytesPerPixel; 31 rgb_buffer_.reset(new uint8[rgb_buffer_size_]); 32 33 ResetYuvBuffer(); 34 ResetRgbBuffer(); 35 } 36 37 ~YuvToRgbTester() {} 38 39 void ResetYuvBuffer() { 40 memset(yuv_buffer_.get(), 0, yuv_buffer_size_); 41 } 42 43 void ResetRgbBuffer() { 44 memset(rgb_buffer_.get(), 0, rgb_buffer_size_); 45 } 46 47 void FillRgbBuffer(const webrtc::DesktopRect& rect) { 48 uint32* ptr = reinterpret_cast<uint32*>( 49 rgb_buffer_.get() + (rect.top() * kRgbStride) + 50 (rect.left() * kBytesPerPixel)); 51 int width = rect.width(); 52 for (int height = rect.height(); height > 0; --height) { 53 std::fill(ptr, ptr + width, kFillColor); 54 ptr += kRgbStride / kBytesPerPixel; 55 } 56 } 57 58 // Check the the desination buffer is filled within expected bounds. 59 void CheckRgbBuffer(const webrtc::DesktopRect& rect) { 60 uint32* ptr = reinterpret_cast<uint32*>(rgb_buffer_.get()); 61 for (int y = 0; y < kHeight; ++y) { 62 if (y < rect.top() || rect.bottom() <= y) { 63 // The whole line should be intact. 64 EXPECT_EQ((ptrdiff_t)kWidth, 65 std::count(ptr, ptr + kWidth, 0u)); 66 } else { 67 // The space before the painted rectangle should be intact. 68 EXPECT_EQ((ptrdiff_t)rect.left(), 69 std::count(ptr, ptr + rect.left(), 0u)); 70 71 // All pixels of the target rectangle should be touched. 72 EXPECT_EQ(ptr + rect.right(), 73 std::find(ptr + rect.left(), ptr + rect.right(), 0u)); 74 75 // The space after the painted rectangle should be intact. 76 EXPECT_EQ((ptrdiff_t)kWidth - rect.right(), 77 std::count(ptr + rect.right(), ptr + kWidth, 0u)); 78 } 79 ptr += kRgbStride / kBytesPerPixel; 80 } 81 } 82 83 void RunTest(const webrtc::DesktopSize dest_size, 84 const webrtc::DesktopRect& rect) { 85 ASSERT_TRUE( 86 DoesRectContain(webrtc::DesktopRect::MakeSize(dest_size), rect)); 87 88 // Reset buffers. 89 ResetYuvBuffer(); 90 ResetRgbBuffer(); 91 FillRgbBuffer(rect); 92 93 // RGB -> YUV 94 ConvertRGB32ToYUVWithRect(rgb_buffer_.get(), 95 yplane_, 96 uplane_, 97 vplane_, 98 0, 99 0, 100 kWidth, 101 kHeight, 102 kRgbStride, 103 kYStride, 104 kUvStride); 105 106 // Reset RGB buffer and do opposite conversion. 107 ResetRgbBuffer(); 108 ConvertAndScaleYUVToRGB32Rect(yplane_, 109 uplane_, 110 vplane_, 111 kYStride, 112 kUvStride, 113 webrtc::DesktopSize(kWidth, kHeight), 114 webrtc::DesktopRect::MakeWH(kWidth, kHeight), 115 rgb_buffer_.get(), 116 kRgbStride, 117 dest_size, 118 webrtc::DesktopRect::MakeSize(dest_size), 119 rect); 120 121 // Check if it worked out. 122 CheckRgbBuffer(rect); 123 } 124 125 void TestBasicConversion() { 126 // Whole buffer. 127 RunTest(webrtc::DesktopSize(kWidth, kHeight), 128 webrtc::DesktopRect::MakeWH(kWidth, kHeight)); 129 } 130 131 private: 132 size_t yuv_buffer_size_; 133 scoped_ptr<uint8[]> yuv_buffer_; 134 uint8* yplane_; 135 uint8* uplane_; 136 uint8* vplane_; 137 138 size_t rgb_buffer_size_; 139 scoped_ptr<uint8[]> rgb_buffer_; 140 141 DISALLOW_COPY_AND_ASSIGN(YuvToRgbTester); 142 }; 143 144 TEST(YuvToRgbTest, BasicConversion) { 145 YuvToRgbTester tester; 146 tester.TestBasicConversion(); 147 } 148 149 TEST(YuvToRgbTest, Clipping) { 150 YuvToRgbTester tester; 151 152 webrtc::DesktopSize dest_size = webrtc::DesktopSize(kWidth, kHeight); 153 webrtc::DesktopRect rect = 154 webrtc::DesktopRect::MakeLTRB(0, 0, kWidth - 1, kHeight - 1); 155 // TODO(fbarchard): Allow top/left clipping to odd boundary. 156 for (int i = 0; i < 16; ++i) { 157 webrtc::DesktopRect dest_rect = webrtc::DesktopRect::MakeLTRB( 158 rect.left() + ((i & 1) ? 2 : 0), 159 rect.top() + ((i & 2) ? 2 : 0), 160 rect.right() - ((i & 4) ? 1 : 0), 161 rect.bottom() - ((i & 8) ? 1 : 0)); 162 163 tester.RunTest(dest_size, dest_rect); 164 } 165 } 166 167 TEST(YuvToRgbTest, ClippingAndScaling) { 168 YuvToRgbTester tester; 169 170 webrtc::DesktopSize dest_size = 171 webrtc::DesktopSize(kWidth - 10, kHeight - 10); 172 webrtc::DesktopRect rect = 173 webrtc::DesktopRect::MakeLTRB(6, 6, kWidth - 11, kHeight - 11); 174 for (int i = 0; i < 16; ++i) { 175 webrtc::DesktopRect dest_rect = webrtc::DesktopRect::MakeLTRB( 176 rect.left() + ((i & 1) ? 2 : 0), 177 rect.top() + ((i & 2) ? 2 : 0), 178 rect.right() - ((i & 4) ? 1 : 0), 179 rect.bottom() - ((i & 8) ? 1 : 0)); 180 181 tester.RunTest(dest_size, dest_rect); 182 } 183 } 184 185 TEST(ReplaceLfByCrLfTest, Basic) { 186 EXPECT_EQ("ab", ReplaceLfByCrLf("ab")); 187 EXPECT_EQ("\r\nab", ReplaceLfByCrLf("\nab")); 188 EXPECT_EQ("\r\nab\r\n", ReplaceLfByCrLf("\nab\n")); 189 EXPECT_EQ("\r\nab\r\ncd", ReplaceLfByCrLf("\nab\ncd")); 190 EXPECT_EQ("\r\nab\r\ncd\r\n", ReplaceLfByCrLf("\nab\ncd\n")); 191 EXPECT_EQ("\r\n\r\nab\r\n\r\ncd\r\n\r\n", 192 ReplaceLfByCrLf("\n\nab\n\ncd\n\n")); 193 } 194 195 TEST(ReplaceLfByCrLfTest, Speed) { 196 int kLineSize = 128; 197 std::string line(kLineSize, 'a'); 198 line[kLineSize - 1] = '\n'; 199 // Make a 10M string. 200 int kLineNum = 10 * 1024 * 1024 / kLineSize; 201 std::string buffer; 202 buffer.resize(kLineNum * kLineSize); 203 for (int i = 0; i < kLineNum; ++i) { 204 memcpy(&buffer[i * kLineSize], &line[0], kLineSize); 205 } 206 // Convert the string. 207 buffer = ReplaceLfByCrLf(buffer); 208 // Check the converted string. 209 EXPECT_EQ(static_cast<size_t>((kLineSize + 1) * kLineNum), buffer.size()); 210 const char* p = &buffer[0]; 211 for (int i = 0; i < kLineNum; ++i) { 212 EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 1)); 213 p += kLineSize - 1; 214 EXPECT_EQ('\r', *p++); 215 EXPECT_EQ('\n', *p++); 216 } 217 } 218 219 TEST(ReplaceCrLfByLfTest, Basic) { 220 EXPECT_EQ("ab", ReplaceCrLfByLf("ab")); 221 EXPECT_EQ("\nab", ReplaceCrLfByLf("\r\nab")); 222 EXPECT_EQ("\nab\n", ReplaceCrLfByLf("\r\nab\r\n")); 223 EXPECT_EQ("\nab\ncd", ReplaceCrLfByLf("\r\nab\r\ncd")); 224 EXPECT_EQ("\nab\ncd\n", ReplaceCrLfByLf("\r\nab\r\ncd\n")); 225 EXPECT_EQ("\n\nab\n\ncd\n\n", 226 ReplaceCrLfByLf("\r\n\r\nab\r\n\r\ncd\r\n\r\n")); 227 EXPECT_EQ("\rab\rcd\r", ReplaceCrLfByLf("\rab\rcd\r")); 228 } 229 230 TEST(ReplaceCrLfByLfTest, Speed) { 231 int kLineSize = 128; 232 std::string line(kLineSize, 'a'); 233 line[kLineSize - 2] = '\r'; 234 line[kLineSize - 1] = '\n'; 235 // Make a 10M string. 236 int kLineNum = 10 * 1024 * 1024 / kLineSize; 237 std::string buffer; 238 buffer.resize(kLineNum * kLineSize); 239 for (int i = 0; i < kLineNum; ++i) { 240 memcpy(&buffer[i * kLineSize], &line[0], kLineSize); 241 } 242 // Convert the string. 243 buffer = ReplaceCrLfByLf(buffer); 244 // Check the converted string. 245 EXPECT_EQ(static_cast<size_t>((kLineSize - 1) * kLineNum), buffer.size()); 246 const char* p = &buffer[0]; 247 for (int i = 0; i < kLineNum; ++i) { 248 EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 2)); 249 p += kLineSize - 2; 250 EXPECT_EQ('\n', *p++); 251 } 252 } 253 254 TEST(StringIsUtf8Test, Basic) { 255 EXPECT_TRUE(StringIsUtf8("", 0)); 256 EXPECT_TRUE(StringIsUtf8("\0", 1)); 257 EXPECT_TRUE(StringIsUtf8("abc", 3)); 258 EXPECT_TRUE(StringIsUtf8("\xc0\x80", 2)); 259 EXPECT_TRUE(StringIsUtf8("\xe0\x80\x80", 3)); 260 EXPECT_TRUE(StringIsUtf8("\xf0\x80\x80\x80", 4)); 261 EXPECT_TRUE(StringIsUtf8("\xf8\x80\x80\x80\x80", 5)); 262 EXPECT_TRUE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80", 6)); 263 264 // Not enough continuation characters 265 EXPECT_FALSE(StringIsUtf8("\xc0", 1)); 266 EXPECT_FALSE(StringIsUtf8("\xe0\x80", 2)); 267 EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80", 3)); 268 EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80", 4)); 269 EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80", 5)); 270 271 // One more continuation character than needed 272 EXPECT_FALSE(StringIsUtf8("\xc0\x80\x80", 3)); 273 EXPECT_FALSE(StringIsUtf8("\xe0\x80\x80\x80", 4)); 274 EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80\x80\x80", 5)); 275 EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80\x80\x80", 6)); 276 EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80\x80", 7)); 277 278 // Invalid first byte 279 EXPECT_FALSE(StringIsUtf8("\xfe\x80\x80\x80\x80\x80\x80", 7)); 280 EXPECT_FALSE(StringIsUtf8("\xff\x80\x80\x80\x80\x80\x80", 7)); 281 282 // Invalid continuation byte 283 EXPECT_FALSE(StringIsUtf8("\xc0\x00", 2)); 284 EXPECT_FALSE(StringIsUtf8("\xc0\x40", 2)); 285 EXPECT_FALSE(StringIsUtf8("\xc0\xc0", 2)); 286 } 287 288 } // namespace remoting 289