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 "remoting/base/util.h" 6 7 #include <math.h> 8 9 #include "base/logging.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/time/time.h" 12 #include "media/base/video_frame.h" 13 #include "media/base/yuv_convert.h" 14 #include "third_party/libyuv/include/libyuv/convert.h" 15 #include "third_party/skia/include/core/SkRegion.h" 16 17 #if defined(OS_POSIX) 18 #include <pwd.h> 19 #include <sys/types.h> 20 #include <unistd.h> 21 #endif // defined(OS_POSIX) 22 23 using media::VideoFrame; 24 25 namespace remoting { 26 27 enum { kBytesPerPixelRGB32 = 4 }; 28 29 // Do not write LOG messages in this routine since it is called from within 30 // our LOG message handler. Bad things will happen. 31 std::string GetTimestampString() { 32 base::Time t = base::Time::NowFromSystemTime(); 33 base::Time::Exploded tex; 34 t.LocalExplode(&tex); 35 return base::StringPrintf("%02d%02d/%02d%02d%02d:", 36 tex.month, tex.day_of_month, 37 tex.hour, tex.minute, tex.second); 38 } 39 40 int CalculateRGBOffset(int x, int y, int stride) { 41 return stride * y + kBytesPerPixelRGB32 * x; 42 } 43 44 int CalculateYOffset(int x, int y, int stride) { 45 DCHECK(((x & 1) == 0) && ((y & 1) == 0)); 46 return stride * y + x; 47 } 48 49 int CalculateUVOffset(int x, int y, int stride) { 50 DCHECK(((x & 1) == 0) && ((y & 1) == 0)); 51 return stride * y / 2 + x / 2; 52 } 53 54 void ConvertRGB32ToYUVWithRect(const uint8* rgb_plane, 55 uint8* y_plane, 56 uint8* u_plane, 57 uint8* v_plane, 58 int x, 59 int y, 60 int width, 61 int height, 62 int rgb_stride, 63 int y_stride, 64 int uv_stride) { 65 int rgb_offset = CalculateRGBOffset(x, y, rgb_stride); 66 int y_offset = CalculateYOffset(x, y, y_stride); 67 int uv_offset = CalculateUVOffset(x, y, uv_stride);; 68 69 libyuv::ARGBToI420(rgb_plane + rgb_offset, rgb_stride, 70 y_plane + y_offset, y_stride, 71 u_plane + uv_offset, uv_stride, 72 v_plane + uv_offset, uv_stride, 73 width, height); 74 } 75 76 void ConvertAndScaleYUVToRGB32Rect(const uint8* source_yplane, 77 const uint8* source_uplane, 78 const uint8* source_vplane, 79 int source_ystride, 80 int source_uvstride, 81 const SkISize& source_size, 82 const SkIRect& source_buffer_rect, 83 uint8* dest_buffer, 84 int dest_stride, 85 const SkISize& dest_size, 86 const SkIRect& dest_buffer_rect, 87 const SkIRect& dest_rect) { 88 // N.B. It is caller's responsibility to check if strides are large enough. We 89 // cannot do it here anyway. 90 DCHECK(SkIRect::MakeSize(source_size).contains(source_buffer_rect)); 91 DCHECK(SkIRect::MakeSize(dest_size).contains(dest_buffer_rect)); 92 DCHECK(dest_buffer_rect.contains(dest_rect)); 93 DCHECK(ScaleRect(source_buffer_rect, source_size, dest_size). 94 contains(dest_rect)); 95 96 // If the source and/or destination buffers don't start at (0, 0) 97 // offset the pointers to pretend we have complete buffers. 98 int y_offset = - CalculateYOffset(source_buffer_rect.x(), 99 source_buffer_rect.y(), 100 source_ystride); 101 int uv_offset = - CalculateUVOffset(source_buffer_rect.x(), 102 source_buffer_rect.y(), 103 source_uvstride); 104 int rgb_offset = - CalculateRGBOffset(dest_buffer_rect.x(), 105 dest_buffer_rect.y(), 106 dest_stride); 107 108 // See if scaling is needed. 109 if (source_size == dest_size) { 110 // Calculate the inner rectangle that can be copied by the optimized 111 // libyuv::I420ToARGB(). 112 SkIRect inner_rect = 113 SkIRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left() + 1), 114 RoundToTwosMultiple(dest_rect.top() + 1), 115 dest_rect.right(), 116 dest_rect.bottom()); 117 118 // Offset pointers to point to the top left corner of the inner rectangle. 119 y_offset += CalculateYOffset(inner_rect.x(), inner_rect.y(), 120 source_ystride); 121 uv_offset += CalculateUVOffset(inner_rect.x(), inner_rect.y(), 122 source_uvstride); 123 rgb_offset += CalculateRGBOffset(inner_rect.x(), inner_rect.y(), 124 dest_stride); 125 126 libyuv::I420ToARGB(source_yplane + y_offset, source_ystride, 127 source_uplane + uv_offset, source_uvstride, 128 source_vplane + uv_offset, source_uvstride, 129 dest_buffer + rgb_offset, dest_stride, 130 inner_rect.width(), inner_rect.height()); 131 132 // Now see if some pixels weren't copied due to alignment. 133 if (dest_rect != inner_rect) { 134 SkIRect outer_rect = 135 SkIRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left()), 136 RoundToTwosMultiple(dest_rect.top()), 137 dest_rect.right(), 138 dest_rect.bottom()); 139 140 SkIPoint offset = SkIPoint::Make(outer_rect.x() - inner_rect.x(), 141 outer_rect.y() - inner_rect.y()); 142 143 // Offset the pointers to point to the top left corner of the outer 144 // rectangle. 145 y_offset += CalculateYOffset(offset.x(), offset.y(), source_ystride); 146 uv_offset += CalculateUVOffset(offset.x(), offset.y(), source_uvstride); 147 rgb_offset += CalculateRGBOffset(offset.x(), offset.y(), dest_stride); 148 149 // Draw unaligned edges. 150 SkRegion edges(dest_rect); 151 edges.op(inner_rect, SkRegion::kDifference_Op); 152 for (SkRegion::Iterator i(edges); !i.done(); i.next()) { 153 SkIRect rect(i.rect()); 154 rect.offset(- outer_rect.left(), - outer_rect.top()); 155 media::ScaleYUVToRGB32WithRect(source_yplane + y_offset, 156 source_uplane + uv_offset, 157 source_vplane + uv_offset, 158 dest_buffer + rgb_offset, 159 source_size.width(), 160 source_size.height(), 161 dest_size.width(), 162 dest_size.height(), 163 rect.left(), 164 rect.top(), 165 rect.right(), 166 rect.bottom(), 167 source_ystride, 168 source_uvstride, 169 dest_stride); 170 } 171 } 172 } else { 173 media::ScaleYUVToRGB32WithRect(source_yplane + y_offset, 174 source_uplane + uv_offset, 175 source_vplane + uv_offset, 176 dest_buffer + rgb_offset, 177 source_size.width(), 178 source_size.height(), 179 dest_size.width(), 180 dest_size.height(), 181 dest_rect.left(), 182 dest_rect.top(), 183 dest_rect.right(), 184 dest_rect.bottom(), 185 source_ystride, 186 source_uvstride, 187 dest_stride); 188 } 189 } 190 191 int RoundToTwosMultiple(int x) { 192 return x & (~1); 193 } 194 195 SkIRect AlignRect(const SkIRect& rect) { 196 int x = RoundToTwosMultiple(rect.left()); 197 int y = RoundToTwosMultiple(rect.top()); 198 int right = RoundToTwosMultiple(rect.right() + 1); 199 int bottom = RoundToTwosMultiple(rect.bottom() + 1); 200 return SkIRect::MakeLTRB(x, y, right, bottom); 201 } 202 203 SkIRect ScaleRect(const SkIRect& rect, 204 const SkISize& in_size, 205 const SkISize& out_size) { 206 int left = (rect.left() * out_size.width()) / in_size.width(); 207 int top = (rect.top() * out_size.height()) / in_size.height(); 208 int right = (rect.right() * out_size.width() + in_size.width() - 1) / 209 in_size.width(); 210 int bottom = (rect.bottom() * out_size.height() + in_size.height() - 1) / 211 in_size.height(); 212 return SkIRect::MakeLTRB(left, top, right, bottom); 213 } 214 215 void CopyRGB32Rect(const uint8* source_buffer, 216 int source_stride, 217 const SkIRect& source_buffer_rect, 218 uint8* dest_buffer, 219 int dest_stride, 220 const SkIRect& dest_buffer_rect, 221 const SkIRect& dest_rect) { 222 DCHECK(dest_buffer_rect.contains(dest_rect)); 223 DCHECK(source_buffer_rect.contains(dest_rect)); 224 225 // Get the address of the starting point. 226 source_buffer += CalculateRGBOffset(dest_rect.x() - source_buffer_rect.x(), 227 dest_rect.y() - source_buffer_rect.y(), 228 source_stride); 229 dest_buffer += CalculateRGBOffset(dest_rect.x() - dest_buffer_rect.x(), 230 dest_rect.y() - dest_buffer_rect.y(), 231 source_stride); 232 233 // Copy pixels in the rectangle line by line. 234 const int bytes_per_line = kBytesPerPixelRGB32 * dest_rect.width(); 235 for (int i = 0 ; i < dest_rect.height(); ++i) { 236 memcpy(dest_buffer, source_buffer, bytes_per_line); 237 source_buffer += source_stride; 238 dest_buffer += dest_stride; 239 } 240 } 241 242 std::string ReplaceLfByCrLf(const std::string& in) { 243 std::string out; 244 out.resize(2 * in.size()); 245 char* out_p_begin = &out[0]; 246 char* out_p = out_p_begin; 247 const char* in_p_begin = &in[0]; 248 const char* in_p_end = &in[in.size()]; 249 for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) { 250 char c = *in_p; 251 if (c == '\n') { 252 *out_p++ = '\r'; 253 } 254 *out_p++ = c; 255 } 256 out.resize(out_p - out_p_begin); 257 return out; 258 } 259 260 std::string ReplaceCrLfByLf(const std::string& in) { 261 std::string out; 262 out.resize(in.size()); 263 char* out_p_begin = &out[0]; 264 char* out_p = out_p_begin; 265 const char* in_p_begin = &in[0]; 266 const char* in_p_end = &in[in.size()]; 267 for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) { 268 char c = *in_p; 269 if ((c == '\r') && (in_p + 1 < in_p_end) && (*(in_p + 1) == '\n')) { 270 *out_p++ = '\n'; 271 ++in_p; 272 } else { 273 *out_p++ = c; 274 } 275 } 276 out.resize(out_p - out_p_begin); 277 return out; 278 } 279 280 bool StringIsUtf8(const char* data, size_t length) { 281 const char* ptr = data; 282 const char* ptr_end = data + length; 283 while (ptr != ptr_end) { 284 if ((*ptr & 0x80) == 0) { 285 // Single-byte symbol. 286 ++ptr; 287 } else if ((*ptr & 0xc0) == 0x80 || (*ptr & 0xfe) == 0xfe) { 288 // Invalid first byte. 289 return false; 290 } else { 291 // First byte of a multi-byte symbol. The bits from 2 to 6 are the count 292 // of continuation bytes (up to 5 of them). 293 for (char first = *ptr << 1; first & 0x80; first <<= 1) { 294 ++ptr; 295 296 // Missing continuation byte. 297 if (ptr == ptr_end) 298 return false; 299 300 // Invalid continuation byte. 301 if ((*ptr & 0xc0) != 0x80) 302 return false; 303 } 304 305 ++ptr; 306 } 307 } 308 309 return true; 310 } 311 312 std::string GetUsername() { 313 #if defined(OS_ANDROID) 314 struct passwd* passwd = getpwuid(getuid()); 315 return passwd ? passwd->pw_name : std::string(); 316 #elif defined(OS_POSIX) 317 long buf_size = sysconf(_SC_GETPW_R_SIZE_MAX); 318 if (buf_size <= 0) 319 return std::string(); 320 321 scoped_ptr<char[]> buf(new char[buf_size]); 322 struct passwd passwd; 323 struct passwd* passwd_result = NULL; 324 getpwuid_r(getuid(), &passwd, buf.get(), buf_size, &passwd_result); 325 return passwd_result ? passwd_result->pw_name : std::string(); 326 #else // !defined(OS_POSIX) 327 return std::string(); 328 #endif // defined(OS_POSIX) 329 } 330 331 } // namespace remoting 332