react-native-vision-camera-spoof-detector 1.0.22 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +442 -442
  2. package/android/build.gradle +12 -4
  3. package/android/src/main/cpp/CMakeLists.txt +101 -94
  4. package/android/src/main/cpp/libyuv/.clang-format +6 -6
  5. package/android/src/main/cpp/libyuv/.gn +40 -40
  6. package/android/src/main/cpp/libyuv/.vpython3 +410 -410
  7. package/android/src/main/cpp/libyuv/AUTHORS +7 -7
  8. package/android/src/main/cpp/libyuv/Android.bp +202 -202
  9. package/android/src/main/cpp/libyuv/Android.mk +106 -106
  10. package/android/src/main/cpp/libyuv/BUILD.gn +490 -490
  11. package/android/src/main/cpp/libyuv/CM_linux_packages.cmake +70 -70
  12. package/android/src/main/cpp/libyuv/CMakeLists.txt +259 -252
  13. package/android/src/main/cpp/libyuv/DEPS +935 -935
  14. package/android/src/main/cpp/libyuv/DIR_METADATA +3 -3
  15. package/android/src/main/cpp/libyuv/LICENSE +29 -29
  16. package/android/src/main/cpp/libyuv/OWNERS +11 -11
  17. package/android/src/main/cpp/libyuv/PATENTS +23 -23
  18. package/android/src/main/cpp/libyuv/PRESUBMIT.py +65 -65
  19. package/android/src/main/cpp/libyuv/README.chromium +11 -11
  20. package/android/src/main/cpp/libyuv/README.md +19 -19
  21. package/android/src/main/cpp/libyuv/build_overrides/build.gni +60 -60
  22. package/android/src/main/cpp/libyuv/build_overrides/gtest.gni +19 -19
  23. package/android/src/main/cpp/libyuv/build_overrides/partition_alloc.gni +17 -17
  24. package/android/src/main/cpp/libyuv/codereview.settings +5 -5
  25. package/android/src/main/cpp/libyuv/docs/deprecated_builds.md +409 -409
  26. package/android/src/main/cpp/libyuv/docs/environment_variables.md +64 -64
  27. package/android/src/main/cpp/libyuv/docs/feature_detection.md +108 -108
  28. package/android/src/main/cpp/libyuv/docs/filtering.md +196 -196
  29. package/android/src/main/cpp/libyuv/docs/formats.md +208 -208
  30. package/android/src/main/cpp/libyuv/docs/getting_started.md +296 -296
  31. package/android/src/main/cpp/libyuv/docs/rotation.md +107 -107
  32. package/android/src/main/cpp/libyuv/download_vs_toolchain.py +29 -29
  33. package/android/src/main/cpp/libyuv/include/libyuv/basic_types.h +68 -68
  34. package/android/src/main/cpp/libyuv/include/libyuv/compare.h +111 -111
  35. package/android/src/main/cpp/libyuv/include/libyuv/compare_row.h +112 -112
  36. package/android/src/main/cpp/libyuv/include/libyuv/convert.h +1117 -1117
  37. package/android/src/main/cpp/libyuv/include/libyuv/convert_argb.h +2335 -2335
  38. package/android/src/main/cpp/libyuv/include/libyuv/convert_from.h +203 -203
  39. package/android/src/main/cpp/libyuv/include/libyuv/convert_from_argb.h +394 -394
  40. package/android/src/main/cpp/libyuv/include/libyuv/cpu_id.h +147 -147
  41. package/android/src/main/cpp/libyuv/include/libyuv/cpu_support.h +99 -99
  42. package/android/src/main/cpp/libyuv/include/libyuv/loongson_intrinsics.h +1949 -1949
  43. package/android/src/main/cpp/libyuv/include/libyuv/mjpeg_decoder.h +195 -195
  44. package/android/src/main/cpp/libyuv/include/libyuv/planar_functions.h +1131 -1131
  45. package/android/src/main/cpp/libyuv/include/libyuv/rotate.h +296 -296
  46. package/android/src/main/cpp/libyuv/include/libyuv/rotate_argb.h +37 -37
  47. package/android/src/main/cpp/libyuv/include/libyuv/rotate_row.h +265 -265
  48. package/android/src/main/cpp/libyuv/include/libyuv/row.h +6738 -6738
  49. package/android/src/main/cpp/libyuv/include/libyuv/row_sve.h +2154 -2154
  50. package/android/src/main/cpp/libyuv/include/libyuv/scale.h +336 -336
  51. package/android/src/main/cpp/libyuv/include/libyuv/scale_argb.h +76 -76
  52. package/android/src/main/cpp/libyuv/include/libyuv/scale_rgb.h +42 -42
  53. package/android/src/main/cpp/libyuv/include/libyuv/scale_row.h +1726 -1726
  54. package/android/src/main/cpp/libyuv/include/libyuv/scale_uv.h +51 -51
  55. package/android/src/main/cpp/libyuv/include/libyuv/version.h +16 -16
  56. package/android/src/main/cpp/libyuv/include/libyuv/video_common.h +222 -222
  57. package/android/src/main/cpp/libyuv/include/libyuv.h +33 -33
  58. package/android/src/main/cpp/libyuv/infra/config/OWNERS +3 -3
  59. package/android/src/main/cpp/libyuv/infra/config/PRESUBMIT.py +17 -17
  60. package/android/src/main/cpp/libyuv/infra/config/README.md +2 -2
  61. package/android/src/main/cpp/libyuv/infra/config/codereview.settings +6 -6
  62. package/android/src/main/cpp/libyuv/infra/config/commit-queue.cfg +144 -144
  63. package/android/src/main/cpp/libyuv/infra/config/cr-buildbucket.cfg +1185 -1185
  64. package/android/src/main/cpp/libyuv/infra/config/luci-logdog.cfg +9 -9
  65. package/android/src/main/cpp/libyuv/infra/config/luci-milo.cfg +246 -246
  66. package/android/src/main/cpp/libyuv/infra/config/luci-scheduler.cfg +385 -385
  67. package/android/src/main/cpp/libyuv/infra/config/main.star +402 -402
  68. package/android/src/main/cpp/libyuv/infra/config/project.cfg +16 -16
  69. package/android/src/main/cpp/libyuv/infra/config/realms.cfg +111 -111
  70. package/android/src/main/cpp/libyuv/libyuv.gni +34 -34
  71. package/android/src/main/cpp/libyuv/libyuv.gyp +149 -149
  72. package/android/src/main/cpp/libyuv/libyuv.gypi +87 -87
  73. package/android/src/main/cpp/libyuv/linux.mk +96 -96
  74. package/android/src/main/cpp/libyuv/public.mk +13 -13
  75. package/android/src/main/cpp/libyuv/pylintrc +49 -49
  76. package/android/src/main/cpp/libyuv/riscv_script/prepare_toolchain_qemu.sh +74 -74
  77. package/android/src/main/cpp/libyuv/riscv_script/riscv-clang.cmake +56 -56
  78. package/android/src/main/cpp/libyuv/riscv_script/run_qemu.sh +15 -15
  79. package/android/src/main/cpp/libyuv/source/compare.cc +435 -435
  80. package/android/src/main/cpp/libyuv/source/compare_common.cc +74 -74
  81. package/android/src/main/cpp/libyuv/source/compare_gcc.cc +362 -362
  82. package/android/src/main/cpp/libyuv/source/compare_neon.cc +96 -96
  83. package/android/src/main/cpp/libyuv/source/compare_neon64.cc +223 -223
  84. package/android/src/main/cpp/libyuv/source/compare_win.cc +241 -241
  85. package/android/src/main/cpp/libyuv/source/convert.cc +4746 -4746
  86. package/android/src/main/cpp/libyuv/source/convert_argb.cc +9179 -9179
  87. package/android/src/main/cpp/libyuv/source/convert_from.cc +866 -866
  88. package/android/src/main/cpp/libyuv/source/convert_from_argb.cc +3671 -3671
  89. package/android/src/main/cpp/libyuv/source/convert_jpeg.cc +602 -602
  90. package/android/src/main/cpp/libyuv/source/convert_to_argb.cc +391 -391
  91. package/android/src/main/cpp/libyuv/source/convert_to_i420.cc +288 -288
  92. package/android/src/main/cpp/libyuv/source/cpu_id.cc +496 -496
  93. package/android/src/main/cpp/libyuv/source/mjpeg_decoder.cc +580 -580
  94. package/android/src/main/cpp/libyuv/source/mjpeg_validate.cc +71 -71
  95. package/android/src/main/cpp/libyuv/source/planar_functions.cc +5663 -5663
  96. package/android/src/main/cpp/libyuv/source/rotate.cc +1241 -1241
  97. package/android/src/main/cpp/libyuv/source/rotate_any.cc +76 -76
  98. package/android/src/main/cpp/libyuv/source/rotate_argb.cc +259 -259
  99. package/android/src/main/cpp/libyuv/source/rotate_common.cc +208 -208
  100. package/android/src/main/cpp/libyuv/source/rotate_gcc.cc +505 -505
  101. package/android/src/main/cpp/libyuv/source/rotate_lsx.cc +233 -233
  102. package/android/src/main/cpp/libyuv/source/rotate_neon.cc +219 -219
  103. package/android/src/main/cpp/libyuv/source/rotate_neon64.cc +273 -273
  104. package/android/src/main/cpp/libyuv/source/rotate_sme.cc +174 -174
  105. package/android/src/main/cpp/libyuv/source/rotate_win.cc +253 -253
  106. package/android/src/main/cpp/libyuv/source/row_any.cc +2519 -2519
  107. package/android/src/main/cpp/libyuv/source/row_common.cc +4461 -4461
  108. package/android/src/main/cpp/libyuv/source/row_gcc.cc +9570 -9570
  109. package/android/src/main/cpp/libyuv/source/row_lasx.cc +2343 -2343
  110. package/android/src/main/cpp/libyuv/source/row_lsx.cc +3030 -3030
  111. package/android/src/main/cpp/libyuv/source/row_neon.cc +4026 -4026
  112. package/android/src/main/cpp/libyuv/source/row_neon64.cc +5617 -5617
  113. package/android/src/main/cpp/libyuv/source/row_rvv.cc +2599 -2599
  114. package/android/src/main/cpp/libyuv/source/row_sme.cc +1183 -1183
  115. package/android/src/main/cpp/libyuv/source/row_sve.cc +1088 -1088
  116. package/android/src/main/cpp/libyuv/source/row_win.cc +6453 -6453
  117. package/android/src/main/cpp/libyuv/source/scale.cc +2710 -2710
  118. package/android/src/main/cpp/libyuv/source/scale_any.cc +991 -991
  119. package/android/src/main/cpp/libyuv/source/scale_argb.cc +1158 -1158
  120. package/android/src/main/cpp/libyuv/source/scale_common.cc +1977 -1977
  121. package/android/src/main/cpp/libyuv/source/scale_gcc.cc +2947 -2947
  122. package/android/src/main/cpp/libyuv/source/scale_lsx.cc +739 -739
  123. package/android/src/main/cpp/libyuv/source/scale_neon.cc +1449 -1449
  124. package/android/src/main/cpp/libyuv/source/scale_neon64.cc +1552 -1552
  125. package/android/src/main/cpp/libyuv/source/scale_rgb.cc +82 -82
  126. package/android/src/main/cpp/libyuv/source/scale_rvv.cc +1971 -1971
  127. package/android/src/main/cpp/libyuv/source/scale_sme.cc +555 -555
  128. package/android/src/main/cpp/libyuv/source/scale_uv.cc +1159 -1159
  129. package/android/src/main/cpp/libyuv/source/scale_win.cc +1392 -1392
  130. package/android/src/main/cpp/libyuv/source/test.sh +35 -35
  131. package/android/src/main/cpp/libyuv/source/video_common.cc +62 -62
  132. package/android/src/main/cpp/libyuv/tools_libyuv/OWNERS +4 -4
  133. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/roll_deps.py +931 -931
  134. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py +164 -164
  135. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS +21 -21
  136. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium.new +13 -13
  137. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium.old +13 -13
  138. package/android/src/main/cpp/libyuv/tools_libyuv/get_landmines.py +38 -38
  139. package/android/src/main/cpp/libyuv/tools_libyuv/msan/OWNERS +3 -3
  140. package/android/src/main/cpp/libyuv/tools_libyuv/msan/blacklist.txt +9 -9
  141. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/OWNERS +3 -3
  142. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/blacklist.txt +15 -15
  143. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/vptr_blacklist.txt +25 -25
  144. package/android/src/main/cpp/libyuv/unit_test/basictypes_test.cc +43 -43
  145. package/android/src/main/cpp/libyuv/unit_test/color_test.cc +848 -848
  146. package/android/src/main/cpp/libyuv/unit_test/compare_test.cc +739 -739
  147. package/android/src/main/cpp/libyuv/unit_test/convert_argb_test.cc +2867 -2867
  148. package/android/src/main/cpp/libyuv/unit_test/convert_test.cc +2133 -2133
  149. package/android/src/main/cpp/libyuv/unit_test/cpu_test.cc +427 -427
  150. package/android/src/main/cpp/libyuv/unit_test/cpu_thread_test.cc +63 -63
  151. package/android/src/main/cpp/libyuv/unit_test/math_test.cc +160 -160
  152. package/android/src/main/cpp/libyuv/unit_test/planar_test.cc +4731 -4731
  153. package/android/src/main/cpp/libyuv/unit_test/rotate_argb_test.cc +334 -334
  154. package/android/src/main/cpp/libyuv/unit_test/rotate_test.cc +962 -962
  155. package/android/src/main/cpp/libyuv/unit_test/scale_argb_test.cc +590 -590
  156. package/android/src/main/cpp/libyuv/unit_test/scale_plane_test.cc +465 -465
  157. package/android/src/main/cpp/libyuv/unit_test/scale_rgb_test.cc +280 -280
  158. package/android/src/main/cpp/libyuv/unit_test/scale_test.cc +1135 -1135
  159. package/android/src/main/cpp/libyuv/unit_test/scale_uv_test.cc +249 -249
  160. package/android/src/main/cpp/libyuv/unit_test/testdata/arm_v7.txt +12 -12
  161. package/android/src/main/cpp/libyuv/unit_test/testdata/mips.txt +7 -7
  162. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson2k.txt +5 -5
  163. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson3.txt +10 -10
  164. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson_mmi.txt +7 -7
  165. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64.txt +3 -3
  166. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64_rvv.txt +3 -3
  167. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64_rvv_zvfh.txt +3 -3
  168. package/android/src/main/cpp/libyuv/unit_test/testdata/tegra3.txt +23 -23
  169. package/android/src/main/cpp/libyuv/unit_test/unit_test.cc +581 -581
  170. package/android/src/main/cpp/libyuv/unit_test/unit_test.h +232 -232
  171. package/android/src/main/cpp/libyuv/unit_test/video_common_test.cc +112 -112
  172. package/android/src/main/cpp/libyuv/util/Makefile +9 -9
  173. package/android/src/main/cpp/libyuv/util/color.cc +120 -120
  174. package/android/src/main/cpp/libyuv/util/compare.cc +67 -67
  175. package/android/src/main/cpp/libyuv/util/cpuid.c +211 -211
  176. package/android/src/main/cpp/libyuv/util/i444tonv12_eg.cc +27 -27
  177. package/android/src/main/cpp/libyuv/util/psnr.cc +291 -291
  178. package/android/src/main/cpp/libyuv/util/psnr.h +47 -47
  179. package/android/src/main/cpp/libyuv/util/psnr_main.cc +620 -620
  180. package/android/src/main/cpp/libyuv/util/ssim.cc +364 -364
  181. package/android/src/main/cpp/libyuv/util/ssim.h +38 -38
  182. package/android/src/main/cpp/libyuv/util/yuvconstants.c +114 -114
  183. package/android/src/main/cpp/libyuv/util/yuvconvert.cc +367 -367
  184. package/android/src/main/cpp/libyuv/winarm.mk +47 -47
  185. package/package.json +86 -86
  186. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  187. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  188. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  189. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  190. package/android/.gradle/8.9/gc.properties +0 -0
  191. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  192. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  193. package/android/.gradle/vcs-1/gc.properties +0 -0
@@ -1,1241 +1,1241 @@
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 <assert.h>
12
-
13
- #include "libyuv/rotate.h"
14
-
15
- #include "libyuv/convert.h"
16
- #include "libyuv/cpu_id.h"
17
- #include "libyuv/planar_functions.h"
18
- #include "libyuv/rotate_row.h"
19
- #include "libyuv/row.h"
20
-
21
- #ifdef __cplusplus
22
- namespace libyuv {
23
- extern "C" {
24
- #endif
25
-
26
- LIBYUV_API
27
- void TransposePlane(const uint8_t* src,
28
- int src_stride,
29
- uint8_t* dst,
30
- int dst_stride,
31
- int width,
32
- int height) {
33
- int i = height;
34
- #if defined(HAS_TRANSPOSEWXH_SME)
35
- void (*TransposeWxH)(const uint8_t* src, int src_stride, uint8_t* dst,
36
- int dst_stride, int width, int height) = NULL;
37
- #endif
38
- #if defined(HAS_TRANSPOSEWX16_LSX) || defined(HAS_TRANSPOSEWX16_NEON)
39
- void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst,
40
- int dst_stride, int width) = TransposeWx16_C;
41
- #else
42
- void (*TransposeWx8)(const uint8_t* src, int src_stride, uint8_t* dst,
43
- int dst_stride, int width) = TransposeWx8_C;
44
- #endif
45
-
46
- #if defined(HAS_TRANSPOSEWX8_NEON)
47
- if (TestCpuFlag(kCpuHasNEON)) {
48
- TransposeWx8 = TransposeWx8_Any_NEON;
49
- if (IS_ALIGNED(width, 8)) {
50
- TransposeWx8 = TransposeWx8_NEON;
51
- }
52
- }
53
- #endif
54
- #if defined(HAS_TRANSPOSEWX16_NEON)
55
- if (TestCpuFlag(kCpuHasNEON)) {
56
- TransposeWx16 = TransposeWx16_Any_NEON;
57
- if (IS_ALIGNED(width, 16)) {
58
- TransposeWx16 = TransposeWx16_NEON;
59
- }
60
- }
61
- #endif
62
- #if defined(HAS_TRANSPOSEWXH_SME)
63
- if (TestCpuFlag(kCpuHasSME)) {
64
- TransposeWxH = TransposeWxH_SME;
65
- }
66
- #endif
67
- #if defined(HAS_TRANSPOSEWX8_SSSE3)
68
- if (TestCpuFlag(kCpuHasSSSE3)) {
69
- TransposeWx8 = TransposeWx8_Any_SSSE3;
70
- if (IS_ALIGNED(width, 8)) {
71
- TransposeWx8 = TransposeWx8_SSSE3;
72
- }
73
- }
74
- #endif
75
- #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3)
76
- if (TestCpuFlag(kCpuHasSSSE3)) {
77
- TransposeWx8 = TransposeWx8_Fast_Any_SSSE3;
78
- if (IS_ALIGNED(width, 16)) {
79
- TransposeWx8 = TransposeWx8_Fast_SSSE3;
80
- }
81
- }
82
- #endif
83
- #if defined(HAS_TRANSPOSEWX16_LSX)
84
- if (TestCpuFlag(kCpuHasLSX)) {
85
- TransposeWx16 = TransposeWx16_Any_LSX;
86
- if (IS_ALIGNED(width, 16)) {
87
- TransposeWx16 = TransposeWx16_LSX;
88
- }
89
- }
90
- #endif
91
-
92
- #if defined(HAS_TRANSPOSEWXH_SME)
93
- if (TransposeWxH) {
94
- TransposeWxH(src, src_stride, dst, dst_stride, width, height);
95
- return;
96
- }
97
- #endif
98
- #if defined(HAS_TRANSPOSEWX16_LSX) || defined(HAS_TRANSPOSEWX16_NEON)
99
- // Work across the source in 16x16 tiles
100
- while (i >= 16) {
101
- TransposeWx16(src, src_stride, dst, dst_stride, width);
102
- src += 16 * src_stride; // Go down 16 rows.
103
- dst += 16; // Move over 16 columns.
104
- i -= 16;
105
- }
106
- #else
107
- // Work across the source in 8x8 tiles
108
- while (i >= 8) {
109
- TransposeWx8(src, src_stride, dst, dst_stride, width);
110
- src += 8 * src_stride; // Go down 8 rows.
111
- dst += 8; // Move over 8 columns.
112
- i -= 8;
113
- }
114
- #endif
115
-
116
- if (i > 0) {
117
- TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
118
- }
119
- }
120
-
121
- LIBYUV_API
122
- void RotatePlane90(const uint8_t* src,
123
- int src_stride,
124
- uint8_t* dst,
125
- int dst_stride,
126
- int width,
127
- int height) {
128
- // Rotate by 90 is a transpose with the source read
129
- // from bottom to top. So set the source pointer to the end
130
- // of the buffer and flip the sign of the source stride.
131
- src += src_stride * (height - 1);
132
- src_stride = -src_stride;
133
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
134
- }
135
-
136
- LIBYUV_API
137
- void RotatePlane270(const uint8_t* src,
138
- int src_stride,
139
- uint8_t* dst,
140
- int dst_stride,
141
- int width,
142
- int height) {
143
- // Rotate by 270 is a transpose with the destination written
144
- // from bottom to top. So set the destination pointer to the end
145
- // of the buffer and flip the sign of the destination stride.
146
- dst += dst_stride * (width - 1);
147
- dst_stride = -dst_stride;
148
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
149
- }
150
-
151
- LIBYUV_API
152
- void RotatePlane180(const uint8_t* src,
153
- int src_stride,
154
- uint8_t* dst,
155
- int dst_stride,
156
- int width,
157
- int height) {
158
- // Swap top and bottom row and mirror the content. Uses a temporary row.
159
- align_buffer_64(row, width);
160
- assert(row);
161
- if (!row)
162
- return;
163
- const uint8_t* src_bot = src + src_stride * (height - 1);
164
- uint8_t* dst_bot = dst + dst_stride * (height - 1);
165
- int half_height = (height + 1) >> 1;
166
- int y;
167
- void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C;
168
- void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
169
- #if defined(HAS_MIRRORROW_NEON)
170
- if (TestCpuFlag(kCpuHasNEON)) {
171
- MirrorRow = MirrorRow_Any_NEON;
172
- if (IS_ALIGNED(width, 32)) {
173
- MirrorRow = MirrorRow_NEON;
174
- }
175
- }
176
- #endif
177
- #if defined(HAS_MIRRORROW_SSSE3)
178
- if (TestCpuFlag(kCpuHasSSSE3)) {
179
- MirrorRow = MirrorRow_Any_SSSE3;
180
- if (IS_ALIGNED(width, 16)) {
181
- MirrorRow = MirrorRow_SSSE3;
182
- }
183
- }
184
- #endif
185
- #if defined(HAS_MIRRORROW_AVX2)
186
- if (TestCpuFlag(kCpuHasAVX2)) {
187
- MirrorRow = MirrorRow_Any_AVX2;
188
- if (IS_ALIGNED(width, 32)) {
189
- MirrorRow = MirrorRow_AVX2;
190
- }
191
- }
192
- #endif
193
- #if defined(HAS_MIRRORROW_LSX)
194
- if (TestCpuFlag(kCpuHasLSX)) {
195
- MirrorRow = MirrorRow_Any_LSX;
196
- if (IS_ALIGNED(width, 32)) {
197
- MirrorRow = MirrorRow_LSX;
198
- }
199
- }
200
- #endif
201
- #if defined(HAS_MIRRORROW_LASX)
202
- if (TestCpuFlag(kCpuHasLASX)) {
203
- MirrorRow = MirrorRow_Any_LASX;
204
- if (IS_ALIGNED(width, 64)) {
205
- MirrorRow = MirrorRow_LASX;
206
- }
207
- }
208
- #endif
209
- #if defined(HAS_COPYROW_SSE2)
210
- if (TestCpuFlag(kCpuHasSSE2)) {
211
- CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
212
- }
213
- #endif
214
- #if defined(HAS_COPYROW_AVX)
215
- if (TestCpuFlag(kCpuHasAVX)) {
216
- CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
217
- }
218
- #endif
219
- #if defined(HAS_COPYROW_AVX512BW)
220
- if (TestCpuFlag(kCpuHasAVX512BW)) {
221
- CopyRow = IS_ALIGNED(width, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW;
222
- }
223
- #endif
224
- #if defined(HAS_COPYROW_ERMS)
225
- if (TestCpuFlag(kCpuHasERMS)) {
226
- CopyRow = CopyRow_ERMS;
227
- }
228
- #endif
229
- #if defined(HAS_COPYROW_NEON)
230
- if (TestCpuFlag(kCpuHasNEON)) {
231
- CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
232
- }
233
- #endif
234
- #if defined(HAS_COPYROW_SME)
235
- if (TestCpuFlag(kCpuHasSME)) {
236
- CopyRow = CopyRow_SME;
237
- }
238
- #endif
239
- #if defined(HAS_COPYROW_RVV)
240
- if (TestCpuFlag(kCpuHasRVV)) {
241
- CopyRow = CopyRow_RVV;
242
- }
243
- #endif
244
-
245
- // Odd height will harmlessly mirror the middle row twice.
246
- for (y = 0; y < half_height; ++y) {
247
- CopyRow(src, row, width); // Copy top row into buffer
248
- MirrorRow(src_bot, dst, width); // Mirror bottom row into top row
249
- MirrorRow(row, dst_bot, width); // Mirror buffer into bottom row
250
- src += src_stride;
251
- dst += dst_stride;
252
- src_bot -= src_stride;
253
- dst_bot -= dst_stride;
254
- }
255
- free_aligned_buffer_64(row);
256
- }
257
-
258
- LIBYUV_API
259
- void SplitTransposeUV(const uint8_t* src,
260
- int src_stride,
261
- uint8_t* dst_a,
262
- int dst_stride_a,
263
- uint8_t* dst_b,
264
- int dst_stride_b,
265
- int width,
266
- int height) {
267
- int i = height;
268
- #if defined(HAS_TRANSPOSEUVWXH_SME)
269
- void (*TransposeUVWxH)(const uint8_t* src, int src_stride, uint8_t* dst_a,
270
- int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
271
- int width, int height) = TransposeUVWxH_C;
272
- #endif
273
- #if defined(HAS_TRANSPOSEUVWX16_LSX)
274
- void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a,
275
- int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
276
- int width) = TransposeUVWx16_C;
277
- #else
278
- void (*TransposeUVWx8)(const uint8_t* src, int src_stride, uint8_t* dst_a,
279
- int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
280
- int width) = TransposeUVWx8_C;
281
- #endif
282
-
283
- #if defined(HAS_TRANSPOSEUVWX16_LSX)
284
- if (TestCpuFlag(kCpuHasLSX)) {
285
- TransposeUVWx16 = TransposeUVWx16_Any_LSX;
286
- if (IS_ALIGNED(width, 8)) {
287
- TransposeUVWx16 = TransposeUVWx16_LSX;
288
- }
289
- }
290
- #endif
291
- #if defined(HAS_TRANSPOSEUVWX8_NEON)
292
- if (TestCpuFlag(kCpuHasNEON)) {
293
- TransposeUVWx8 = TransposeUVWx8_Any_NEON;
294
- if (IS_ALIGNED(width, 8)) {
295
- TransposeUVWx8 = TransposeUVWx8_NEON;
296
- }
297
- }
298
- #endif
299
- #if defined(HAS_TRANSPOSEUVWXH_SME)
300
- if (TestCpuFlag(kCpuHasSME)) {
301
- TransposeUVWxH = TransposeUVWxH_SME;
302
- }
303
- #endif
304
- #if defined(HAS_TRANSPOSEUVWX8_SSE2)
305
- if (TestCpuFlag(kCpuHasSSE2)) {
306
- TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
307
- if (IS_ALIGNED(width, 8)) {
308
- TransposeUVWx8 = TransposeUVWx8_SSE2;
309
- }
310
- }
311
- #endif
312
-
313
- #if defined(HAS_TRANSPOSEUVWXH_SME)
314
- if (TestCpuFlag(kCpuHasSME)) {
315
- TransposeUVWxH(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
316
- width, i);
317
- return;
318
- }
319
- #endif
320
- #if defined(HAS_TRANSPOSEUVWX16_LSX)
321
- // Work through the source in 8x8 tiles.
322
- while (i >= 16) {
323
- TransposeUVWx16(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
324
- width);
325
- src += 16 * src_stride; // Go down 16 rows.
326
- dst_a += 16; // Move over 8 columns.
327
- dst_b += 16; // Move over 8 columns.
328
- i -= 16;
329
- }
330
- #else
331
- // Work through the source in 8x8 tiles.
332
- while (i >= 8) {
333
- TransposeUVWx8(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
334
- width);
335
- src += 8 * src_stride; // Go down 8 rows.
336
- dst_a += 8; // Move over 8 columns.
337
- dst_b += 8; // Move over 8 columns.
338
- i -= 8;
339
- }
340
- #endif
341
-
342
- if (i > 0) {
343
- TransposeUVWxH_C(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
344
- width, i);
345
- }
346
- }
347
-
348
- LIBYUV_API
349
- void SplitRotateUV90(const uint8_t* src,
350
- int src_stride,
351
- uint8_t* dst_a,
352
- int dst_stride_a,
353
- uint8_t* dst_b,
354
- int dst_stride_b,
355
- int width,
356
- int height) {
357
- src += src_stride * (height - 1);
358
- src_stride = -src_stride;
359
-
360
- SplitTransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
361
- width, height);
362
- }
363
-
364
- LIBYUV_API
365
- void SplitRotateUV270(const uint8_t* src,
366
- int src_stride,
367
- uint8_t* dst_a,
368
- int dst_stride_a,
369
- uint8_t* dst_b,
370
- int dst_stride_b,
371
- int width,
372
- int height) {
373
- dst_a += dst_stride_a * (width - 1);
374
- dst_b += dst_stride_b * (width - 1);
375
- dst_stride_a = -dst_stride_a;
376
- dst_stride_b = -dst_stride_b;
377
-
378
- SplitTransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
379
- width, height);
380
- }
381
-
382
- // Rotate 180 is a horizontal and vertical flip.
383
- LIBYUV_API
384
- void SplitRotateUV180(const uint8_t* src,
385
- int src_stride,
386
- uint8_t* dst_a,
387
- int dst_stride_a,
388
- uint8_t* dst_b,
389
- int dst_stride_b,
390
- int width,
391
- int height) {
392
- int i;
393
- void (*MirrorSplitUVRow)(const uint8_t* src, uint8_t* dst_u, uint8_t* dst_v,
394
- int width) = MirrorSplitUVRow_C;
395
- #if defined(HAS_MIRRORSPLITUVROW_NEON)
396
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
397
- MirrorSplitUVRow = MirrorSplitUVRow_NEON;
398
- }
399
- #endif
400
- #if defined(HAS_MIRRORSPLITUVROW_SSSE3)
401
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
402
- MirrorSplitUVRow = MirrorSplitUVRow_SSSE3;
403
- }
404
- #endif
405
- #if defined(HAS_MIRRORSPLITUVROW_LSX)
406
- if (TestCpuFlag(kCpuHasLSX) && IS_ALIGNED(width, 32)) {
407
- MirrorSplitUVRow = MirrorSplitUVRow_LSX;
408
- }
409
- #endif
410
-
411
- dst_a += dst_stride_a * (height - 1);
412
- dst_b += dst_stride_b * (height - 1);
413
-
414
- for (i = 0; i < height; ++i) {
415
- MirrorSplitUVRow(src, dst_a, dst_b, width);
416
- src += src_stride;
417
- dst_a -= dst_stride_a;
418
- dst_b -= dst_stride_b;
419
- }
420
- }
421
-
422
- // Rotate UV and split into planar.
423
- // width and height expected to be half size for NV12
424
- LIBYUV_API
425
- int SplitRotateUV(const uint8_t* src_uv,
426
- int src_stride_uv,
427
- uint8_t* dst_u,
428
- int dst_stride_u,
429
- uint8_t* dst_v,
430
- int dst_stride_v,
431
- int width,
432
- int height,
433
- enum RotationMode mode) {
434
- if (!src_uv || width <= 0 || height == 0 || !dst_u || !dst_v) {
435
- return -1;
436
- }
437
-
438
- // Negative height means invert the image.
439
- if (height < 0) {
440
- height = -height;
441
- src_uv = src_uv + (height - 1) * src_stride_uv;
442
- src_stride_uv = -src_stride_uv;
443
- }
444
-
445
- switch (mode) {
446
- case kRotate0:
447
- SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
448
- dst_stride_v, width, height);
449
- return 0;
450
- case kRotate90:
451
- SplitRotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
452
- dst_stride_v, width, height);
453
- return 0;
454
- case kRotate270:
455
- SplitRotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
456
- dst_stride_v, width, height);
457
- return 0;
458
- case kRotate180:
459
- SplitRotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
460
- dst_stride_v, width, height);
461
- return 0;
462
- default:
463
- break;
464
- }
465
- return -1;
466
- }
467
-
468
- LIBYUV_API
469
- int RotatePlane(const uint8_t* src,
470
- int src_stride,
471
- uint8_t* dst,
472
- int dst_stride,
473
- int width,
474
- int height,
475
- enum RotationMode mode) {
476
- if (!src || width <= 0 || height == 0 || !dst) {
477
- return -1;
478
- }
479
-
480
- // Negative height means invert the image.
481
- if (height < 0) {
482
- height = -height;
483
- src = src + (height - 1) * src_stride;
484
- src_stride = -src_stride;
485
- }
486
-
487
- switch (mode) {
488
- case kRotate0:
489
- // copy frame
490
- CopyPlane(src, src_stride, dst, dst_stride, width, height);
491
- return 0;
492
- case kRotate90:
493
- RotatePlane90(src, src_stride, dst, dst_stride, width, height);
494
- return 0;
495
- case kRotate270:
496
- RotatePlane270(src, src_stride, dst, dst_stride, width, height);
497
- return 0;
498
- case kRotate180:
499
- RotatePlane180(src, src_stride, dst, dst_stride, width, height);
500
- return 0;
501
- default:
502
- break;
503
- }
504
- return -1;
505
- }
506
-
507
- static void TransposePlane_16(const uint16_t* src,
508
- int src_stride,
509
- uint16_t* dst,
510
- int dst_stride,
511
- int width,
512
- int height) {
513
- int i = height;
514
- // Work across the source in 8x8 tiles
515
- while (i >= 8) {
516
- TransposeWx8_16_C(src, src_stride, dst, dst_stride, width);
517
- src += 8 * src_stride; // Go down 8 rows.
518
- dst += 8; // Move over 8 columns.
519
- i -= 8;
520
- }
521
-
522
- if (i > 0) {
523
- TransposeWxH_16_C(src, src_stride, dst, dst_stride, width, i);
524
- }
525
- }
526
-
527
- static void RotatePlane90_16(const uint16_t* src,
528
- int src_stride,
529
- uint16_t* dst,
530
- int dst_stride,
531
- int width,
532
- int height) {
533
- // Rotate by 90 is a transpose with the source read
534
- // from bottom to top. So set the source pointer to the end
535
- // of the buffer and flip the sign of the source stride.
536
- src += src_stride * (height - 1);
537
- src_stride = -src_stride;
538
- TransposePlane_16(src, src_stride, dst, dst_stride, width, height);
539
- }
540
-
541
- static void RotatePlane270_16(const uint16_t* src,
542
- int src_stride,
543
- uint16_t* dst,
544
- int dst_stride,
545
- int width,
546
- int height) {
547
- // Rotate by 270 is a transpose with the destination written
548
- // from bottom to top. So set the destination pointer to the end
549
- // of the buffer and flip the sign of the destination stride.
550
- dst += dst_stride * (width - 1);
551
- dst_stride = -dst_stride;
552
- TransposePlane_16(src, src_stride, dst, dst_stride, width, height);
553
- }
554
-
555
- static void RotatePlane180_16(const uint16_t* src,
556
- int src_stride,
557
- uint16_t* dst,
558
- int dst_stride,
559
- int width,
560
- int height) {
561
- const uint16_t* src_bot = src + src_stride * (height - 1);
562
- uint16_t* dst_bot = dst + dst_stride * (height - 1);
563
- int half_height = (height + 1) >> 1;
564
- int y;
565
-
566
- // Swap top and bottom row and mirror the content. Uses a temporary row.
567
- align_buffer_64(row, width * 2);
568
- uint16_t* row_tmp = (uint16_t*)row;
569
- assert(row);
570
- if (!row)
571
- return;
572
-
573
- // Odd height will harmlessly mirror the middle row twice.
574
- for (y = 0; y < half_height; ++y) {
575
- CopyRow_16_C(src, row_tmp, width); // Copy top row into buffer
576
- MirrorRow_16_C(src_bot, dst, width); // Mirror bottom row into top row
577
- MirrorRow_16_C(row_tmp, dst_bot, width); // Mirror buffer into bottom row
578
- src += src_stride;
579
- dst += dst_stride;
580
- src_bot -= src_stride;
581
- dst_bot -= dst_stride;
582
- }
583
- free_aligned_buffer_64(row);
584
- }
585
-
586
- LIBYUV_API
587
- int RotatePlane_16(const uint16_t* src,
588
- int src_stride,
589
- uint16_t* dst,
590
- int dst_stride,
591
- int width,
592
- int height,
593
- enum RotationMode mode) {
594
- if (!src || width <= 0 || height == 0 || !dst) {
595
- return -1;
596
- }
597
-
598
- // Negative height means invert the image.
599
- if (height < 0) {
600
- height = -height;
601
- src = src + (height - 1) * src_stride;
602
- src_stride = -src_stride;
603
- }
604
-
605
- switch (mode) {
606
- case kRotate0:
607
- // copy frame
608
- CopyPlane_16(src, src_stride, dst, dst_stride, width, height);
609
- return 0;
610
- case kRotate90:
611
- RotatePlane90_16(src, src_stride, dst, dst_stride, width, height);
612
- return 0;
613
- case kRotate270:
614
- RotatePlane270_16(src, src_stride, dst, dst_stride, width, height);
615
- return 0;
616
- case kRotate180:
617
- RotatePlane180_16(src, src_stride, dst, dst_stride, width, height);
618
- return 0;
619
- default:
620
- break;
621
- }
622
- return -1;
623
- }
624
-
625
- LIBYUV_API
626
- int I420Rotate(const uint8_t* src_y,
627
- int src_stride_y,
628
- const uint8_t* src_u,
629
- int src_stride_u,
630
- const uint8_t* src_v,
631
- int src_stride_v,
632
- uint8_t* dst_y,
633
- int dst_stride_y,
634
- uint8_t* dst_u,
635
- int dst_stride_u,
636
- uint8_t* dst_v,
637
- int dst_stride_v,
638
- int width,
639
- int height,
640
- enum RotationMode mode) {
641
- int halfwidth = (width + 1) >> 1;
642
- int halfheight = (height + 1) >> 1;
643
- if ((!src_y && dst_y) || !src_u || !src_v || width <= 0 || height == 0 ||
644
- !dst_y || !dst_u || !dst_v) {
645
- return -1;
646
- }
647
-
648
- // Negative height means invert the image.
649
- if (height < 0) {
650
- height = -height;
651
- halfheight = (height + 1) >> 1;
652
- src_y = src_y + (height - 1) * src_stride_y;
653
- src_u = src_u + (halfheight - 1) * src_stride_u;
654
- src_v = src_v + (halfheight - 1) * src_stride_v;
655
- src_stride_y = -src_stride_y;
656
- src_stride_u = -src_stride_u;
657
- src_stride_v = -src_stride_v;
658
- }
659
-
660
- switch (mode) {
661
- case kRotate0:
662
- // copy frame
663
- return I420Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
664
- src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
665
- dst_v, dst_stride_v, width, height);
666
- case kRotate90:
667
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
668
- RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
669
- halfheight);
670
- RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
671
- halfheight);
672
- return 0;
673
- case kRotate270:
674
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
675
- RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
676
- halfheight);
677
- RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
678
- halfheight);
679
- return 0;
680
- case kRotate180:
681
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
682
- RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
683
- halfheight);
684
- RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
685
- halfheight);
686
- return 0;
687
- default:
688
- break;
689
- }
690
- return -1;
691
- }
692
-
693
- // I422 has half width x full height UV planes, so rotate by 90 and 270
694
- // require scaling to maintain 422 subsampling.
695
- LIBYUV_API
696
- int I422Rotate(const uint8_t* src_y,
697
- int src_stride_y,
698
- const uint8_t* src_u,
699
- int src_stride_u,
700
- const uint8_t* src_v,
701
- int src_stride_v,
702
- uint8_t* dst_y,
703
- int dst_stride_y,
704
- uint8_t* dst_u,
705
- int dst_stride_u,
706
- uint8_t* dst_v,
707
- int dst_stride_v,
708
- int width,
709
- int height,
710
- enum RotationMode mode) {
711
- int halfwidth = (width + 1) >> 1;
712
- int halfheight = (height + 1) >> 1;
713
- int r;
714
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
715
- !dst_u || !dst_v) {
716
- return -1;
717
- }
718
- // Negative height means invert the image.
719
- if (height < 0) {
720
- height = -height;
721
- src_y = src_y + (height - 1) * src_stride_y;
722
- src_u = src_u + (height - 1) * src_stride_u;
723
- src_v = src_v + (height - 1) * src_stride_v;
724
- src_stride_y = -src_stride_y;
725
- src_stride_u = -src_stride_u;
726
- src_stride_v = -src_stride_v;
727
- }
728
-
729
- switch (mode) {
730
- case kRotate0:
731
- // Copy frame
732
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
733
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
734
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
735
- return 0;
736
-
737
- // Note on temporary Y plane for UV.
738
- // Rotation of UV first fits within the Y destination plane rows.
739
- // Y plane is width x height
740
- // Y plane rotated is height x width
741
- // UV plane is (width / 2) x height
742
- // UV plane rotated is height x (width / 2)
743
- // UV plane rotated+scaled is (height / 2) x width.
744
- // UV plane rotated is a temporary that fits within the Y plane rotated.
745
-
746
- case kRotate90:
747
- RotatePlane90(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
748
- height);
749
- r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u,
750
- dst_stride_u, halfheight, width, kFilterBilinear);
751
- if (r != 0) {
752
- return r;
753
- }
754
- RotatePlane90(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
755
- height);
756
- r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v,
757
- dst_stride_v, halfheight, width, kFilterLinear);
758
- if (r != 0) {
759
- return r;
760
- }
761
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
762
- return 0;
763
- case kRotate270:
764
- RotatePlane270(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
765
- height);
766
- r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u,
767
- dst_stride_u, halfheight, width, kFilterBilinear);
768
- if (r != 0) {
769
- return r;
770
- }
771
- RotatePlane270(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
772
- height);
773
- r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v,
774
- dst_stride_v, halfheight, width, kFilterLinear);
775
- if (r != 0) {
776
- return r;
777
- }
778
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
779
- return 0;
780
- case kRotate180:
781
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
782
- RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
783
- height);
784
- RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
785
- height);
786
- return 0;
787
- default:
788
- break;
789
- }
790
- return -1;
791
- }
792
-
793
- LIBYUV_API
794
- int I444Rotate(const uint8_t* src_y,
795
- int src_stride_y,
796
- const uint8_t* src_u,
797
- int src_stride_u,
798
- const uint8_t* src_v,
799
- int src_stride_v,
800
- uint8_t* dst_y,
801
- int dst_stride_y,
802
- uint8_t* dst_u,
803
- int dst_stride_u,
804
- uint8_t* dst_v,
805
- int dst_stride_v,
806
- int width,
807
- int height,
808
- enum RotationMode mode) {
809
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
810
- !dst_u || !dst_v) {
811
- return -1;
812
- }
813
-
814
- // Negative height means invert the image.
815
- if (height < 0) {
816
- height = -height;
817
- src_y = src_y + (height - 1) * src_stride_y;
818
- src_u = src_u + (height - 1) * src_stride_u;
819
- src_v = src_v + (height - 1) * src_stride_v;
820
- src_stride_y = -src_stride_y;
821
- src_stride_u = -src_stride_u;
822
- src_stride_v = -src_stride_v;
823
- }
824
-
825
- switch (mode) {
826
- case kRotate0:
827
- // copy frame
828
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
829
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
830
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
831
- return 0;
832
- case kRotate90:
833
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
834
- RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
835
- RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
836
- return 0;
837
- case kRotate270:
838
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
839
- RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
840
- RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
841
- return 0;
842
- case kRotate180:
843
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
844
- RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
845
- RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
846
- return 0;
847
- default:
848
- break;
849
- }
850
- return -1;
851
- }
852
-
853
- LIBYUV_API
854
- int NV12ToI420Rotate(const uint8_t* src_y,
855
- int src_stride_y,
856
- const uint8_t* src_uv,
857
- int src_stride_uv,
858
- uint8_t* dst_y,
859
- int dst_stride_y,
860
- uint8_t* dst_u,
861
- int dst_stride_u,
862
- uint8_t* dst_v,
863
- int dst_stride_v,
864
- int width,
865
- int height,
866
- enum RotationMode mode) {
867
- int halfwidth = (width + 1) >> 1;
868
- int halfheight = (height + 1) >> 1;
869
- if (!src_y || !src_uv || width <= 0 || height == 0 || !dst_y || !dst_u ||
870
- !dst_v) {
871
- return -1;
872
- }
873
-
874
- // Negative height means invert the image.
875
- if (height < 0) {
876
- height = -height;
877
- halfheight = (height + 1) >> 1;
878
- src_y = src_y + (height - 1) * src_stride_y;
879
- src_uv = src_uv + (halfheight - 1) * src_stride_uv;
880
- src_stride_y = -src_stride_y;
881
- src_stride_uv = -src_stride_uv;
882
- }
883
-
884
- switch (mode) {
885
- case kRotate0:
886
- // copy frame
887
- return NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
888
- dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
889
- width, height);
890
- case kRotate90:
891
- RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
892
- SplitRotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
893
- dst_stride_v, halfwidth, halfheight);
894
- return 0;
895
- case kRotate270:
896
- RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
897
- SplitRotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
898
- dst_stride_v, halfwidth, halfheight);
899
- return 0;
900
- case kRotate180:
901
- RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
902
- SplitRotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
903
- dst_stride_v, halfwidth, halfheight);
904
- return 0;
905
- default:
906
- break;
907
- }
908
- return -1;
909
- }
910
-
911
- static void SplitPixels(const uint8_t* src_u,
912
- int src_pixel_stride_uv,
913
- uint8_t* dst_u,
914
- int width) {
915
- int i;
916
- for (i = 0; i < width; ++i) {
917
- *dst_u = *src_u;
918
- ++dst_u;
919
- src_u += src_pixel_stride_uv;
920
- }
921
- }
922
-
923
- // Convert Android420 to I420 with Rotate
924
- LIBYUV_API
925
- int Android420ToI420Rotate(const uint8_t* src_y,
926
- int src_stride_y,
927
- const uint8_t* src_u,
928
- int src_stride_u,
929
- const uint8_t* src_v,
930
- int src_stride_v,
931
- int src_pixel_stride_uv,
932
- uint8_t* dst_y,
933
- int dst_stride_y,
934
- uint8_t* dst_u,
935
- int dst_stride_u,
936
- uint8_t* dst_v,
937
- int dst_stride_v,
938
- int width,
939
- int height,
940
- enum RotationMode rotation) {
941
- int y;
942
- const ptrdiff_t vu_off = src_v - src_u;
943
- int halfwidth = (width + 1) >> 1;
944
- int halfheight = (height + 1) >> 1;
945
- if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
946
- height == 0) {
947
- return -1;
948
- }
949
- // Negative height means invert the image.
950
- if (height < 0) {
951
- height = -height;
952
- halfheight = (height + 1) >> 1;
953
- src_y = src_y + (height - 1) * src_stride_y;
954
- src_u = src_u + (halfheight - 1) * src_stride_u;
955
- src_v = src_v + (halfheight - 1) * src_stride_v;
956
- src_stride_y = -src_stride_y;
957
- src_stride_u = -src_stride_u;
958
- src_stride_v = -src_stride_v;
959
- }
960
-
961
- if (dst_y) {
962
- RotatePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
963
- rotation);
964
- }
965
-
966
- // Copy UV planes - I420
967
- if (src_pixel_stride_uv == 1) {
968
- RotatePlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight,
969
- rotation);
970
- RotatePlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight,
971
- rotation);
972
- return 0;
973
- }
974
- // Split UV planes - NV21
975
- if (src_pixel_stride_uv == 2 && vu_off == -1 &&
976
- src_stride_u == src_stride_v) {
977
- SplitRotateUV(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
978
- halfwidth, halfheight, rotation);
979
- return 0;
980
- }
981
- // Split UV planes - NV12
982
- if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
983
- SplitRotateUV(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
984
- halfwidth, halfheight, rotation);
985
- return 0;
986
- }
987
-
988
- if (rotation == 0) {
989
- for (y = 0; y < halfheight; ++y) {
990
- SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
991
- SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
992
- src_u += src_stride_u;
993
- src_v += src_stride_v;
994
- dst_u += dst_stride_u;
995
- dst_v += dst_stride_v;
996
- }
997
- return 0;
998
- }
999
- // unsupported type and/or rotation.
1000
- return -1;
1001
- }
1002
-
1003
- LIBYUV_API
1004
- int I010Rotate(const uint16_t* src_y,
1005
- int src_stride_y,
1006
- const uint16_t* src_u,
1007
- int src_stride_u,
1008
- const uint16_t* src_v,
1009
- int src_stride_v,
1010
- uint16_t* dst_y,
1011
- int dst_stride_y,
1012
- uint16_t* dst_u,
1013
- int dst_stride_u,
1014
- uint16_t* dst_v,
1015
- int dst_stride_v,
1016
- int width,
1017
- int height,
1018
- enum RotationMode mode) {
1019
- int halfwidth = (width + 1) >> 1;
1020
- int halfheight = (height + 1) >> 1;
1021
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1022
- !dst_u || !dst_v || dst_stride_y < 0) {
1023
- return -1;
1024
- }
1025
- // Negative height means invert the image.
1026
- if (height < 0) {
1027
- height = -height;
1028
- src_y = src_y + (height - 1) * src_stride_y;
1029
- src_u = src_u + (height - 1) * src_stride_u;
1030
- src_v = src_v + (height - 1) * src_stride_v;
1031
- src_stride_y = -src_stride_y;
1032
- src_stride_u = -src_stride_u;
1033
- src_stride_v = -src_stride_v;
1034
- }
1035
-
1036
- switch (mode) {
1037
- case kRotate0:
1038
- // copy frame
1039
- return I010Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
1040
- src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1041
- dst_v, dst_stride_v, width, height);
1042
- case kRotate90:
1043
- RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1044
- RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1045
- halfheight);
1046
- RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1047
- halfheight);
1048
- return 0;
1049
- case kRotate270:
1050
- RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1051
- height);
1052
- RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1053
- halfheight);
1054
- RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1055
- halfheight);
1056
- return 0;
1057
- case kRotate180:
1058
- RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1059
- height);
1060
- RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1061
- halfheight);
1062
- RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1063
- halfheight);
1064
- return 0;
1065
- default:
1066
- break;
1067
- }
1068
- return -1;
1069
- }
1070
-
1071
- // I210 has half width x full height UV planes, so rotate by 90 and 270
1072
- // require scaling to maintain 422 subsampling.
1073
- LIBYUV_API
1074
- int I210Rotate(const uint16_t* src_y,
1075
- int src_stride_y,
1076
- const uint16_t* src_u,
1077
- int src_stride_u,
1078
- const uint16_t* src_v,
1079
- int src_stride_v,
1080
- uint16_t* dst_y,
1081
- int dst_stride_y,
1082
- uint16_t* dst_u,
1083
- int dst_stride_u,
1084
- uint16_t* dst_v,
1085
- int dst_stride_v,
1086
- int width,
1087
- int height,
1088
- enum RotationMode mode) {
1089
- int halfwidth = (width + 1) >> 1;
1090
- int halfheight = (height + 1) >> 1;
1091
- int r;
1092
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1093
- !dst_u || !dst_v) {
1094
- return -1;
1095
- }
1096
- // Negative height means invert the image.
1097
- if (height < 0) {
1098
- height = -height;
1099
- src_y = src_y + (height - 1) * src_stride_y;
1100
- src_u = src_u + (height - 1) * src_stride_u;
1101
- src_v = src_v + (height - 1) * src_stride_v;
1102
- src_stride_y = -src_stride_y;
1103
- src_stride_u = -src_stride_u;
1104
- src_stride_v = -src_stride_v;
1105
- }
1106
-
1107
- switch (mode) {
1108
- case kRotate0:
1109
- // Copy frame
1110
- CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1111
- CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
1112
- CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
1113
- return 0;
1114
-
1115
- // Note on temporary Y plane for UV.
1116
- // Rotation of UV first fits within the Y destination plane rows.
1117
- // Y plane is width x height
1118
- // Y plane rotated is height x width
1119
- // UV plane is (width / 2) x height
1120
- // UV plane rotated is height x (width / 2)
1121
- // UV plane rotated+scaled is (height / 2) x width.
1122
- // UV plane rotated is a temporary that fits within the Y plane rotated.
1123
-
1124
- case kRotate90:
1125
- RotatePlane90_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
1126
- height);
1127
- r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u,
1128
- dst_stride_u, halfheight, width, kFilterBilinear);
1129
- if (r != 0) {
1130
- return r;
1131
- }
1132
- RotatePlane90_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
1133
- height);
1134
- r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v,
1135
- dst_stride_v, halfheight, width, kFilterLinear);
1136
- if (r != 0) {
1137
- return r;
1138
- }
1139
- RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1140
- return 0;
1141
- case kRotate270:
1142
- RotatePlane270_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
1143
- height);
1144
- r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u,
1145
- dst_stride_u, halfheight, width, kFilterBilinear);
1146
- if (r != 0) {
1147
- return r;
1148
- }
1149
- RotatePlane270_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
1150
- height);
1151
- r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v,
1152
- dst_stride_v, halfheight, width, kFilterLinear);
1153
- if (r != 0) {
1154
- return r;
1155
- }
1156
- RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1157
- height);
1158
- return 0;
1159
- case kRotate180:
1160
- RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1161
- height);
1162
- RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1163
- height);
1164
- RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1165
- height);
1166
- return 0;
1167
- default:
1168
- break;
1169
- }
1170
- return -1;
1171
- }
1172
-
1173
- LIBYUV_API
1174
- int I410Rotate(const uint16_t* src_y,
1175
- int src_stride_y,
1176
- const uint16_t* src_u,
1177
- int src_stride_u,
1178
- const uint16_t* src_v,
1179
- int src_stride_v,
1180
- uint16_t* dst_y,
1181
- int dst_stride_y,
1182
- uint16_t* dst_u,
1183
- int dst_stride_u,
1184
- uint16_t* dst_v,
1185
- int dst_stride_v,
1186
- int width,
1187
- int height,
1188
- enum RotationMode mode) {
1189
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1190
- !dst_u || !dst_v || dst_stride_y < 0) {
1191
- return -1;
1192
- }
1193
- // Negative height means invert the image.
1194
- if (height < 0) {
1195
- height = -height;
1196
- src_y = src_y + (height - 1) * src_stride_y;
1197
- src_u = src_u + (height - 1) * src_stride_u;
1198
- src_v = src_v + (height - 1) * src_stride_v;
1199
- src_stride_y = -src_stride_y;
1200
- src_stride_u = -src_stride_u;
1201
- src_stride_v = -src_stride_v;
1202
- }
1203
-
1204
- switch (mode) {
1205
- case kRotate0:
1206
- // copy frame
1207
- CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1208
- CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
1209
- CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
1210
- return 0;
1211
- case kRotate90:
1212
- RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1213
- RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
1214
- RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
1215
- return 0;
1216
- case kRotate270:
1217
- RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1218
- height);
1219
- RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, width,
1220
- height);
1221
- RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, width,
1222
- height);
1223
- return 0;
1224
- case kRotate180:
1225
- RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1226
- height);
1227
- RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, width,
1228
- height);
1229
- RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, width,
1230
- height);
1231
- return 0;
1232
- default:
1233
- break;
1234
- }
1235
- return -1;
1236
- }
1237
-
1238
- #ifdef __cplusplus
1239
- } // extern "C"
1240
- } // namespace libyuv
1241
- #endif
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 <assert.h>
12
+
13
+ #include "libyuv/rotate.h"
14
+
15
+ #include "libyuv/convert.h"
16
+ #include "libyuv/cpu_id.h"
17
+ #include "libyuv/planar_functions.h"
18
+ #include "libyuv/rotate_row.h"
19
+ #include "libyuv/row.h"
20
+
21
+ #ifdef __cplusplus
22
+ namespace libyuv {
23
+ extern "C" {
24
+ #endif
25
+
26
+ LIBYUV_API
27
+ void TransposePlane(const uint8_t* src,
28
+ int src_stride,
29
+ uint8_t* dst,
30
+ int dst_stride,
31
+ int width,
32
+ int height) {
33
+ int i = height;
34
+ #if defined(HAS_TRANSPOSEWXH_SME)
35
+ void (*TransposeWxH)(const uint8_t* src, int src_stride, uint8_t* dst,
36
+ int dst_stride, int width, int height) = NULL;
37
+ #endif
38
+ #if defined(HAS_TRANSPOSEWX16_LSX) || defined(HAS_TRANSPOSEWX16_NEON)
39
+ void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst,
40
+ int dst_stride, int width) = TransposeWx16_C;
41
+ #else
42
+ void (*TransposeWx8)(const uint8_t* src, int src_stride, uint8_t* dst,
43
+ int dst_stride, int width) = TransposeWx8_C;
44
+ #endif
45
+
46
+ #if defined(HAS_TRANSPOSEWX8_NEON)
47
+ if (TestCpuFlag(kCpuHasNEON)) {
48
+ TransposeWx8 = TransposeWx8_Any_NEON;
49
+ if (IS_ALIGNED(width, 8)) {
50
+ TransposeWx8 = TransposeWx8_NEON;
51
+ }
52
+ }
53
+ #endif
54
+ #if defined(HAS_TRANSPOSEWX16_NEON)
55
+ if (TestCpuFlag(kCpuHasNEON)) {
56
+ TransposeWx16 = TransposeWx16_Any_NEON;
57
+ if (IS_ALIGNED(width, 16)) {
58
+ TransposeWx16 = TransposeWx16_NEON;
59
+ }
60
+ }
61
+ #endif
62
+ #if defined(HAS_TRANSPOSEWXH_SME)
63
+ if (TestCpuFlag(kCpuHasSME)) {
64
+ TransposeWxH = TransposeWxH_SME;
65
+ }
66
+ #endif
67
+ #if defined(HAS_TRANSPOSEWX8_SSSE3)
68
+ if (TestCpuFlag(kCpuHasSSSE3)) {
69
+ TransposeWx8 = TransposeWx8_Any_SSSE3;
70
+ if (IS_ALIGNED(width, 8)) {
71
+ TransposeWx8 = TransposeWx8_SSSE3;
72
+ }
73
+ }
74
+ #endif
75
+ #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3)
76
+ if (TestCpuFlag(kCpuHasSSSE3)) {
77
+ TransposeWx8 = TransposeWx8_Fast_Any_SSSE3;
78
+ if (IS_ALIGNED(width, 16)) {
79
+ TransposeWx8 = TransposeWx8_Fast_SSSE3;
80
+ }
81
+ }
82
+ #endif
83
+ #if defined(HAS_TRANSPOSEWX16_LSX)
84
+ if (TestCpuFlag(kCpuHasLSX)) {
85
+ TransposeWx16 = TransposeWx16_Any_LSX;
86
+ if (IS_ALIGNED(width, 16)) {
87
+ TransposeWx16 = TransposeWx16_LSX;
88
+ }
89
+ }
90
+ #endif
91
+
92
+ #if defined(HAS_TRANSPOSEWXH_SME)
93
+ if (TransposeWxH) {
94
+ TransposeWxH(src, src_stride, dst, dst_stride, width, height);
95
+ return;
96
+ }
97
+ #endif
98
+ #if defined(HAS_TRANSPOSEWX16_LSX) || defined(HAS_TRANSPOSEWX16_NEON)
99
+ // Work across the source in 16x16 tiles
100
+ while (i >= 16) {
101
+ TransposeWx16(src, src_stride, dst, dst_stride, width);
102
+ src += 16 * src_stride; // Go down 16 rows.
103
+ dst += 16; // Move over 16 columns.
104
+ i -= 16;
105
+ }
106
+ #else
107
+ // Work across the source in 8x8 tiles
108
+ while (i >= 8) {
109
+ TransposeWx8(src, src_stride, dst, dst_stride, width);
110
+ src += 8 * src_stride; // Go down 8 rows.
111
+ dst += 8; // Move over 8 columns.
112
+ i -= 8;
113
+ }
114
+ #endif
115
+
116
+ if (i > 0) {
117
+ TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
118
+ }
119
+ }
120
+
121
+ LIBYUV_API
122
+ void RotatePlane90(const uint8_t* src,
123
+ int src_stride,
124
+ uint8_t* dst,
125
+ int dst_stride,
126
+ int width,
127
+ int height) {
128
+ // Rotate by 90 is a transpose with the source read
129
+ // from bottom to top. So set the source pointer to the end
130
+ // of the buffer and flip the sign of the source stride.
131
+ src += src_stride * (height - 1);
132
+ src_stride = -src_stride;
133
+ TransposePlane(src, src_stride, dst, dst_stride, width, height);
134
+ }
135
+
136
+ LIBYUV_API
137
+ void RotatePlane270(const uint8_t* src,
138
+ int src_stride,
139
+ uint8_t* dst,
140
+ int dst_stride,
141
+ int width,
142
+ int height) {
143
+ // Rotate by 270 is a transpose with the destination written
144
+ // from bottom to top. So set the destination pointer to the end
145
+ // of the buffer and flip the sign of the destination stride.
146
+ dst += dst_stride * (width - 1);
147
+ dst_stride = -dst_stride;
148
+ TransposePlane(src, src_stride, dst, dst_stride, width, height);
149
+ }
150
+
151
+ LIBYUV_API
152
+ void RotatePlane180(const uint8_t* src,
153
+ int src_stride,
154
+ uint8_t* dst,
155
+ int dst_stride,
156
+ int width,
157
+ int height) {
158
+ // Swap top and bottom row and mirror the content. Uses a temporary row.
159
+ align_buffer_64(row, width);
160
+ assert(row);
161
+ if (!row)
162
+ return;
163
+ const uint8_t* src_bot = src + src_stride * (height - 1);
164
+ uint8_t* dst_bot = dst + dst_stride * (height - 1);
165
+ int half_height = (height + 1) >> 1;
166
+ int y;
167
+ void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C;
168
+ void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
169
+ #if defined(HAS_MIRRORROW_NEON)
170
+ if (TestCpuFlag(kCpuHasNEON)) {
171
+ MirrorRow = MirrorRow_Any_NEON;
172
+ if (IS_ALIGNED(width, 32)) {
173
+ MirrorRow = MirrorRow_NEON;
174
+ }
175
+ }
176
+ #endif
177
+ #if defined(HAS_MIRRORROW_SSSE3)
178
+ if (TestCpuFlag(kCpuHasSSSE3)) {
179
+ MirrorRow = MirrorRow_Any_SSSE3;
180
+ if (IS_ALIGNED(width, 16)) {
181
+ MirrorRow = MirrorRow_SSSE3;
182
+ }
183
+ }
184
+ #endif
185
+ #if defined(HAS_MIRRORROW_AVX2)
186
+ if (TestCpuFlag(kCpuHasAVX2)) {
187
+ MirrorRow = MirrorRow_Any_AVX2;
188
+ if (IS_ALIGNED(width, 32)) {
189
+ MirrorRow = MirrorRow_AVX2;
190
+ }
191
+ }
192
+ #endif
193
+ #if defined(HAS_MIRRORROW_LSX)
194
+ if (TestCpuFlag(kCpuHasLSX)) {
195
+ MirrorRow = MirrorRow_Any_LSX;
196
+ if (IS_ALIGNED(width, 32)) {
197
+ MirrorRow = MirrorRow_LSX;
198
+ }
199
+ }
200
+ #endif
201
+ #if defined(HAS_MIRRORROW_LASX)
202
+ if (TestCpuFlag(kCpuHasLASX)) {
203
+ MirrorRow = MirrorRow_Any_LASX;
204
+ if (IS_ALIGNED(width, 64)) {
205
+ MirrorRow = MirrorRow_LASX;
206
+ }
207
+ }
208
+ #endif
209
+ #if defined(HAS_COPYROW_SSE2)
210
+ if (TestCpuFlag(kCpuHasSSE2)) {
211
+ CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
212
+ }
213
+ #endif
214
+ #if defined(HAS_COPYROW_AVX)
215
+ if (TestCpuFlag(kCpuHasAVX)) {
216
+ CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
217
+ }
218
+ #endif
219
+ #if defined(HAS_COPYROW_AVX512BW)
220
+ if (TestCpuFlag(kCpuHasAVX512BW)) {
221
+ CopyRow = IS_ALIGNED(width, 128) ? CopyRow_AVX512BW : CopyRow_Any_AVX512BW;
222
+ }
223
+ #endif
224
+ #if defined(HAS_COPYROW_ERMS)
225
+ if (TestCpuFlag(kCpuHasERMS)) {
226
+ CopyRow = CopyRow_ERMS;
227
+ }
228
+ #endif
229
+ #if defined(HAS_COPYROW_NEON)
230
+ if (TestCpuFlag(kCpuHasNEON)) {
231
+ CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
232
+ }
233
+ #endif
234
+ #if defined(HAS_COPYROW_SME)
235
+ if (TestCpuFlag(kCpuHasSME)) {
236
+ CopyRow = CopyRow_SME;
237
+ }
238
+ #endif
239
+ #if defined(HAS_COPYROW_RVV)
240
+ if (TestCpuFlag(kCpuHasRVV)) {
241
+ CopyRow = CopyRow_RVV;
242
+ }
243
+ #endif
244
+
245
+ // Odd height will harmlessly mirror the middle row twice.
246
+ for (y = 0; y < half_height; ++y) {
247
+ CopyRow(src, row, width); // Copy top row into buffer
248
+ MirrorRow(src_bot, dst, width); // Mirror bottom row into top row
249
+ MirrorRow(row, dst_bot, width); // Mirror buffer into bottom row
250
+ src += src_stride;
251
+ dst += dst_stride;
252
+ src_bot -= src_stride;
253
+ dst_bot -= dst_stride;
254
+ }
255
+ free_aligned_buffer_64(row);
256
+ }
257
+
258
+ LIBYUV_API
259
+ void SplitTransposeUV(const uint8_t* src,
260
+ int src_stride,
261
+ uint8_t* dst_a,
262
+ int dst_stride_a,
263
+ uint8_t* dst_b,
264
+ int dst_stride_b,
265
+ int width,
266
+ int height) {
267
+ int i = height;
268
+ #if defined(HAS_TRANSPOSEUVWXH_SME)
269
+ void (*TransposeUVWxH)(const uint8_t* src, int src_stride, uint8_t* dst_a,
270
+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
271
+ int width, int height) = TransposeUVWxH_C;
272
+ #endif
273
+ #if defined(HAS_TRANSPOSEUVWX16_LSX)
274
+ void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a,
275
+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
276
+ int width) = TransposeUVWx16_C;
277
+ #else
278
+ void (*TransposeUVWx8)(const uint8_t* src, int src_stride, uint8_t* dst_a,
279
+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
280
+ int width) = TransposeUVWx8_C;
281
+ #endif
282
+
283
+ #if defined(HAS_TRANSPOSEUVWX16_LSX)
284
+ if (TestCpuFlag(kCpuHasLSX)) {
285
+ TransposeUVWx16 = TransposeUVWx16_Any_LSX;
286
+ if (IS_ALIGNED(width, 8)) {
287
+ TransposeUVWx16 = TransposeUVWx16_LSX;
288
+ }
289
+ }
290
+ #endif
291
+ #if defined(HAS_TRANSPOSEUVWX8_NEON)
292
+ if (TestCpuFlag(kCpuHasNEON)) {
293
+ TransposeUVWx8 = TransposeUVWx8_Any_NEON;
294
+ if (IS_ALIGNED(width, 8)) {
295
+ TransposeUVWx8 = TransposeUVWx8_NEON;
296
+ }
297
+ }
298
+ #endif
299
+ #if defined(HAS_TRANSPOSEUVWXH_SME)
300
+ if (TestCpuFlag(kCpuHasSME)) {
301
+ TransposeUVWxH = TransposeUVWxH_SME;
302
+ }
303
+ #endif
304
+ #if defined(HAS_TRANSPOSEUVWX8_SSE2)
305
+ if (TestCpuFlag(kCpuHasSSE2)) {
306
+ TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
307
+ if (IS_ALIGNED(width, 8)) {
308
+ TransposeUVWx8 = TransposeUVWx8_SSE2;
309
+ }
310
+ }
311
+ #endif
312
+
313
+ #if defined(HAS_TRANSPOSEUVWXH_SME)
314
+ if (TestCpuFlag(kCpuHasSME)) {
315
+ TransposeUVWxH(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
316
+ width, i);
317
+ return;
318
+ }
319
+ #endif
320
+ #if defined(HAS_TRANSPOSEUVWX16_LSX)
321
+ // Work through the source in 8x8 tiles.
322
+ while (i >= 16) {
323
+ TransposeUVWx16(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
324
+ width);
325
+ src += 16 * src_stride; // Go down 16 rows.
326
+ dst_a += 16; // Move over 8 columns.
327
+ dst_b += 16; // Move over 8 columns.
328
+ i -= 16;
329
+ }
330
+ #else
331
+ // Work through the source in 8x8 tiles.
332
+ while (i >= 8) {
333
+ TransposeUVWx8(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
334
+ width);
335
+ src += 8 * src_stride; // Go down 8 rows.
336
+ dst_a += 8; // Move over 8 columns.
337
+ dst_b += 8; // Move over 8 columns.
338
+ i -= 8;
339
+ }
340
+ #endif
341
+
342
+ if (i > 0) {
343
+ TransposeUVWxH_C(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
344
+ width, i);
345
+ }
346
+ }
347
+
348
+ LIBYUV_API
349
+ void SplitRotateUV90(const uint8_t* src,
350
+ int src_stride,
351
+ uint8_t* dst_a,
352
+ int dst_stride_a,
353
+ uint8_t* dst_b,
354
+ int dst_stride_b,
355
+ int width,
356
+ int height) {
357
+ src += src_stride * (height - 1);
358
+ src_stride = -src_stride;
359
+
360
+ SplitTransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
361
+ width, height);
362
+ }
363
+
364
+ LIBYUV_API
365
+ void SplitRotateUV270(const uint8_t* src,
366
+ int src_stride,
367
+ uint8_t* dst_a,
368
+ int dst_stride_a,
369
+ uint8_t* dst_b,
370
+ int dst_stride_b,
371
+ int width,
372
+ int height) {
373
+ dst_a += dst_stride_a * (width - 1);
374
+ dst_b += dst_stride_b * (width - 1);
375
+ dst_stride_a = -dst_stride_a;
376
+ dst_stride_b = -dst_stride_b;
377
+
378
+ SplitTransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
379
+ width, height);
380
+ }
381
+
382
+ // Rotate 180 is a horizontal and vertical flip.
383
+ LIBYUV_API
384
+ void SplitRotateUV180(const uint8_t* src,
385
+ int src_stride,
386
+ uint8_t* dst_a,
387
+ int dst_stride_a,
388
+ uint8_t* dst_b,
389
+ int dst_stride_b,
390
+ int width,
391
+ int height) {
392
+ int i;
393
+ void (*MirrorSplitUVRow)(const uint8_t* src, uint8_t* dst_u, uint8_t* dst_v,
394
+ int width) = MirrorSplitUVRow_C;
395
+ #if defined(HAS_MIRRORSPLITUVROW_NEON)
396
+ if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
397
+ MirrorSplitUVRow = MirrorSplitUVRow_NEON;
398
+ }
399
+ #endif
400
+ #if defined(HAS_MIRRORSPLITUVROW_SSSE3)
401
+ if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
402
+ MirrorSplitUVRow = MirrorSplitUVRow_SSSE3;
403
+ }
404
+ #endif
405
+ #if defined(HAS_MIRRORSPLITUVROW_LSX)
406
+ if (TestCpuFlag(kCpuHasLSX) && IS_ALIGNED(width, 32)) {
407
+ MirrorSplitUVRow = MirrorSplitUVRow_LSX;
408
+ }
409
+ #endif
410
+
411
+ dst_a += dst_stride_a * (height - 1);
412
+ dst_b += dst_stride_b * (height - 1);
413
+
414
+ for (i = 0; i < height; ++i) {
415
+ MirrorSplitUVRow(src, dst_a, dst_b, width);
416
+ src += src_stride;
417
+ dst_a -= dst_stride_a;
418
+ dst_b -= dst_stride_b;
419
+ }
420
+ }
421
+
422
+ // Rotate UV and split into planar.
423
+ // width and height expected to be half size for NV12
424
+ LIBYUV_API
425
+ int SplitRotateUV(const uint8_t* src_uv,
426
+ int src_stride_uv,
427
+ uint8_t* dst_u,
428
+ int dst_stride_u,
429
+ uint8_t* dst_v,
430
+ int dst_stride_v,
431
+ int width,
432
+ int height,
433
+ enum RotationMode mode) {
434
+ if (!src_uv || width <= 0 || height == 0 || !dst_u || !dst_v) {
435
+ return -1;
436
+ }
437
+
438
+ // Negative height means invert the image.
439
+ if (height < 0) {
440
+ height = -height;
441
+ src_uv = src_uv + (height - 1) * src_stride_uv;
442
+ src_stride_uv = -src_stride_uv;
443
+ }
444
+
445
+ switch (mode) {
446
+ case kRotate0:
447
+ SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
448
+ dst_stride_v, width, height);
449
+ return 0;
450
+ case kRotate90:
451
+ SplitRotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
452
+ dst_stride_v, width, height);
453
+ return 0;
454
+ case kRotate270:
455
+ SplitRotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
456
+ dst_stride_v, width, height);
457
+ return 0;
458
+ case kRotate180:
459
+ SplitRotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
460
+ dst_stride_v, width, height);
461
+ return 0;
462
+ default:
463
+ break;
464
+ }
465
+ return -1;
466
+ }
467
+
468
+ LIBYUV_API
469
+ int RotatePlane(const uint8_t* src,
470
+ int src_stride,
471
+ uint8_t* dst,
472
+ int dst_stride,
473
+ int width,
474
+ int height,
475
+ enum RotationMode mode) {
476
+ if (!src || width <= 0 || height == 0 || !dst) {
477
+ return -1;
478
+ }
479
+
480
+ // Negative height means invert the image.
481
+ if (height < 0) {
482
+ height = -height;
483
+ src = src + (height - 1) * src_stride;
484
+ src_stride = -src_stride;
485
+ }
486
+
487
+ switch (mode) {
488
+ case kRotate0:
489
+ // copy frame
490
+ CopyPlane(src, src_stride, dst, dst_stride, width, height);
491
+ return 0;
492
+ case kRotate90:
493
+ RotatePlane90(src, src_stride, dst, dst_stride, width, height);
494
+ return 0;
495
+ case kRotate270:
496
+ RotatePlane270(src, src_stride, dst, dst_stride, width, height);
497
+ return 0;
498
+ case kRotate180:
499
+ RotatePlane180(src, src_stride, dst, dst_stride, width, height);
500
+ return 0;
501
+ default:
502
+ break;
503
+ }
504
+ return -1;
505
+ }
506
+
507
+ static void TransposePlane_16(const uint16_t* src,
508
+ int src_stride,
509
+ uint16_t* dst,
510
+ int dst_stride,
511
+ int width,
512
+ int height) {
513
+ int i = height;
514
+ // Work across the source in 8x8 tiles
515
+ while (i >= 8) {
516
+ TransposeWx8_16_C(src, src_stride, dst, dst_stride, width);
517
+ src += 8 * src_stride; // Go down 8 rows.
518
+ dst += 8; // Move over 8 columns.
519
+ i -= 8;
520
+ }
521
+
522
+ if (i > 0) {
523
+ TransposeWxH_16_C(src, src_stride, dst, dst_stride, width, i);
524
+ }
525
+ }
526
+
527
+ static void RotatePlane90_16(const uint16_t* src,
528
+ int src_stride,
529
+ uint16_t* dst,
530
+ int dst_stride,
531
+ int width,
532
+ int height) {
533
+ // Rotate by 90 is a transpose with the source read
534
+ // from bottom to top. So set the source pointer to the end
535
+ // of the buffer and flip the sign of the source stride.
536
+ src += src_stride * (height - 1);
537
+ src_stride = -src_stride;
538
+ TransposePlane_16(src, src_stride, dst, dst_stride, width, height);
539
+ }
540
+
541
+ static void RotatePlane270_16(const uint16_t* src,
542
+ int src_stride,
543
+ uint16_t* dst,
544
+ int dst_stride,
545
+ int width,
546
+ int height) {
547
+ // Rotate by 270 is a transpose with the destination written
548
+ // from bottom to top. So set the destination pointer to the end
549
+ // of the buffer and flip the sign of the destination stride.
550
+ dst += dst_stride * (width - 1);
551
+ dst_stride = -dst_stride;
552
+ TransposePlane_16(src, src_stride, dst, dst_stride, width, height);
553
+ }
554
+
555
+ static void RotatePlane180_16(const uint16_t* src,
556
+ int src_stride,
557
+ uint16_t* dst,
558
+ int dst_stride,
559
+ int width,
560
+ int height) {
561
+ const uint16_t* src_bot = src + src_stride * (height - 1);
562
+ uint16_t* dst_bot = dst + dst_stride * (height - 1);
563
+ int half_height = (height + 1) >> 1;
564
+ int y;
565
+
566
+ // Swap top and bottom row and mirror the content. Uses a temporary row.
567
+ align_buffer_64(row, width * 2);
568
+ uint16_t* row_tmp = (uint16_t*)row;
569
+ assert(row);
570
+ if (!row)
571
+ return;
572
+
573
+ // Odd height will harmlessly mirror the middle row twice.
574
+ for (y = 0; y < half_height; ++y) {
575
+ CopyRow_16_C(src, row_tmp, width); // Copy top row into buffer
576
+ MirrorRow_16_C(src_bot, dst, width); // Mirror bottom row into top row
577
+ MirrorRow_16_C(row_tmp, dst_bot, width); // Mirror buffer into bottom row
578
+ src += src_stride;
579
+ dst += dst_stride;
580
+ src_bot -= src_stride;
581
+ dst_bot -= dst_stride;
582
+ }
583
+ free_aligned_buffer_64(row);
584
+ }
585
+
586
+ LIBYUV_API
587
+ int RotatePlane_16(const uint16_t* src,
588
+ int src_stride,
589
+ uint16_t* dst,
590
+ int dst_stride,
591
+ int width,
592
+ int height,
593
+ enum RotationMode mode) {
594
+ if (!src || width <= 0 || height == 0 || !dst) {
595
+ return -1;
596
+ }
597
+
598
+ // Negative height means invert the image.
599
+ if (height < 0) {
600
+ height = -height;
601
+ src = src + (height - 1) * src_stride;
602
+ src_stride = -src_stride;
603
+ }
604
+
605
+ switch (mode) {
606
+ case kRotate0:
607
+ // copy frame
608
+ CopyPlane_16(src, src_stride, dst, dst_stride, width, height);
609
+ return 0;
610
+ case kRotate90:
611
+ RotatePlane90_16(src, src_stride, dst, dst_stride, width, height);
612
+ return 0;
613
+ case kRotate270:
614
+ RotatePlane270_16(src, src_stride, dst, dst_stride, width, height);
615
+ return 0;
616
+ case kRotate180:
617
+ RotatePlane180_16(src, src_stride, dst, dst_stride, width, height);
618
+ return 0;
619
+ default:
620
+ break;
621
+ }
622
+ return -1;
623
+ }
624
+
625
+ LIBYUV_API
626
+ int I420Rotate(const uint8_t* src_y,
627
+ int src_stride_y,
628
+ const uint8_t* src_u,
629
+ int src_stride_u,
630
+ const uint8_t* src_v,
631
+ int src_stride_v,
632
+ uint8_t* dst_y,
633
+ int dst_stride_y,
634
+ uint8_t* dst_u,
635
+ int dst_stride_u,
636
+ uint8_t* dst_v,
637
+ int dst_stride_v,
638
+ int width,
639
+ int height,
640
+ enum RotationMode mode) {
641
+ int halfwidth = (width + 1) >> 1;
642
+ int halfheight = (height + 1) >> 1;
643
+ if ((!src_y && dst_y) || !src_u || !src_v || width <= 0 || height == 0 ||
644
+ !dst_y || !dst_u || !dst_v) {
645
+ return -1;
646
+ }
647
+
648
+ // Negative height means invert the image.
649
+ if (height < 0) {
650
+ height = -height;
651
+ halfheight = (height + 1) >> 1;
652
+ src_y = src_y + (height - 1) * src_stride_y;
653
+ src_u = src_u + (halfheight - 1) * src_stride_u;
654
+ src_v = src_v + (halfheight - 1) * src_stride_v;
655
+ src_stride_y = -src_stride_y;
656
+ src_stride_u = -src_stride_u;
657
+ src_stride_v = -src_stride_v;
658
+ }
659
+
660
+ switch (mode) {
661
+ case kRotate0:
662
+ // copy frame
663
+ return I420Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
664
+ src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
665
+ dst_v, dst_stride_v, width, height);
666
+ case kRotate90:
667
+ RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
668
+ RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
669
+ halfheight);
670
+ RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
671
+ halfheight);
672
+ return 0;
673
+ case kRotate270:
674
+ RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
675
+ RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
676
+ halfheight);
677
+ RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
678
+ halfheight);
679
+ return 0;
680
+ case kRotate180:
681
+ RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
682
+ RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
683
+ halfheight);
684
+ RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
685
+ halfheight);
686
+ return 0;
687
+ default:
688
+ break;
689
+ }
690
+ return -1;
691
+ }
692
+
693
+ // I422 has half width x full height UV planes, so rotate by 90 and 270
694
+ // require scaling to maintain 422 subsampling.
695
+ LIBYUV_API
696
+ int I422Rotate(const uint8_t* src_y,
697
+ int src_stride_y,
698
+ const uint8_t* src_u,
699
+ int src_stride_u,
700
+ const uint8_t* src_v,
701
+ int src_stride_v,
702
+ uint8_t* dst_y,
703
+ int dst_stride_y,
704
+ uint8_t* dst_u,
705
+ int dst_stride_u,
706
+ uint8_t* dst_v,
707
+ int dst_stride_v,
708
+ int width,
709
+ int height,
710
+ enum RotationMode mode) {
711
+ int halfwidth = (width + 1) >> 1;
712
+ int halfheight = (height + 1) >> 1;
713
+ int r;
714
+ if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
715
+ !dst_u || !dst_v) {
716
+ return -1;
717
+ }
718
+ // Negative height means invert the image.
719
+ if (height < 0) {
720
+ height = -height;
721
+ src_y = src_y + (height - 1) * src_stride_y;
722
+ src_u = src_u + (height - 1) * src_stride_u;
723
+ src_v = src_v + (height - 1) * src_stride_v;
724
+ src_stride_y = -src_stride_y;
725
+ src_stride_u = -src_stride_u;
726
+ src_stride_v = -src_stride_v;
727
+ }
728
+
729
+ switch (mode) {
730
+ case kRotate0:
731
+ // Copy frame
732
+ CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
733
+ CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
734
+ CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
735
+ return 0;
736
+
737
+ // Note on temporary Y plane for UV.
738
+ // Rotation of UV first fits within the Y destination plane rows.
739
+ // Y plane is width x height
740
+ // Y plane rotated is height x width
741
+ // UV plane is (width / 2) x height
742
+ // UV plane rotated is height x (width / 2)
743
+ // UV plane rotated+scaled is (height / 2) x width.
744
+ // UV plane rotated is a temporary that fits within the Y plane rotated.
745
+
746
+ case kRotate90:
747
+ RotatePlane90(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
748
+ height);
749
+ r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u,
750
+ dst_stride_u, halfheight, width, kFilterBilinear);
751
+ if (r != 0) {
752
+ return r;
753
+ }
754
+ RotatePlane90(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
755
+ height);
756
+ r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v,
757
+ dst_stride_v, halfheight, width, kFilterLinear);
758
+ if (r != 0) {
759
+ return r;
760
+ }
761
+ RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
762
+ return 0;
763
+ case kRotate270:
764
+ RotatePlane270(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
765
+ height);
766
+ r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u,
767
+ dst_stride_u, halfheight, width, kFilterBilinear);
768
+ if (r != 0) {
769
+ return r;
770
+ }
771
+ RotatePlane270(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
772
+ height);
773
+ r = ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v,
774
+ dst_stride_v, halfheight, width, kFilterLinear);
775
+ if (r != 0) {
776
+ return r;
777
+ }
778
+ RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
779
+ return 0;
780
+ case kRotate180:
781
+ RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
782
+ RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
783
+ height);
784
+ RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
785
+ height);
786
+ return 0;
787
+ default:
788
+ break;
789
+ }
790
+ return -1;
791
+ }
792
+
793
+ LIBYUV_API
794
+ int I444Rotate(const uint8_t* src_y,
795
+ int src_stride_y,
796
+ const uint8_t* src_u,
797
+ int src_stride_u,
798
+ const uint8_t* src_v,
799
+ int src_stride_v,
800
+ uint8_t* dst_y,
801
+ int dst_stride_y,
802
+ uint8_t* dst_u,
803
+ int dst_stride_u,
804
+ uint8_t* dst_v,
805
+ int dst_stride_v,
806
+ int width,
807
+ int height,
808
+ enum RotationMode mode) {
809
+ if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
810
+ !dst_u || !dst_v) {
811
+ return -1;
812
+ }
813
+
814
+ // Negative height means invert the image.
815
+ if (height < 0) {
816
+ height = -height;
817
+ src_y = src_y + (height - 1) * src_stride_y;
818
+ src_u = src_u + (height - 1) * src_stride_u;
819
+ src_v = src_v + (height - 1) * src_stride_v;
820
+ src_stride_y = -src_stride_y;
821
+ src_stride_u = -src_stride_u;
822
+ src_stride_v = -src_stride_v;
823
+ }
824
+
825
+ switch (mode) {
826
+ case kRotate0:
827
+ // copy frame
828
+ CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
829
+ CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
830
+ CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
831
+ return 0;
832
+ case kRotate90:
833
+ RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
834
+ RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
835
+ RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
836
+ return 0;
837
+ case kRotate270:
838
+ RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
839
+ RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
840
+ RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
841
+ return 0;
842
+ case kRotate180:
843
+ RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
844
+ RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
845
+ RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
846
+ return 0;
847
+ default:
848
+ break;
849
+ }
850
+ return -1;
851
+ }
852
+
853
+ LIBYUV_API
854
+ int NV12ToI420Rotate(const uint8_t* src_y,
855
+ int src_stride_y,
856
+ const uint8_t* src_uv,
857
+ int src_stride_uv,
858
+ uint8_t* dst_y,
859
+ int dst_stride_y,
860
+ uint8_t* dst_u,
861
+ int dst_stride_u,
862
+ uint8_t* dst_v,
863
+ int dst_stride_v,
864
+ int width,
865
+ int height,
866
+ enum RotationMode mode) {
867
+ int halfwidth = (width + 1) >> 1;
868
+ int halfheight = (height + 1) >> 1;
869
+ if (!src_y || !src_uv || width <= 0 || height == 0 || !dst_y || !dst_u ||
870
+ !dst_v) {
871
+ return -1;
872
+ }
873
+
874
+ // Negative height means invert the image.
875
+ if (height < 0) {
876
+ height = -height;
877
+ halfheight = (height + 1) >> 1;
878
+ src_y = src_y + (height - 1) * src_stride_y;
879
+ src_uv = src_uv + (halfheight - 1) * src_stride_uv;
880
+ src_stride_y = -src_stride_y;
881
+ src_stride_uv = -src_stride_uv;
882
+ }
883
+
884
+ switch (mode) {
885
+ case kRotate0:
886
+ // copy frame
887
+ return NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
888
+ dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
889
+ width, height);
890
+ case kRotate90:
891
+ RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
892
+ SplitRotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
893
+ dst_stride_v, halfwidth, halfheight);
894
+ return 0;
895
+ case kRotate270:
896
+ RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
897
+ SplitRotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
898
+ dst_stride_v, halfwidth, halfheight);
899
+ return 0;
900
+ case kRotate180:
901
+ RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
902
+ SplitRotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
903
+ dst_stride_v, halfwidth, halfheight);
904
+ return 0;
905
+ default:
906
+ break;
907
+ }
908
+ return -1;
909
+ }
910
+
911
+ static void SplitPixels(const uint8_t* src_u,
912
+ int src_pixel_stride_uv,
913
+ uint8_t* dst_u,
914
+ int width) {
915
+ int i;
916
+ for (i = 0; i < width; ++i) {
917
+ *dst_u = *src_u;
918
+ ++dst_u;
919
+ src_u += src_pixel_stride_uv;
920
+ }
921
+ }
922
+
923
+ // Convert Android420 to I420 with Rotate
924
+ LIBYUV_API
925
+ int Android420ToI420Rotate(const uint8_t* src_y,
926
+ int src_stride_y,
927
+ const uint8_t* src_u,
928
+ int src_stride_u,
929
+ const uint8_t* src_v,
930
+ int src_stride_v,
931
+ int src_pixel_stride_uv,
932
+ uint8_t* dst_y,
933
+ int dst_stride_y,
934
+ uint8_t* dst_u,
935
+ int dst_stride_u,
936
+ uint8_t* dst_v,
937
+ int dst_stride_v,
938
+ int width,
939
+ int height,
940
+ enum RotationMode rotation) {
941
+ int y;
942
+ const ptrdiff_t vu_off = src_v - src_u;
943
+ int halfwidth = (width + 1) >> 1;
944
+ int halfheight = (height + 1) >> 1;
945
+ if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
946
+ height == 0) {
947
+ return -1;
948
+ }
949
+ // Negative height means invert the image.
950
+ if (height < 0) {
951
+ height = -height;
952
+ halfheight = (height + 1) >> 1;
953
+ src_y = src_y + (height - 1) * src_stride_y;
954
+ src_u = src_u + (halfheight - 1) * src_stride_u;
955
+ src_v = src_v + (halfheight - 1) * src_stride_v;
956
+ src_stride_y = -src_stride_y;
957
+ src_stride_u = -src_stride_u;
958
+ src_stride_v = -src_stride_v;
959
+ }
960
+
961
+ if (dst_y) {
962
+ RotatePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
963
+ rotation);
964
+ }
965
+
966
+ // Copy UV planes - I420
967
+ if (src_pixel_stride_uv == 1) {
968
+ RotatePlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight,
969
+ rotation);
970
+ RotatePlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight,
971
+ rotation);
972
+ return 0;
973
+ }
974
+ // Split UV planes - NV21
975
+ if (src_pixel_stride_uv == 2 && vu_off == -1 &&
976
+ src_stride_u == src_stride_v) {
977
+ SplitRotateUV(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
978
+ halfwidth, halfheight, rotation);
979
+ return 0;
980
+ }
981
+ // Split UV planes - NV12
982
+ if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
983
+ SplitRotateUV(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
984
+ halfwidth, halfheight, rotation);
985
+ return 0;
986
+ }
987
+
988
+ if (rotation == 0) {
989
+ for (y = 0; y < halfheight; ++y) {
990
+ SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
991
+ SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
992
+ src_u += src_stride_u;
993
+ src_v += src_stride_v;
994
+ dst_u += dst_stride_u;
995
+ dst_v += dst_stride_v;
996
+ }
997
+ return 0;
998
+ }
999
+ // unsupported type and/or rotation.
1000
+ return -1;
1001
+ }
1002
+
1003
+ LIBYUV_API
1004
+ int I010Rotate(const uint16_t* src_y,
1005
+ int src_stride_y,
1006
+ const uint16_t* src_u,
1007
+ int src_stride_u,
1008
+ const uint16_t* src_v,
1009
+ int src_stride_v,
1010
+ uint16_t* dst_y,
1011
+ int dst_stride_y,
1012
+ uint16_t* dst_u,
1013
+ int dst_stride_u,
1014
+ uint16_t* dst_v,
1015
+ int dst_stride_v,
1016
+ int width,
1017
+ int height,
1018
+ enum RotationMode mode) {
1019
+ int halfwidth = (width + 1) >> 1;
1020
+ int halfheight = (height + 1) >> 1;
1021
+ if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1022
+ !dst_u || !dst_v || dst_stride_y < 0) {
1023
+ return -1;
1024
+ }
1025
+ // Negative height means invert the image.
1026
+ if (height < 0) {
1027
+ height = -height;
1028
+ src_y = src_y + (height - 1) * src_stride_y;
1029
+ src_u = src_u + (height - 1) * src_stride_u;
1030
+ src_v = src_v + (height - 1) * src_stride_v;
1031
+ src_stride_y = -src_stride_y;
1032
+ src_stride_u = -src_stride_u;
1033
+ src_stride_v = -src_stride_v;
1034
+ }
1035
+
1036
+ switch (mode) {
1037
+ case kRotate0:
1038
+ // copy frame
1039
+ return I010Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
1040
+ src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1041
+ dst_v, dst_stride_v, width, height);
1042
+ case kRotate90:
1043
+ RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1044
+ RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1045
+ halfheight);
1046
+ RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1047
+ halfheight);
1048
+ return 0;
1049
+ case kRotate270:
1050
+ RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1051
+ height);
1052
+ RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1053
+ halfheight);
1054
+ RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1055
+ halfheight);
1056
+ return 0;
1057
+ case kRotate180:
1058
+ RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1059
+ height);
1060
+ RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1061
+ halfheight);
1062
+ RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1063
+ halfheight);
1064
+ return 0;
1065
+ default:
1066
+ break;
1067
+ }
1068
+ return -1;
1069
+ }
1070
+
1071
+ // I210 has half width x full height UV planes, so rotate by 90 and 270
1072
+ // require scaling to maintain 422 subsampling.
1073
+ LIBYUV_API
1074
+ int I210Rotate(const uint16_t* src_y,
1075
+ int src_stride_y,
1076
+ const uint16_t* src_u,
1077
+ int src_stride_u,
1078
+ const uint16_t* src_v,
1079
+ int src_stride_v,
1080
+ uint16_t* dst_y,
1081
+ int dst_stride_y,
1082
+ uint16_t* dst_u,
1083
+ int dst_stride_u,
1084
+ uint16_t* dst_v,
1085
+ int dst_stride_v,
1086
+ int width,
1087
+ int height,
1088
+ enum RotationMode mode) {
1089
+ int halfwidth = (width + 1) >> 1;
1090
+ int halfheight = (height + 1) >> 1;
1091
+ int r;
1092
+ if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1093
+ !dst_u || !dst_v) {
1094
+ return -1;
1095
+ }
1096
+ // Negative height means invert the image.
1097
+ if (height < 0) {
1098
+ height = -height;
1099
+ src_y = src_y + (height - 1) * src_stride_y;
1100
+ src_u = src_u + (height - 1) * src_stride_u;
1101
+ src_v = src_v + (height - 1) * src_stride_v;
1102
+ src_stride_y = -src_stride_y;
1103
+ src_stride_u = -src_stride_u;
1104
+ src_stride_v = -src_stride_v;
1105
+ }
1106
+
1107
+ switch (mode) {
1108
+ case kRotate0:
1109
+ // Copy frame
1110
+ CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1111
+ CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
1112
+ CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
1113
+ return 0;
1114
+
1115
+ // Note on temporary Y plane for UV.
1116
+ // Rotation of UV first fits within the Y destination plane rows.
1117
+ // Y plane is width x height
1118
+ // Y plane rotated is height x width
1119
+ // UV plane is (width / 2) x height
1120
+ // UV plane rotated is height x (width / 2)
1121
+ // UV plane rotated+scaled is (height / 2) x width.
1122
+ // UV plane rotated is a temporary that fits within the Y plane rotated.
1123
+
1124
+ case kRotate90:
1125
+ RotatePlane90_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
1126
+ height);
1127
+ r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u,
1128
+ dst_stride_u, halfheight, width, kFilterBilinear);
1129
+ if (r != 0) {
1130
+ return r;
1131
+ }
1132
+ RotatePlane90_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
1133
+ height);
1134
+ r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v,
1135
+ dst_stride_v, halfheight, width, kFilterLinear);
1136
+ if (r != 0) {
1137
+ return r;
1138
+ }
1139
+ RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1140
+ return 0;
1141
+ case kRotate270:
1142
+ RotatePlane270_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth,
1143
+ height);
1144
+ r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u,
1145
+ dst_stride_u, halfheight, width, kFilterBilinear);
1146
+ if (r != 0) {
1147
+ return r;
1148
+ }
1149
+ RotatePlane270_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth,
1150
+ height);
1151
+ r = ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v,
1152
+ dst_stride_v, halfheight, width, kFilterLinear);
1153
+ if (r != 0) {
1154
+ return r;
1155
+ }
1156
+ RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1157
+ height);
1158
+ return 0;
1159
+ case kRotate180:
1160
+ RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1161
+ height);
1162
+ RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
1163
+ height);
1164
+ RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
1165
+ height);
1166
+ return 0;
1167
+ default:
1168
+ break;
1169
+ }
1170
+ return -1;
1171
+ }
1172
+
1173
+ LIBYUV_API
1174
+ int I410Rotate(const uint16_t* src_y,
1175
+ int src_stride_y,
1176
+ const uint16_t* src_u,
1177
+ int src_stride_u,
1178
+ const uint16_t* src_v,
1179
+ int src_stride_v,
1180
+ uint16_t* dst_y,
1181
+ int dst_stride_y,
1182
+ uint16_t* dst_u,
1183
+ int dst_stride_u,
1184
+ uint16_t* dst_v,
1185
+ int dst_stride_v,
1186
+ int width,
1187
+ int height,
1188
+ enum RotationMode mode) {
1189
+ if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
1190
+ !dst_u || !dst_v || dst_stride_y < 0) {
1191
+ return -1;
1192
+ }
1193
+ // Negative height means invert the image.
1194
+ if (height < 0) {
1195
+ height = -height;
1196
+ src_y = src_y + (height - 1) * src_stride_y;
1197
+ src_u = src_u + (height - 1) * src_stride_u;
1198
+ src_v = src_v + (height - 1) * src_stride_v;
1199
+ src_stride_y = -src_stride_y;
1200
+ src_stride_u = -src_stride_u;
1201
+ src_stride_v = -src_stride_v;
1202
+ }
1203
+
1204
+ switch (mode) {
1205
+ case kRotate0:
1206
+ // copy frame
1207
+ CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1208
+ CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
1209
+ CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
1210
+ return 0;
1211
+ case kRotate90:
1212
+ RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1213
+ RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
1214
+ RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
1215
+ return 0;
1216
+ case kRotate270:
1217
+ RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1218
+ height);
1219
+ RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, width,
1220
+ height);
1221
+ RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, width,
1222
+ height);
1223
+ return 0;
1224
+ case kRotate180:
1225
+ RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width,
1226
+ height);
1227
+ RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, width,
1228
+ height);
1229
+ RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, width,
1230
+ height);
1231
+ return 0;
1232
+ default:
1233
+ break;
1234
+ }
1235
+ return -1;
1236
+ }
1237
+
1238
+ #ifdef __cplusplus
1239
+ } // extern "C"
1240
+ } // namespace libyuv
1241
+ #endif