rotate.cc 15 KB

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