Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS. All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "libyuv/rotate.h"
     12 
     13 #include "libyuv/cpu_id.h"
     14 #include "libyuv/convert.h"
     15 #include "libyuv/planar_functions.h"
     16 #include "libyuv/rotate_row.h"
     17 #include "libyuv/row.h"
     18 
     19 #ifdef __cplusplus
     20 namespace libyuv {
     21 extern "C" {
     22 #endif
     23 
     24 LIBYUV_API
     25 void TransposePlane(const uint8* src, int src_stride,
     26                     uint8* dst, int dst_stride,
     27                     int width, int height) {
     28   int i = height;
     29   void (*TransposeWx8)(const uint8* src, int src_stride,
     30                        uint8* dst, int dst_stride, int width) = TransposeWx8_C;
     31 #if defined(HAS_TRANSPOSEWX8_NEON)
     32   if (TestCpuFlag(kCpuHasNEON)) {
     33     TransposeWx8 = TransposeWx8_NEON;
     34   }
     35 #endif
     36 #if defined(HAS_TRANSPOSEWX8_SSSE3)
     37   if (TestCpuFlag(kCpuHasSSSE3)) {
     38     TransposeWx8 = TransposeWx8_Any_SSSE3;
     39     if (IS_ALIGNED(width, 8)) {
     40       TransposeWx8 = TransposeWx8_SSSE3;
     41     }
     42   }
     43 #endif
     44 #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3)
     45   if (TestCpuFlag(kCpuHasSSSE3)) {
     46     TransposeWx8 = TransposeWx8_Fast_Any_SSSE3;
     47     if (IS_ALIGNED(width, 16)) {
     48       TransposeWx8 = TransposeWx8_Fast_SSSE3;
     49     }
     50   }
     51 #endif
     52 #if defined(HAS_TRANSPOSEWX8_DSPR2)
     53   if (TestCpuFlag(kCpuHasDSPR2)) {
     54     if (IS_ALIGNED(width, 4) &&
     55         IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
     56       TransposeWx8 = TransposeWx8_Fast_DSPR2;
     57     } else {
     58       TransposeWx8 = TransposeWx8_DSPR2;
     59     }
     60   }
     61 #endif
     62 
     63   // Work across the source in 8x8 tiles
     64   while (i >= 8) {
     65     TransposeWx8(src, src_stride, dst, dst_stride, width);
     66     src += 8 * src_stride;    // Go down 8 rows.
     67     dst += 8;                 // Move over 8 columns.
     68     i -= 8;
     69   }
     70 
     71   if (i > 0) {
     72     TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
     73   }
     74 }
     75 
     76 LIBYUV_API
     77 void RotatePlane90(const uint8* src, int src_stride,
     78                    uint8* dst, int dst_stride,
     79                    int width, int height) {
     80   // Rotate by 90 is a transpose with the source read
     81   // from bottom to top. So set the source pointer to the end
     82   // of the buffer and flip the sign of the source stride.
     83   src += src_stride * (height - 1);
     84   src_stride = -src_stride;
     85   TransposePlane(src, src_stride, dst, dst_stride, width, height);
     86 }
     87 
     88 LIBYUV_API
     89 void RotatePlane270(const uint8* src, int src_stride,
     90                     uint8* dst, int dst_stride,
     91                     int width, int height) {
     92   // Rotate by 270 is a transpose with the destination written
     93   // from bottom to top. So set the destination pointer to the end
     94   // of the buffer and flip the sign of the destination stride.
     95   dst += dst_stride * (width - 1);
     96   dst_stride = -dst_stride;
     97   TransposePlane(src, src_stride, dst, dst_stride, width, height);
     98 }
     99 
    100 LIBYUV_API
    101 void RotatePlane180(const uint8* src, int src_stride,
    102                     uint8* dst, int dst_stride,
    103                     int width, int height) {
    104   // Swap first and last row and mirror the content. Uses a temporary row.
    105   align_buffer_64(row, width);
    106   const uint8* src_bot = src + src_stride * (height - 1);
    107   uint8* dst_bot = dst + dst_stride * (height - 1);
    108   int half_height = (height + 1) >> 1;
    109   int y;
    110   void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
    111   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
    112 #if defined(HAS_MIRRORROW_NEON)
    113   if (TestCpuFlag(kCpuHasNEON)) {
    114     MirrorRow = MirrorRow_Any_NEON;
    115     if (IS_ALIGNED(width, 16)) {
    116       MirrorRow = MirrorRow_NEON;
    117     }
    118   }
    119 #endif
    120 #if defined(HAS_MIRRORROW_SSSE3)
    121   if (TestCpuFlag(kCpuHasSSSE3)) {
    122     MirrorRow = MirrorRow_Any_SSSE3;
    123     if (IS_ALIGNED(width, 16)) {
    124       MirrorRow = MirrorRow_SSSE3;
    125     }
    126   }
    127 #endif
    128 #if defined(HAS_MIRRORROW_AVX2)
    129   if (TestCpuFlag(kCpuHasAVX2)) {
    130     MirrorRow = MirrorRow_Any_AVX2;
    131     if (IS_ALIGNED(width, 32)) {
    132       MirrorRow = MirrorRow_AVX2;
    133     }
    134   }
    135 #endif
    136 // TODO(fbarchard): Mirror on mips handle unaligned memory.
    137 #if defined(HAS_MIRRORROW_DSPR2)
    138   if (TestCpuFlag(kCpuHasDSPR2) &&
    139       IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4) &&
    140       IS_ALIGNED(dst, 4) && IS_ALIGNED(dst_stride, 4)) {
    141     MirrorRow = MirrorRow_DSPR2;
    142   }
    143 #endif
    144 #if defined(HAS_COPYROW_SSE2)
    145   if (TestCpuFlag(kCpuHasSSE2)) {
    146     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
    147   }
    148 #endif
    149 #if defined(HAS_COPYROW_AVX)
    150   if (TestCpuFlag(kCpuHasAVX)) {
    151     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
    152   }
    153 #endif
    154 #if defined(HAS_COPYROW_ERMS)
    155   if (TestCpuFlag(kCpuHasERMS)) {
    156     CopyRow = CopyRow_ERMS;
    157   }
    158 #endif
    159 #if defined(HAS_COPYROW_NEON)
    160   if (TestCpuFlag(kCpuHasNEON)) {
    161     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
    162   }
    163 #endif
    164 #if defined(HAS_COPYROW_MIPS)
    165   if (TestCpuFlag(kCpuHasMIPS)) {
    166     CopyRow = CopyRow_MIPS;
    167   }
    168 #endif
    169 
    170   // Odd height will harmlessly mirror the middle row twice.
    171   for (y = 0; y < half_height; ++y) {
    172     MirrorRow(src, row, width);  // Mirror first row into a buffer
    173     src += src_stride;
    174     MirrorRow(src_bot, dst, width);  // Mirror last row into first row
    175     dst += dst_stride;
    176     CopyRow(row, dst_bot, width);  // Copy first mirrored row into last
    177     src_bot -= src_stride;
    178     dst_bot -= dst_stride;
    179   }
    180   free_aligned_buffer_64(row);
    181 }
    182 
    183 LIBYUV_API
    184 void TransposeUV(const uint8* src, int src_stride,
    185                  uint8* dst_a, int dst_stride_a,
    186                  uint8* dst_b, int dst_stride_b,
    187                  int width, int height) {
    188   int i = height;
    189   void (*TransposeUVWx8)(const uint8* src, int src_stride,
    190                          uint8* dst_a, int dst_stride_a,
    191                          uint8* dst_b, int dst_stride_b,
    192                          int width) = TransposeUVWx8_C;
    193 #if defined(HAS_TRANSPOSEUVWX8_NEON)
    194   if (TestCpuFlag(kCpuHasNEON)) {
    195     TransposeUVWx8 = TransposeUVWx8_NEON;
    196   }
    197 #endif
    198 #if defined(HAS_TRANSPOSEUVWX8_SSE2)
    199   if (TestCpuFlag(kCpuHasSSE2)) {
    200     TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
    201     if (IS_ALIGNED(width, 8)) {
    202       TransposeUVWx8 = TransposeUVWx8_SSE2;
    203     }
    204   }
    205 #endif
    206 #if defined(HAS_TRANSPOSEUVWX8_DSPR2)
    207   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 2) &&
    208       IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
    209     TransposeUVWx8 = TransposeUVWx8_DSPR2;
    210   }
    211 #endif
    212 
    213   // Work through the source in 8x8 tiles.
    214   while (i >= 8) {
    215     TransposeUVWx8(src, src_stride,
    216                    dst_a, dst_stride_a,
    217                    dst_b, dst_stride_b,
    218                    width);
    219     src += 8 * src_stride;    // Go down 8 rows.
    220     dst_a += 8;               // Move over 8 columns.
    221     dst_b += 8;               // Move over 8 columns.
    222     i -= 8;
    223   }
    224 
    225   if (i > 0) {
    226     TransposeUVWxH_C(src, src_stride,
    227                      dst_a, dst_stride_a,
    228                      dst_b, dst_stride_b,
    229                      width, i);
    230   }
    231 }
    232 
    233 LIBYUV_API
    234 void RotateUV90(const uint8* src, int src_stride,
    235                 uint8* dst_a, int dst_stride_a,
    236                 uint8* dst_b, int dst_stride_b,
    237                 int width, int height) {
    238   src += src_stride * (height - 1);
    239   src_stride = -src_stride;
    240 
    241   TransposeUV(src, src_stride,
    242               dst_a, dst_stride_a,
    243               dst_b, dst_stride_b,
    244               width, height);
    245 }
    246 
    247 LIBYUV_API
    248 void RotateUV270(const uint8* src, int src_stride,
    249                  uint8* dst_a, int dst_stride_a,
    250                  uint8* dst_b, int dst_stride_b,
    251                  int width, int height) {
    252   dst_a += dst_stride_a * (width - 1);
    253   dst_b += dst_stride_b * (width - 1);
    254   dst_stride_a = -dst_stride_a;
    255   dst_stride_b = -dst_stride_b;
    256 
    257   TransposeUV(src, src_stride,
    258               dst_a, dst_stride_a,
    259               dst_b, dst_stride_b,
    260               width, height);
    261 }
    262 
    263 // Rotate 180 is a horizontal and vertical flip.
    264 LIBYUV_API
    265 void RotateUV180(const uint8* src, int src_stride,
    266                  uint8* dst_a, int dst_stride_a,
    267                  uint8* dst_b, int dst_stride_b,
    268                  int width, int height) {
    269   int i;
    270   void (*MirrorUVRow)(const uint8* src, uint8* dst_u, uint8* dst_v, int width) =
    271       MirrorUVRow_C;
    272 #if defined(HAS_MIRRORUVROW_NEON)
    273   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    274     MirrorUVRow = MirrorUVRow_NEON;
    275   }
    276 #endif
    277 #if defined(HAS_MIRRORUVROW_SSSE3)
    278   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
    279     MirrorUVRow = MirrorUVRow_SSSE3;
    280   }
    281 #endif
    282 #if defined(HAS_MIRRORUVROW_DSPR2)
    283   if (TestCpuFlag(kCpuHasDSPR2) &&
    284       IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
    285     MirrorUVRow = MirrorUVRow_DSPR2;
    286   }
    287 #endif
    288 
    289   dst_a += dst_stride_a * (height - 1);
    290   dst_b += dst_stride_b * (height - 1);
    291 
    292   for (i = 0; i < height; ++i) {
    293     MirrorUVRow(src, dst_a, dst_b, width);
    294     src += src_stride;
    295     dst_a -= dst_stride_a;
    296     dst_b -= dst_stride_b;
    297   }
    298 }
    299 
    300 LIBYUV_API
    301 int RotatePlane(const uint8* src, int src_stride,
    302                 uint8* dst, int dst_stride,
    303                 int width, int height,
    304                 enum RotationMode mode) {
    305   if (!src || width <= 0 || height == 0 || !dst) {
    306     return -1;
    307   }
    308 
    309   // Negative height means invert the image.
    310   if (height < 0) {
    311     height = -height;
    312     src = src + (height - 1) * src_stride;
    313     src_stride = -src_stride;
    314   }
    315 
    316   switch (mode) {
    317     case kRotate0:
    318       // copy frame
    319       CopyPlane(src, src_stride,
    320                 dst, dst_stride,
    321                 width, height);
    322       return 0;
    323     case kRotate90:
    324       RotatePlane90(src, src_stride,
    325                     dst, dst_stride,
    326                     width, height);
    327       return 0;
    328     case kRotate270:
    329       RotatePlane270(src, src_stride,
    330                      dst, dst_stride,
    331                      width, height);
    332       return 0;
    333     case kRotate180:
    334       RotatePlane180(src, src_stride,
    335                      dst, dst_stride,
    336                      width, height);
    337       return 0;
    338     default:
    339       break;
    340   }
    341   return -1;
    342 }
    343 
    344 LIBYUV_API
    345 int I420Rotate(const uint8* src_y, int src_stride_y,
    346                const uint8* src_u, int src_stride_u,
    347                const uint8* src_v, int src_stride_v,
    348                uint8* dst_y, int dst_stride_y,
    349                uint8* dst_u, int dst_stride_u,
    350                uint8* dst_v, int dst_stride_v,
    351                int width, int height,
    352                enum RotationMode mode) {
    353   int halfwidth = (width + 1) >> 1;
    354   int halfheight = (height + 1) >> 1;
    355   if (!src_y || !src_u || !src_v || width <= 0 || height == 0 ||
    356       !dst_y || !dst_u || !dst_v) {
    357     return -1;
    358   }
    359 
    360   // Negative height means invert the image.
    361   if (height < 0) {
    362     height = -height;
    363     halfheight = (height + 1) >> 1;
    364     src_y = src_y + (height - 1) * src_stride_y;
    365     src_u = src_u + (halfheight - 1) * src_stride_u;
    366     src_v = src_v + (halfheight - 1) * src_stride_v;
    367     src_stride_y = -src_stride_y;
    368     src_stride_u = -src_stride_u;
    369     src_stride_v = -src_stride_v;
    370   }
    371 
    372   switch (mode) {
    373     case kRotate0:
    374       // copy frame
    375       return I420Copy(src_y, src_stride_y,
    376                       src_u, src_stride_u,
    377                       src_v, src_stride_v,
    378                       dst_y, dst_stride_y,
    379                       dst_u, dst_stride_u,
    380                       dst_v, dst_stride_v,
    381                       width, height);
    382     case kRotate90:
    383       RotatePlane90(src_y, src_stride_y,
    384                     dst_y, dst_stride_y,
    385                     width, height);
    386       RotatePlane90(src_u, src_stride_u,
    387                     dst_u, dst_stride_u,
    388                     halfwidth, halfheight);
    389       RotatePlane90(src_v, src_stride_v,
    390                     dst_v, dst_stride_v,
    391                     halfwidth, halfheight);
    392       return 0;
    393     case kRotate270:
    394       RotatePlane270(src_y, src_stride_y,
    395                      dst_y, dst_stride_y,
    396                      width, height);
    397       RotatePlane270(src_u, src_stride_u,
    398                      dst_u, dst_stride_u,
    399                      halfwidth, halfheight);
    400       RotatePlane270(src_v, src_stride_v,
    401                      dst_v, dst_stride_v,
    402                      halfwidth, halfheight);
    403       return 0;
    404     case kRotate180:
    405       RotatePlane180(src_y, src_stride_y,
    406                      dst_y, dst_stride_y,
    407                      width, height);
    408       RotatePlane180(src_u, src_stride_u,
    409                      dst_u, dst_stride_u,
    410                      halfwidth, halfheight);
    411       RotatePlane180(src_v, src_stride_v,
    412                      dst_v, dst_stride_v,
    413                      halfwidth, halfheight);
    414       return 0;
    415     default:
    416       break;
    417   }
    418   return -1;
    419 }
    420 
    421 LIBYUV_API
    422 int NV12ToI420Rotate(const uint8* src_y, int src_stride_y,
    423                      const uint8* src_uv, int src_stride_uv,
    424                      uint8* dst_y, int dst_stride_y,
    425                      uint8* dst_u, int dst_stride_u,
    426                      uint8* dst_v, int dst_stride_v,
    427                      int width, int height,
    428                      enum RotationMode mode) {
    429   int halfwidth = (width + 1) >> 1;
    430   int halfheight = (height + 1) >> 1;
    431   if (!src_y || !src_uv || width <= 0 || height == 0 ||
    432       !dst_y || !dst_u || !dst_v) {
    433     return -1;
    434   }
    435 
    436   // Negative height means invert the image.
    437   if (height < 0) {
    438     height = -height;
    439     halfheight = (height + 1) >> 1;
    440     src_y = src_y + (height - 1) * src_stride_y;
    441     src_uv = src_uv + (halfheight - 1) * src_stride_uv;
    442     src_stride_y = -src_stride_y;
    443     src_stride_uv = -src_stride_uv;
    444   }
    445 
    446   switch (mode) {
    447     case kRotate0:
    448       // copy frame
    449       return NV12ToI420(src_y, src_stride_y,
    450                         src_uv, src_stride_uv,
    451                         dst_y, dst_stride_y,
    452                         dst_u, dst_stride_u,
    453                         dst_v, dst_stride_v,
    454                         width, height);
    455     case kRotate90:
    456       RotatePlane90(src_y, src_stride_y,
    457                     dst_y, dst_stride_y,
    458                     width, height);
    459       RotateUV90(src_uv, src_stride_uv,
    460                  dst_u, dst_stride_u,
    461                  dst_v, dst_stride_v,
    462                  halfwidth, halfheight);
    463       return 0;
    464     case kRotate270:
    465       RotatePlane270(src_y, src_stride_y,
    466                      dst_y, dst_stride_y,
    467                      width, height);
    468       RotateUV270(src_uv, src_stride_uv,
    469                   dst_u, dst_stride_u,
    470                   dst_v, dst_stride_v,
    471                   halfwidth, halfheight);
    472       return 0;
    473     case kRotate180:
    474       RotatePlane180(src_y, src_stride_y,
    475                      dst_y, dst_stride_y,
    476                      width, height);
    477       RotateUV180(src_uv, src_stride_uv,
    478                   dst_u, dst_stride_u,
    479                   dst_v, dst_stride_v,
    480                   halfwidth, halfheight);
    481       return 0;
    482     default:
    483       break;
    484   }
    485   return -1;
    486 }
    487 
    488 #ifdef __cplusplus
    489 }  // extern "C"
    490 }  // namespace libyuv
    491 #endif
    492