Home | History | Annotate | Download | only in base
      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