123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- /*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
- #include "libyuv/rotate.h"
- #include "libyuv/convert.h"
- #include "libyuv/cpu_id.h"
- #include "libyuv/planar_functions.h"
- #include "libyuv/rotate_row.h"
- #include "libyuv/row.h"
- #ifdef __cplusplus
- namespace libyuv {
- extern "C" {
- #endif
- LIBYUV_API
- void TransposePlane(const uint8_t* src,
- int src_stride,
- uint8_t* dst,
- int dst_stride,
- int width,
- int height) {
- int i = height;
- #if defined(HAS_TRANSPOSEWX16_MSA)
- void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst,
- int dst_stride, int width) = TransposeWx16_C;
- #else
- void (*TransposeWx8)(const uint8_t* src, int src_stride, uint8_t* dst,
- int dst_stride, int width) = TransposeWx8_C;
- #endif
- #if defined(HAS_TRANSPOSEWX16_MSA)
- if (TestCpuFlag(kCpuHasMSA)) {
- TransposeWx16 = TransposeWx16_Any_MSA;
- if (IS_ALIGNED(width, 16)) {
- TransposeWx16 = TransposeWx16_MSA;
- }
- }
- #else
- #if defined(HAS_TRANSPOSEWX8_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- TransposeWx8 = TransposeWx8_NEON;
- }
- #endif
- #if defined(HAS_TRANSPOSEWX8_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3)) {
- TransposeWx8 = TransposeWx8_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- TransposeWx8 = TransposeWx8_SSSE3;
- }
- }
- #endif
- #if defined(HAS_TRANSPOSEWX8_MMI)
- if (TestCpuFlag(kCpuHasMMI)) {
- TransposeWx8 = TransposeWx8_MMI;
- }
- #endif
- #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3)) {
- TransposeWx8 = TransposeWx8_Fast_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- TransposeWx8 = TransposeWx8_Fast_SSSE3;
- }
- }
- #endif
- #endif /* defined(HAS_TRANSPOSEWX16_MSA) */
- #if defined(HAS_TRANSPOSEWX16_MSA)
- // Work across the source in 16x16 tiles
- while (i >= 16) {
- TransposeWx16(src, src_stride, dst, dst_stride, width);
- src += 16 * src_stride; // Go down 16 rows.
- dst += 16; // Move over 16 columns.
- i -= 16;
- }
- #else
- // Work across the source in 8x8 tiles
- while (i >= 8) {
- TransposeWx8(src, src_stride, dst, dst_stride, width);
- src += 8 * src_stride; // Go down 8 rows.
- dst += 8; // Move over 8 columns.
- i -= 8;
- }
- #endif
- if (i > 0) {
- TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
- }
- }
- LIBYUV_API
- void RotatePlane90(const uint8_t* src,
- int src_stride,
- uint8_t* dst,
- int dst_stride,
- int width,
- int height) {
- // Rotate by 90 is a transpose with the source read
- // from bottom to top. So set the source pointer to the end
- // of the buffer and flip the sign of the source stride.
- src += src_stride * (height - 1);
- src_stride = -src_stride;
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
- }
- LIBYUV_API
- void RotatePlane270(const uint8_t* src,
- int src_stride,
- uint8_t* dst,
- int dst_stride,
- int width,
- int height) {
- // Rotate by 270 is a transpose with the destination written
- // from bottom to top. So set the destination pointer to the end
- // of the buffer and flip the sign of the destination stride.
- dst += dst_stride * (width - 1);
- dst_stride = -dst_stride;
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
- }
- LIBYUV_API
- void RotatePlane180(const uint8_t* src,
- int src_stride,
- uint8_t* dst,
- int dst_stride,
- int width,
- int height) {
- // Swap first and last row and mirror the content. Uses a temporary row.
- align_buffer_64(row, width);
- const uint8_t* src_bot = src + src_stride * (height - 1);
- uint8_t* dst_bot = dst + dst_stride * (height - 1);
- int half_height = (height + 1) >> 1;
- int y;
- void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C;
- void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
- #if defined(HAS_MIRRORROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- MirrorRow = MirrorRow_Any_NEON;
- if (IS_ALIGNED(width, 32)) {
- MirrorRow = MirrorRow_NEON;
- }
- }
- #endif
- #if defined(HAS_MIRRORROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3)) {
- MirrorRow = MirrorRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- MirrorRow = MirrorRow_SSSE3;
- }
- }
- #endif
- #if defined(HAS_MIRRORROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2)) {
- MirrorRow = MirrorRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- MirrorRow = MirrorRow_AVX2;
- }
- }
- #endif
- #if defined(HAS_MIRRORROW_MMI)
- if (TestCpuFlag(kCpuHasMMI)) {
- MirrorRow = MirrorRow_Any_MMI;
- if (IS_ALIGNED(width, 8)) {
- MirrorRow = MirrorRow_MMI;
- }
- }
- #endif
- #if defined(HAS_MIRRORROW_MSA)
- if (TestCpuFlag(kCpuHasMSA)) {
- MirrorRow = MirrorRow_Any_MSA;
- if (IS_ALIGNED(width, 64)) {
- MirrorRow = MirrorRow_MSA;
- }
- }
- #endif
- #if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
- }
- #endif
- #if defined(HAS_COPYROW_AVX)
- if (TestCpuFlag(kCpuHasAVX)) {
- CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
- }
- #endif
- #if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
- #endif
- #if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
- }
- #endif
- #if defined(HAS_COPYROW_MMI)
- if (TestCpuFlag(kCpuHasMMI)) {
- CopyRow = IS_ALIGNED(width, 8) ? CopyRow_MMI : CopyRow_Any_MMI;
- }
- #endif
- // Odd height will harmlessly mirror the middle row twice.
- for (y = 0; y < half_height; ++y) {
- CopyRow(src, row, width); // Copy first row into buffer
- MirrorRow(src_bot, dst, width); // Mirror last row into first row
- MirrorRow(row, dst_bot, width); // Mirror buffer into last row
- src += src_stride;
- dst += dst_stride;
- src_bot -= src_stride;
- dst_bot -= dst_stride;
- }
- free_aligned_buffer_64(row);
- }
- LIBYUV_API
- void TransposeUV(const uint8_t* src,
- int src_stride,
- uint8_t* dst_a,
- int dst_stride_a,
- uint8_t* dst_b,
- int dst_stride_b,
- int width,
- int height) {
- int i = height;
- #if defined(HAS_TRANSPOSEUVWX16_MSA)
- void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a,
- int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
- int width) = TransposeUVWx16_C;
- #else
- void (*TransposeUVWx8)(const uint8_t* src, int src_stride, uint8_t* dst_a,
- int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
- int width) = TransposeUVWx8_C;
- #endif
- #if defined(HAS_TRANSPOSEUVWX16_MSA)
- if (TestCpuFlag(kCpuHasMSA)) {
- TransposeUVWx16 = TransposeUVWx16_Any_MSA;
- if (IS_ALIGNED(width, 8)) {
- TransposeUVWx16 = TransposeUVWx16_MSA;
- }
- }
- #else
- #if defined(HAS_TRANSPOSEUVWX8_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- TransposeUVWx8 = TransposeUVWx8_NEON;
- }
- #endif
- #if defined(HAS_TRANSPOSEUVWX8_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- TransposeUVWx8 = TransposeUVWx8_SSE2;
- }
- }
- #endif
- #if defined(HAS_TRANSPOSEUVWX8_MMI)
- if (TestCpuFlag(kCpuHasMMI)) {
- TransposeUVWx8 = TransposeUVWx8_Any_MMI;
- if (IS_ALIGNED(width, 4)) {
- TransposeUVWx8 = TransposeUVWx8_MMI;
- }
- }
- #endif
- #endif /* defined(HAS_TRANSPOSEUVWX16_MSA) */
- #if defined(HAS_TRANSPOSEUVWX16_MSA)
- // Work through the source in 8x8 tiles.
- while (i >= 16) {
- TransposeUVWx16(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
- width);
- src += 16 * src_stride; // Go down 16 rows.
- dst_a += 16; // Move over 8 columns.
- dst_b += 16; // Move over 8 columns.
- i -= 16;
- }
- #else
- // Work through the source in 8x8 tiles.
- while (i >= 8) {
- TransposeUVWx8(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
- width);
- src += 8 * src_stride; // Go down 8 rows.
- dst_a += 8; // Move over 8 columns.
- dst_b += 8; // Move over 8 columns.
- i -= 8;
- }
- #endif
- if (i > 0) {
- TransposeUVWxH_C(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
- width, i);
- }
- }
- LIBYUV_API
- void RotateUV90(const uint8_t* src,
- int src_stride,
- uint8_t* dst_a,
- int dst_stride_a,
- uint8_t* dst_b,
- int dst_stride_b,
- int width,
- int height) {
- src += src_stride * (height - 1);
- src_stride = -src_stride;
- TransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, width,
- height);
- }
- LIBYUV_API
- void RotateUV270(const uint8_t* src,
- int src_stride,
- uint8_t* dst_a,
- int dst_stride_a,
- uint8_t* dst_b,
- int dst_stride_b,
- int width,
- int height) {
- dst_a += dst_stride_a * (width - 1);
- dst_b += dst_stride_b * (width - 1);
- dst_stride_a = -dst_stride_a;
- dst_stride_b = -dst_stride_b;
- TransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, width,
- height);
- }
- // Rotate 180 is a horizontal and vertical flip.
- LIBYUV_API
- void RotateUV180(const uint8_t* src,
- int src_stride,
- uint8_t* dst_a,
- int dst_stride_a,
- uint8_t* dst_b,
- int dst_stride_b,
- int width,
- int height) {
- int i;
- void (*MirrorSplitUVRow)(const uint8_t* src, uint8_t* dst_u, uint8_t* dst_v,
- int width) = MirrorSplitUVRow_C;
- #if defined(HAS_MIRRORSPLITUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
- MirrorSplitUVRow = MirrorSplitUVRow_NEON;
- }
- #endif
- #if defined(HAS_MIRRORSPLITUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
- MirrorSplitUVRow = MirrorSplitUVRow_SSSE3;
- }
- #endif
- #if defined(HAS_MIRRORSPLITUVROW_MMI)
- if (TestCpuFlag(kCpuHasMMI) && IS_ALIGNED(width, 8)) {
- MirrorSplitUVRow = MirrorSplitUVRow_MMI;
- }
- #endif
- #if defined(HAS_MIRRORSPLITUVROW_MSA)
- if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 32)) {
- MirrorSplitUVRow = MirrorSplitUVRow_MSA;
- }
- #endif
- dst_a += dst_stride_a * (height - 1);
- dst_b += dst_stride_b * (height - 1);
- for (i = 0; i < height; ++i) {
- MirrorSplitUVRow(src, dst_a, dst_b, width);
- src += src_stride;
- dst_a -= dst_stride_a;
- dst_b -= dst_stride_b;
- }
- }
- LIBYUV_API
- int RotatePlane(const uint8_t* src,
- int src_stride,
- uint8_t* dst,
- int dst_stride,
- int width,
- int height,
- enum RotationMode mode) {
- if (!src || width <= 0 || height == 0 || !dst) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src = src + (height - 1) * src_stride;
- src_stride = -src_stride;
- }
- switch (mode) {
- case kRotate0:
- // copy frame
- CopyPlane(src, src_stride, dst, dst_stride, width, height);
- return 0;
- case kRotate90:
- RotatePlane90(src, src_stride, dst, dst_stride, width, height);
- return 0;
- case kRotate270:
- RotatePlane270(src, src_stride, dst, dst_stride, width, height);
- return 0;
- case kRotate180:
- RotatePlane180(src, src_stride, dst, dst_stride, width, height);
- return 0;
- default:
- break;
- }
- return -1;
- }
- LIBYUV_API
- int I420Rotate(const uint8_t* src_y,
- int src_stride_y,
- const uint8_t* src_u,
- int src_stride_u,
- const uint8_t* src_v,
- int src_stride_v,
- uint8_t* dst_y,
- int dst_stride_y,
- uint8_t* dst_u,
- int dst_stride_u,
- uint8_t* dst_v,
- int dst_stride_v,
- int width,
- int height,
- enum RotationMode mode) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
- !dst_u || !dst_v) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (halfheight - 1) * src_stride_u;
- src_v = src_v + (halfheight - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
- switch (mode) {
- case kRotate0:
- // copy frame
- return I420Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
- src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
- dst_v, dst_stride_v, width, height);
- case kRotate90:
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
- halfheight);
- RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
- halfheight);
- return 0;
- case kRotate270:
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
- halfheight);
- RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
- halfheight);
- return 0;
- case kRotate180:
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
- halfheight);
- RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
- halfheight);
- return 0;
- default:
- break;
- }
- return -1;
- }
- LIBYUV_API
- int I444Rotate(const uint8_t* src_y,
- int src_stride_y,
- const uint8_t* src_u,
- int src_stride_u,
- const uint8_t* src_v,
- int src_stride_v,
- uint8_t* dst_y,
- int dst_stride_y,
- uint8_t* dst_u,
- int dst_stride_u,
- uint8_t* dst_v,
- int dst_stride_v,
- int width,
- int height,
- enum libyuv::RotationMode mode) {
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
- !dst_u || !dst_v) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (height - 1) * src_stride_u;
- src_v = src_v + (height - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
- switch (mode) {
- case libyuv::kRotate0:
- // copy frame
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
- return 0;
- case libyuv::kRotate90:
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
- RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
- return 0;
- case libyuv::kRotate270:
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
- RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
- return 0;
- case libyuv::kRotate180:
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
- RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
- return 0;
- default:
- break;
- }
- return -1;
- }
- LIBYUV_API
- int NV12ToI420Rotate(const uint8_t* src_y,
- int src_stride_y,
- const uint8_t* src_uv,
- int src_stride_uv,
- uint8_t* dst_y,
- int dst_stride_y,
- uint8_t* dst_u,
- int dst_stride_u,
- uint8_t* dst_v,
- int dst_stride_v,
- int width,
- int height,
- enum RotationMode mode) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (!src_y || !src_uv || width <= 0 || height == 0 || !dst_y || !dst_u ||
- !dst_v) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_uv = src_uv + (halfheight - 1) * src_stride_uv;
- src_stride_y = -src_stride_y;
- src_stride_uv = -src_stride_uv;
- }
- switch (mode) {
- case kRotate0:
- // copy frame
- return NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
- dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
- width, height);
- case kRotate90:
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
- dst_stride_v, halfwidth, halfheight);
- return 0;
- case kRotate270:
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
- dst_stride_v, halfwidth, halfheight);
- return 0;
- case kRotate180:
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- RotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
- dst_stride_v, halfwidth, halfheight);
- return 0;
- default:
- break;
- }
- return -1;
- }
- #ifdef __cplusplus
- } // extern "C"
- } // namespace libyuv
- #endif
|