- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / base / util.cc
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/webrtc/modules/desktop_capture/desktop_region.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(
77     const uint8* source_yplane,
78     const uint8* source_uplane,
79     const uint8* source_vplane,
80     int source_ystride,
81     int source_uvstride,
82     const webrtc::DesktopSize& source_size,
83     const webrtc::DesktopRect& source_buffer_rect,
84     uint8* dest_buffer,
85     int dest_stride,
86     const webrtc::DesktopSize& dest_size,
87     const webrtc::DesktopRect& dest_buffer_rect,
88     const webrtc::DesktopRect& dest_rect) {
89   // N.B. It is caller's responsibility to check if strides are large enough. We
90   // cannot do it here anyway.
91   DCHECK(DoesRectContain(webrtc::DesktopRect::MakeSize(source_size),
92                          source_buffer_rect));
93   DCHECK(DoesRectContain(webrtc::DesktopRect::MakeSize(dest_size),
94                          dest_buffer_rect));
95   DCHECK(DoesRectContain(dest_buffer_rect, dest_rect));
96   DCHECK(DoesRectContain(ScaleRect(source_buffer_rect, source_size, dest_size),
97                          dest_rect));
98
99   // If the source and/or destination buffers don't start at (0, 0)
100   // offset the pointers to pretend we have complete buffers.
101   int y_offset = - CalculateYOffset(source_buffer_rect.left(),
102                                     source_buffer_rect.top(),
103                                     source_ystride);
104   int uv_offset = - CalculateUVOffset(source_buffer_rect.left(),
105                                       source_buffer_rect.top(),
106                                       source_uvstride);
107   int rgb_offset = - CalculateRGBOffset(dest_buffer_rect.left(),
108                                         dest_buffer_rect.top(),
109                                         dest_stride);
110
111   // See if scaling is needed.
112   if (source_size.equals(dest_size)) {
113     // Calculate the inner rectangle that can be copied by the optimized
114     // libyuv::I420ToARGB().
115     webrtc::DesktopRect inner_rect =
116         webrtc::DesktopRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left() + 1),
117                                       RoundToTwosMultiple(dest_rect.top() + 1),
118                                       dest_rect.right(), dest_rect.bottom());
119
120     // Offset pointers to point to the top left corner of the inner rectangle.
121     y_offset += CalculateYOffset(inner_rect.left(), inner_rect.top(),
122                                  source_ystride);
123     uv_offset += CalculateUVOffset(inner_rect.left(), inner_rect.top(),
124                                    source_uvstride);
125     rgb_offset += CalculateRGBOffset(inner_rect.left(), inner_rect.top(),
126                                      dest_stride);
127
128     libyuv::I420ToARGB(source_yplane + y_offset, source_ystride,
129                        source_uplane + uv_offset, source_uvstride,
130                        source_vplane + uv_offset, source_uvstride,
131                        dest_buffer + rgb_offset, dest_stride,
132                        inner_rect.width(), inner_rect.height());
133
134     // Now see if some pixels weren't copied due to alignment.
135     if (!dest_rect.equals(inner_rect)) {
136       webrtc::DesktopRect outer_rect =
137           webrtc::DesktopRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left()),
138                                         RoundToTwosMultiple(dest_rect.top()),
139                                         dest_rect.right(), dest_rect.bottom());
140
141       webrtc::DesktopVector offset(outer_rect.left() - inner_rect.left(),
142                                    outer_rect.top() - inner_rect.top());
143
144       // Offset the pointers to point to the top left corner of the outer
145       // rectangle.
146       y_offset += CalculateYOffset(offset.x(), offset.y(), source_ystride);
147       uv_offset += CalculateUVOffset(offset.x(), offset.y(), source_uvstride);
148       rgb_offset += CalculateRGBOffset(offset.x(), offset.y(), dest_stride);
149
150       // Draw unaligned edges.
151       webrtc::DesktopRegion edges(dest_rect);
152       edges.Subtract(inner_rect);
153       for (webrtc::DesktopRegion::Iterator i(edges); !i.IsAtEnd();
154            i.Advance()) {
155         webrtc::DesktopRect rect = i.rect();
156         rect.Translate(-outer_rect.left(), -outer_rect.top());
157         media::ScaleYUVToRGB32WithRect(source_yplane + y_offset,
158                                        source_uplane + uv_offset,
159                                        source_vplane + uv_offset,
160                                        dest_buffer + rgb_offset,
161                                        source_size.width(),
162                                        source_size.height(),
163                                        dest_size.width(),
164                                        dest_size.height(),
165                                        rect.left(),
166                                        rect.top(),
167                                        rect.right(),
168                                        rect.bottom(),
169                                        source_ystride,
170                                        source_uvstride,
171                                        dest_stride);
172       }
173     }
174   } else {
175     media::ScaleYUVToRGB32WithRect(source_yplane + y_offset,
176                                    source_uplane + uv_offset,
177                                    source_vplane + uv_offset,
178                                    dest_buffer + rgb_offset,
179                                    source_size.width(),
180                                    source_size.height(),
181                                    dest_size.width(),
182                                    dest_size.height(),
183                                    dest_rect.left(),
184                                    dest_rect.top(),
185                                    dest_rect.right(),
186                                    dest_rect.bottom(),
187                                    source_ystride,
188                                    source_uvstride,
189                                    dest_stride);
190   }
191 }
192
193 int RoundToTwosMultiple(int x) {
194   return x & (~1);
195 }
196
197 webrtc::DesktopRect AlignRect(const webrtc::DesktopRect& rect) {
198   int x = RoundToTwosMultiple(rect.left());
199   int y = RoundToTwosMultiple(rect.top());
200   int right = RoundToTwosMultiple(rect.right() + 1);
201   int bottom = RoundToTwosMultiple(rect.bottom() + 1);
202   return webrtc::DesktopRect::MakeLTRB(x, y, right, bottom);
203 }
204
205 webrtc::DesktopRect ScaleRect(const webrtc::DesktopRect& rect,
206                               const webrtc::DesktopSize& in_size,
207                               const webrtc::DesktopSize& out_size) {
208   int left = (rect.left() * out_size.width()) / in_size.width();
209   int top = (rect.top() * out_size.height()) / in_size.height();
210   int right = (rect.right() * out_size.width() + in_size.width() - 1) /
211       in_size.width();
212   int bottom = (rect.bottom() * out_size.height() + in_size.height() - 1) /
213       in_size.height();
214   return webrtc::DesktopRect::MakeLTRB(left, top, right, bottom);
215 }
216
217 void CopyRGB32Rect(const uint8* source_buffer,
218                    int source_stride,
219                    const webrtc::DesktopRect& source_buffer_rect,
220                    uint8* dest_buffer,
221                    int dest_stride,
222                    const webrtc::DesktopRect& dest_buffer_rect,
223                    const webrtc::DesktopRect& dest_rect) {
224   DCHECK(DoesRectContain(dest_buffer_rect, dest_rect));
225   DCHECK(DoesRectContain(source_buffer_rect, dest_rect));
226
227   // Get the address of the starting point.
228   source_buffer += CalculateRGBOffset(
229       dest_rect.left() - source_buffer_rect.left(),
230       dest_rect.top() - source_buffer_rect.top(),
231       source_stride);
232   dest_buffer += CalculateRGBOffset(
233       dest_rect.left() - dest_buffer_rect.left(),
234       dest_rect.top() - dest_buffer_rect.top(),
235       source_stride);
236
237   // Copy pixels in the rectangle line by line.
238   const int bytes_per_line = kBytesPerPixelRGB32 * dest_rect.width();
239   for (int i = 0 ; i < dest_rect.height(); ++i) {
240     memcpy(dest_buffer, source_buffer, bytes_per_line);
241     source_buffer += source_stride;
242     dest_buffer += dest_stride;
243   }
244 }
245
246 std::string ReplaceLfByCrLf(const std::string& in) {
247   std::string out;
248   out.resize(2 * in.size());
249   char* out_p_begin = &out[0];
250   char* out_p = out_p_begin;
251   const char* in_p_begin = &in[0];
252   const char* in_p_end = &in[in.size()];
253   for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) {
254     char c = *in_p;
255     if (c == '\n') {
256       *out_p++ = '\r';
257     }
258     *out_p++ = c;
259   }
260   out.resize(out_p - out_p_begin);
261   return out;
262 }
263
264 std::string ReplaceCrLfByLf(const std::string& in) {
265   std::string out;
266   out.resize(in.size());
267   char* out_p_begin = &out[0];
268   char* out_p = out_p_begin;
269   const char* in_p_begin = &in[0];
270   const char* in_p_end = &in[in.size()];
271   for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) {
272     char c = *in_p;
273     if ((c == '\r') && (in_p + 1 < in_p_end) && (*(in_p + 1) == '\n')) {
274       *out_p++ = '\n';
275       ++in_p;
276     } else {
277       *out_p++ = c;
278     }
279   }
280   out.resize(out_p - out_p_begin);
281   return out;
282 }
283
284 bool StringIsUtf8(const char* data, size_t length) {
285   const char* ptr = data;
286   const char* ptr_end = data + length;
287   while (ptr != ptr_end) {
288     if ((*ptr & 0x80) == 0) {
289       // Single-byte symbol.
290       ++ptr;
291     } else if ((*ptr & 0xc0) == 0x80 || (*ptr & 0xfe) == 0xfe) {
292       // Invalid first byte.
293       return false;
294     } else {
295       // First byte of a multi-byte symbol. The bits from 2 to 6 are the count
296       // of continuation bytes (up to 5 of them).
297       for (char first = *ptr << 1; first & 0x80; first <<= 1) {
298         ++ptr;
299
300         // Missing continuation byte.
301         if (ptr == ptr_end)
302           return false;
303
304         // Invalid continuation byte.
305         if ((*ptr & 0xc0) != 0x80)
306           return false;
307       }
308
309       ++ptr;
310     }
311   }
312
313   return true;
314 }
315
316 std::string GetUsername() {
317 #if defined(OS_ANDROID)
318   struct passwd* passwd = getpwuid(getuid());
319   return passwd ? passwd->pw_name : std::string();
320 #elif defined(OS_POSIX)
321   long buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
322   if (buf_size <= 0)
323     return std::string();
324
325   scoped_ptr<char[]> buf(new char[buf_size]);
326   struct passwd passwd;
327   struct passwd* passwd_result = NULL;
328   getpwuid_r(getuid(), &passwd, buf.get(), buf_size, &passwd_result);
329   return passwd_result ? passwd_result->pw_name : std::string();
330 #else  // !defined(OS_POSIX)
331   return std::string();
332 #endif  // defined(OS_POSIX)
333 }
334
335 bool DoesRectContain(const webrtc::DesktopRect& a,
336                      const webrtc::DesktopRect& b) {
337   webrtc::DesktopRect intersection(a);
338   intersection.IntersectWith(b);
339   return intersection.equals(b);
340 }
341
342 }  // namespace remoting