133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp/* 233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * Copyright 2012 The LibYuv Project Authors. All rights reserved. 333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * 433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * Use of this source code is governed by a BSD-style license 533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * that can be found in the LICENSE file in the root of the source 633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * tree. An additional intellectual property rights grant can be found 733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * in the file PATENTS. All contributing project authors may 833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp * be found in the AUTHORS file in the root of the source tree. 933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp */ 1033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 1133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#include "libyuv/rotate.h" 1233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 1333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#include "libyuv/cpu_id.h" 1433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#include "libyuv/convert.h" 1533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#include "libyuv/planar_functions.h" 1633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#include "libyuv/row.h" 1733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 1833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#ifdef __cplusplus 1933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampnamespace libyuv { 2033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampextern "C" { 2133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 2233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 2333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp// ARGBScale has a function to copy pixels to a row, striding each source 2433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp// pixel by a constant. 2533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if !defined(YUV_DISABLE_ASM) && (defined(_M_IX86) || \ 2633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp defined(__x86_64__) || defined(__i386__)) 2733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#define HAS_SCALEARGBROWDOWNEVEN_SSE2 2833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampvoid ScaleARGBRowDownEven_SSE2(const uint8* src_ptr, int src_stride, 2933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int src_stepx, 3033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst_ptr, int dst_width); 3133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 3233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampvoid ScaleARGBRowDownEven_C(const uint8* src_ptr, int, 3333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int src_stepx, 3433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst_ptr, int dst_width); 3533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 3633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampstatic void ARGBTranspose(const uint8* src, int src_stride, 3733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst, int dst_stride, 3833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int width, int height) { 3933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp void (*ScaleARGBRowDownEven)(const uint8* src_ptr, int src_stride, 4033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int src_step, uint8* dst_ptr, int dst_width) = ScaleARGBRowDownEven_C; 4133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2) 4233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (TestCpuFlag(kCpuHasSSE2) && 4333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(height, 4) && // width of dest. 4433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) { 4533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ScaleARGBRowDownEven = ScaleARGBRowDownEven_SSE2; 4633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 4733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 4833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 4933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int src_pixel_step = src_stride / 4; 5033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp for (int i = 0; i < width; ++i) { // column of source to row of dest. 5133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ScaleARGBRowDownEven(src, 0, src_pixel_step, dst, height); 5233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst += dst_stride; 5333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src += 4; 5433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 5533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} 5633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 5733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampvoid ARGBRotate90(const uint8* src, int src_stride, 5833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst, int dst_stride, 5933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int width, int height) { 6033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // Rotate by 90 is a ARGBTranspose with the source read 6133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // from bottom to top. So set the source pointer to the end 6233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // of the buffer and flip the sign of the source stride. 6333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src += src_stride * (height - 1); 6433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src_stride = -src_stride; 6533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBTranspose(src, src_stride, dst, dst_stride, width, height); 6633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} 6733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 6833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampvoid ARGBRotate270(const uint8* src, int src_stride, 6933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst, int dst_stride, 7033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int width, int height) { 7133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // Rotate by 270 is a ARGBTranspose with the destination written 7233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // from bottom to top. So set the destination pointer to the end 7333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // of the buffer and flip the sign of the destination stride. 7433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst += dst_stride * (width - 1); 7533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_stride = -dst_stride; 7633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBTranspose(src, src_stride, dst, dst_stride, width, height); 7733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} 7833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 7933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampvoid ARGBRotate180(const uint8* src, int src_stride, 8033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst, int dst_stride, 8133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int width, int height) { 8233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) = 8333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBMirrorRow_C; 8433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if defined(HAS_ARGBMIRRORROW_SSSE3) 8533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4) && 8633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) && 8733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) { 8833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBMirrorRow = ARGBMirrorRow_SSSE3; 8933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 9033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 9133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 9233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if defined(HAS_COPYROW_NEON) 9333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width * 4, 64)) { 9433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp CopyRow = CopyRow_NEON; 9533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 9633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 9733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if defined(HAS_COPYROW_X86) 9833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (TestCpuFlag(kCpuHasX86)) { 9933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp CopyRow = CopyRow_X86; 10033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 10133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 10233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#if defined(HAS_COPYROW_SSE2) 10333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width * 4, 32) && 10433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) && 10533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) { 10633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp CopyRow = CopyRow_SSE2; 10733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 10833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 10933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (width * 4 > kMaxStride) { 11033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return; 11133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 11233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // Swap first and last row and mirror the content. Uses a temporary row. 11333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp SIMD_ALIGNED(uint8 row[kMaxStride]); 11433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp const uint8* src_bot = src + src_stride * (height - 1); 11533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst_bot = dst + dst_stride * (height - 1); 11633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int half_height = (height + 1) >> 1; 11733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // Odd height will harmlessly mirror the middle row twice. 11833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp for (int y = 0; y < half_height; ++y) { 11933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBMirrorRow(src, row, width); // Mirror first row into a buffer 12033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src += src_stride; 12133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBMirrorRow(src_bot, dst, width); // Mirror last row into first row 12233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst += dst_stride; 12333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp CopyRow(row, dst_bot, width * 4); // Copy first mirrored row into last 12433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src_bot -= src_stride; 12533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_bot -= dst_stride; 12633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 12733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} 12833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 12933cfdeb7b267ab635413797fffb046b73272f7ecHendrik DahlkampLIBYUV_API 13033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkampint ARGBRotate(const uint8* src_argb, int src_stride_argb, 13133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp uint8* dst_argb, int dst_stride_argb, 13233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp int width, int height, 13333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp RotationMode mode) { 13433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (!src_argb || width <= 0 || height == 0 || !dst_argb) { 13533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return -1; 13633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 13733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 13833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // Negative height means invert the image. 13933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp if (height < 0) { 14033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp height = -height; 14133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src_argb = src_argb + (height - 1) * src_stride_argb; 14233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp src_stride_argb = -src_stride_argb; 14333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 14433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 14533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp switch (mode) { 14633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp case kRotate0: 14733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp // copy frame 14833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return ARGBCopy(src_argb, src_stride_argb, 14933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_argb, dst_stride_argb, 15033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp width, height); 15133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp case kRotate90: 15233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBRotate90(src_argb, src_stride_argb, 15333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_argb, dst_stride_argb, 15433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp width, height); 15533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return 0; 15633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp case kRotate270: 15733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBRotate270(src_argb, src_stride_argb, 15833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_argb, dst_stride_argb, 15933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp width, height); 16033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return 0; 16133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp case kRotate180: 16233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp ARGBRotate180(src_argb, src_stride_argb, 16333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp dst_argb, dst_stride_argb, 16433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp width, height); 16533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return 0; 16633cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp default: 16733cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp break; 16833cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp } 16933cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp return -1; 17033cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} 17133cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp 17233cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#ifdef __cplusplus 17333cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} // extern "C" 17433cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp} // namespace libyuv 17533cfdeb7b267ab635413797fffb046b73272f7ecHendrik Dahlkamp#endif 176