react-native-vision-camera-spoof-detector 1.0.21 → 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 (197) hide show
  1. package/.gitattributes +2 -0
  2. package/.gitignore +27 -0
  3. package/CHANGELOG.md +2 -2
  4. package/CONTRIBUTING.md +2 -2
  5. package/README.md +442 -443
  6. package/android/build.gradle +12 -4
  7. package/android/src/main/cpp/CMakeLists.txt +101 -94
  8. package/android/src/main/cpp/libyuv/.clang-format +6 -6
  9. package/android/src/main/cpp/libyuv/.gn +40 -40
  10. package/android/src/main/cpp/libyuv/.vpython3 +410 -410
  11. package/android/src/main/cpp/libyuv/AUTHORS +7 -7
  12. package/android/src/main/cpp/libyuv/Android.bp +202 -202
  13. package/android/src/main/cpp/libyuv/Android.mk +106 -106
  14. package/android/src/main/cpp/libyuv/BUILD.gn +490 -490
  15. package/android/src/main/cpp/libyuv/CM_linux_packages.cmake +70 -70
  16. package/android/src/main/cpp/libyuv/CMakeLists.txt +259 -252
  17. package/android/src/main/cpp/libyuv/DEPS +935 -935
  18. package/android/src/main/cpp/libyuv/DIR_METADATA +3 -3
  19. package/android/src/main/cpp/libyuv/LICENSE +29 -29
  20. package/android/src/main/cpp/libyuv/OWNERS +11 -11
  21. package/android/src/main/cpp/libyuv/PATENTS +23 -23
  22. package/android/src/main/cpp/libyuv/PRESUBMIT.py +65 -65
  23. package/android/src/main/cpp/libyuv/README.chromium +11 -11
  24. package/android/src/main/cpp/libyuv/README.md +19 -19
  25. package/android/src/main/cpp/libyuv/build_overrides/build.gni +60 -60
  26. package/android/src/main/cpp/libyuv/build_overrides/gtest.gni +19 -19
  27. package/android/src/main/cpp/libyuv/build_overrides/partition_alloc.gni +17 -17
  28. package/android/src/main/cpp/libyuv/codereview.settings +5 -5
  29. package/android/src/main/cpp/libyuv/docs/deprecated_builds.md +409 -409
  30. package/android/src/main/cpp/libyuv/docs/environment_variables.md +64 -64
  31. package/android/src/main/cpp/libyuv/docs/feature_detection.md +108 -108
  32. package/android/src/main/cpp/libyuv/docs/filtering.md +196 -196
  33. package/android/src/main/cpp/libyuv/docs/formats.md +208 -208
  34. package/android/src/main/cpp/libyuv/docs/getting_started.md +296 -296
  35. package/android/src/main/cpp/libyuv/docs/rotation.md +107 -107
  36. package/android/src/main/cpp/libyuv/download_vs_toolchain.py +29 -29
  37. package/android/src/main/cpp/libyuv/include/libyuv/basic_types.h +68 -68
  38. package/android/src/main/cpp/libyuv/include/libyuv/compare.h +111 -111
  39. package/android/src/main/cpp/libyuv/include/libyuv/compare_row.h +112 -112
  40. package/android/src/main/cpp/libyuv/include/libyuv/convert.h +1117 -1117
  41. package/android/src/main/cpp/libyuv/include/libyuv/convert_argb.h +2335 -2335
  42. package/android/src/main/cpp/libyuv/include/libyuv/convert_from.h +203 -203
  43. package/android/src/main/cpp/libyuv/include/libyuv/convert_from_argb.h +394 -394
  44. package/android/src/main/cpp/libyuv/include/libyuv/cpu_id.h +147 -147
  45. package/android/src/main/cpp/libyuv/include/libyuv/cpu_support.h +99 -99
  46. package/android/src/main/cpp/libyuv/include/libyuv/loongson_intrinsics.h +1949 -1949
  47. package/android/src/main/cpp/libyuv/include/libyuv/mjpeg_decoder.h +195 -195
  48. package/android/src/main/cpp/libyuv/include/libyuv/planar_functions.h +1131 -1131
  49. package/android/src/main/cpp/libyuv/include/libyuv/rotate.h +296 -296
  50. package/android/src/main/cpp/libyuv/include/libyuv/rotate_argb.h +37 -37
  51. package/android/src/main/cpp/libyuv/include/libyuv/rotate_row.h +265 -265
  52. package/android/src/main/cpp/libyuv/include/libyuv/row.h +6738 -6738
  53. package/android/src/main/cpp/libyuv/include/libyuv/row_sve.h +2154 -2154
  54. package/android/src/main/cpp/libyuv/include/libyuv/scale.h +336 -336
  55. package/android/src/main/cpp/libyuv/include/libyuv/scale_argb.h +76 -76
  56. package/android/src/main/cpp/libyuv/include/libyuv/scale_rgb.h +42 -42
  57. package/android/src/main/cpp/libyuv/include/libyuv/scale_row.h +1726 -1726
  58. package/android/src/main/cpp/libyuv/include/libyuv/scale_uv.h +51 -51
  59. package/android/src/main/cpp/libyuv/include/libyuv/version.h +16 -16
  60. package/android/src/main/cpp/libyuv/include/libyuv/video_common.h +222 -222
  61. package/android/src/main/cpp/libyuv/include/libyuv.h +33 -33
  62. package/android/src/main/cpp/libyuv/infra/config/OWNERS +3 -3
  63. package/android/src/main/cpp/libyuv/infra/config/PRESUBMIT.py +17 -17
  64. package/android/src/main/cpp/libyuv/infra/config/README.md +2 -2
  65. package/android/src/main/cpp/libyuv/infra/config/codereview.settings +6 -6
  66. package/android/src/main/cpp/libyuv/infra/config/commit-queue.cfg +144 -144
  67. package/android/src/main/cpp/libyuv/infra/config/cr-buildbucket.cfg +1185 -1185
  68. package/android/src/main/cpp/libyuv/infra/config/luci-logdog.cfg +9 -9
  69. package/android/src/main/cpp/libyuv/infra/config/luci-milo.cfg +246 -246
  70. package/android/src/main/cpp/libyuv/infra/config/luci-scheduler.cfg +385 -385
  71. package/android/src/main/cpp/libyuv/infra/config/main.star +402 -402
  72. package/android/src/main/cpp/libyuv/infra/config/project.cfg +16 -16
  73. package/android/src/main/cpp/libyuv/infra/config/realms.cfg +111 -111
  74. package/android/src/main/cpp/libyuv/libyuv.gni +34 -34
  75. package/android/src/main/cpp/libyuv/libyuv.gyp +149 -149
  76. package/android/src/main/cpp/libyuv/libyuv.gypi +87 -87
  77. package/android/src/main/cpp/libyuv/linux.mk +96 -96
  78. package/android/src/main/cpp/libyuv/public.mk +13 -13
  79. package/android/src/main/cpp/libyuv/pylintrc +49 -49
  80. package/android/src/main/cpp/libyuv/riscv_script/prepare_toolchain_qemu.sh +74 -74
  81. package/android/src/main/cpp/libyuv/riscv_script/riscv-clang.cmake +56 -56
  82. package/android/src/main/cpp/libyuv/riscv_script/run_qemu.sh +15 -15
  83. package/android/src/main/cpp/libyuv/source/compare.cc +435 -435
  84. package/android/src/main/cpp/libyuv/source/compare_common.cc +74 -74
  85. package/android/src/main/cpp/libyuv/source/compare_gcc.cc +362 -362
  86. package/android/src/main/cpp/libyuv/source/compare_neon.cc +96 -96
  87. package/android/src/main/cpp/libyuv/source/compare_neon64.cc +223 -223
  88. package/android/src/main/cpp/libyuv/source/compare_win.cc +241 -241
  89. package/android/src/main/cpp/libyuv/source/convert.cc +4746 -4746
  90. package/android/src/main/cpp/libyuv/source/convert_argb.cc +9179 -9179
  91. package/android/src/main/cpp/libyuv/source/convert_from.cc +866 -866
  92. package/android/src/main/cpp/libyuv/source/convert_from_argb.cc +3671 -3671
  93. package/android/src/main/cpp/libyuv/source/convert_jpeg.cc +602 -602
  94. package/android/src/main/cpp/libyuv/source/convert_to_argb.cc +391 -391
  95. package/android/src/main/cpp/libyuv/source/convert_to_i420.cc +288 -288
  96. package/android/src/main/cpp/libyuv/source/cpu_id.cc +496 -496
  97. package/android/src/main/cpp/libyuv/source/mjpeg_decoder.cc +580 -580
  98. package/android/src/main/cpp/libyuv/source/mjpeg_validate.cc +71 -71
  99. package/android/src/main/cpp/libyuv/source/planar_functions.cc +5663 -5663
  100. package/android/src/main/cpp/libyuv/source/rotate.cc +1241 -1241
  101. package/android/src/main/cpp/libyuv/source/rotate_any.cc +76 -76
  102. package/android/src/main/cpp/libyuv/source/rotate_argb.cc +259 -259
  103. package/android/src/main/cpp/libyuv/source/rotate_common.cc +208 -208
  104. package/android/src/main/cpp/libyuv/source/rotate_gcc.cc +505 -505
  105. package/android/src/main/cpp/libyuv/source/rotate_lsx.cc +233 -233
  106. package/android/src/main/cpp/libyuv/source/rotate_neon.cc +219 -219
  107. package/android/src/main/cpp/libyuv/source/rotate_neon64.cc +273 -273
  108. package/android/src/main/cpp/libyuv/source/rotate_sme.cc +174 -174
  109. package/android/src/main/cpp/libyuv/source/rotate_win.cc +253 -253
  110. package/android/src/main/cpp/libyuv/source/row_any.cc +2519 -2519
  111. package/android/src/main/cpp/libyuv/source/row_common.cc +4461 -4461
  112. package/android/src/main/cpp/libyuv/source/row_gcc.cc +9570 -9570
  113. package/android/src/main/cpp/libyuv/source/row_lasx.cc +2343 -2343
  114. package/android/src/main/cpp/libyuv/source/row_lsx.cc +3030 -3030
  115. package/android/src/main/cpp/libyuv/source/row_neon.cc +4026 -4026
  116. package/android/src/main/cpp/libyuv/source/row_neon64.cc +5617 -5617
  117. package/android/src/main/cpp/libyuv/source/row_rvv.cc +2599 -2599
  118. package/android/src/main/cpp/libyuv/source/row_sme.cc +1183 -1183
  119. package/android/src/main/cpp/libyuv/source/row_sve.cc +1088 -1088
  120. package/android/src/main/cpp/libyuv/source/row_win.cc +6453 -6453
  121. package/android/src/main/cpp/libyuv/source/scale.cc +2710 -2710
  122. package/android/src/main/cpp/libyuv/source/scale_any.cc +991 -991
  123. package/android/src/main/cpp/libyuv/source/scale_argb.cc +1158 -1158
  124. package/android/src/main/cpp/libyuv/source/scale_common.cc +1977 -1977
  125. package/android/src/main/cpp/libyuv/source/scale_gcc.cc +2947 -2947
  126. package/android/src/main/cpp/libyuv/source/scale_lsx.cc +739 -739
  127. package/android/src/main/cpp/libyuv/source/scale_neon.cc +1449 -1449
  128. package/android/src/main/cpp/libyuv/source/scale_neon64.cc +1552 -1552
  129. package/android/src/main/cpp/libyuv/source/scale_rgb.cc +82 -82
  130. package/android/src/main/cpp/libyuv/source/scale_rvv.cc +1971 -1971
  131. package/android/src/main/cpp/libyuv/source/scale_sme.cc +555 -555
  132. package/android/src/main/cpp/libyuv/source/scale_uv.cc +1159 -1159
  133. package/android/src/main/cpp/libyuv/source/scale_win.cc +1392 -1392
  134. package/android/src/main/cpp/libyuv/source/test.sh +35 -35
  135. package/android/src/main/cpp/libyuv/source/video_common.cc +62 -62
  136. package/android/src/main/cpp/libyuv/tools_libyuv/OWNERS +4 -4
  137. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/roll_deps.py +931 -931
  138. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py +164 -164
  139. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS +21 -21
  140. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium.new +13 -13
  141. package/android/src/main/cpp/libyuv/tools_libyuv/autoroller/unittests/testdata/DEPS.chromium.old +13 -13
  142. package/android/src/main/cpp/libyuv/tools_libyuv/get_landmines.py +38 -38
  143. package/android/src/main/cpp/libyuv/tools_libyuv/msan/OWNERS +3 -3
  144. package/android/src/main/cpp/libyuv/tools_libyuv/msan/blacklist.txt +9 -9
  145. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/OWNERS +3 -3
  146. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/blacklist.txt +15 -15
  147. package/android/src/main/cpp/libyuv/tools_libyuv/ubsan/vptr_blacklist.txt +25 -25
  148. package/android/src/main/cpp/libyuv/unit_test/basictypes_test.cc +43 -43
  149. package/android/src/main/cpp/libyuv/unit_test/color_test.cc +848 -848
  150. package/android/src/main/cpp/libyuv/unit_test/compare_test.cc +739 -739
  151. package/android/src/main/cpp/libyuv/unit_test/convert_argb_test.cc +2867 -2867
  152. package/android/src/main/cpp/libyuv/unit_test/convert_test.cc +2133 -2133
  153. package/android/src/main/cpp/libyuv/unit_test/cpu_test.cc +427 -427
  154. package/android/src/main/cpp/libyuv/unit_test/cpu_thread_test.cc +63 -63
  155. package/android/src/main/cpp/libyuv/unit_test/math_test.cc +160 -160
  156. package/android/src/main/cpp/libyuv/unit_test/planar_test.cc +4731 -4731
  157. package/android/src/main/cpp/libyuv/unit_test/rotate_argb_test.cc +334 -334
  158. package/android/src/main/cpp/libyuv/unit_test/rotate_test.cc +962 -962
  159. package/android/src/main/cpp/libyuv/unit_test/scale_argb_test.cc +590 -590
  160. package/android/src/main/cpp/libyuv/unit_test/scale_plane_test.cc +465 -465
  161. package/android/src/main/cpp/libyuv/unit_test/scale_rgb_test.cc +280 -280
  162. package/android/src/main/cpp/libyuv/unit_test/scale_test.cc +1135 -1135
  163. package/android/src/main/cpp/libyuv/unit_test/scale_uv_test.cc +249 -249
  164. package/android/src/main/cpp/libyuv/unit_test/testdata/arm_v7.txt +12 -12
  165. package/android/src/main/cpp/libyuv/unit_test/testdata/mips.txt +7 -7
  166. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson2k.txt +5 -5
  167. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson3.txt +10 -10
  168. package/android/src/main/cpp/libyuv/unit_test/testdata/mips_loongson_mmi.txt +7 -7
  169. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64.txt +3 -3
  170. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64_rvv.txt +3 -3
  171. package/android/src/main/cpp/libyuv/unit_test/testdata/riscv64_rvv_zvfh.txt +3 -3
  172. package/android/src/main/cpp/libyuv/unit_test/testdata/tegra3.txt +23 -23
  173. package/android/src/main/cpp/libyuv/unit_test/unit_test.cc +581 -581
  174. package/android/src/main/cpp/libyuv/unit_test/unit_test.h +232 -232
  175. package/android/src/main/cpp/libyuv/unit_test/video_common_test.cc +112 -112
  176. package/android/src/main/cpp/libyuv/util/Makefile +9 -9
  177. package/android/src/main/cpp/libyuv/util/color.cc +120 -120
  178. package/android/src/main/cpp/libyuv/util/compare.cc +67 -67
  179. package/android/src/main/cpp/libyuv/util/cpuid.c +211 -211
  180. package/android/src/main/cpp/libyuv/util/i444tonv12_eg.cc +27 -27
  181. package/android/src/main/cpp/libyuv/util/psnr.cc +291 -291
  182. package/android/src/main/cpp/libyuv/util/psnr.h +47 -47
  183. package/android/src/main/cpp/libyuv/util/psnr_main.cc +620 -620
  184. package/android/src/main/cpp/libyuv/util/ssim.cc +364 -364
  185. package/android/src/main/cpp/libyuv/util/ssim.h +38 -38
  186. package/android/src/main/cpp/libyuv/util/yuvconstants.c +114 -114
  187. package/android/src/main/cpp/libyuv/util/yuvconvert.cc +367 -367
  188. package/android/src/main/cpp/libyuv/winarm.mk +47 -47
  189. package/package.json +86 -84
  190. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  191. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  192. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  193. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  194. package/android/.gradle/8.9/gc.properties +0 -0
  195. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  196. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  197. 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