rotate.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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_COPYROW_SSE2)
  136. if (TestCpuFlag(kCpuHasSSE2)) {
  137. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
  138. }
  139. #endif
  140. #if defined(HAS_COPYROW_AVX)
  141. if (TestCpuFlag(kCpuHasAVX)) {
  142. CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
  143. }
  144. #endif
  145. #if defined(HAS_COPYROW_ERMS)
  146. if (TestCpuFlag(kCpuHasERMS)) {
  147. CopyRow = CopyRow_ERMS;
  148. }
  149. #endif
  150. #if defined(HAS_COPYROW_NEON)
  151. if (TestCpuFlag(kCpuHasNEON)) {
  152. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
  153. }
  154. #endif
  155. #if defined(HAS_COPYROW_MIPS)
  156. if (TestCpuFlag(kCpuHasMIPS)) {
  157. CopyRow = CopyRow_MIPS;
  158. }
  159. #endif
  160. // Odd height will harmlessly mirror the middle row twice.
  161. for (y = 0; y < half_height; ++y) {
  162. MirrorRow(src, row, width); // Mirror first row into a buffer
  163. src += src_stride;
  164. MirrorRow(src_bot, dst, width); // Mirror last row into first row
  165. dst += dst_stride;
  166. CopyRow(row, dst_bot, width); // Copy first mirrored row into last
  167. src_bot -= src_stride;
  168. dst_bot -= dst_stride;
  169. }
  170. free_aligned_buffer_64(row);
  171. }
  172. LIBYUV_API
  173. void TransposeUV(const uint8* src, int src_stride,
  174. uint8* dst_a, int dst_stride_a,
  175. uint8* dst_b, int dst_stride_b,
  176. int width, int height) {
  177. int i = height;
  178. void (*TransposeUVWx8)(const uint8* src, int src_stride,
  179. uint8* dst_a, int dst_stride_a,
  180. uint8* dst_b, int dst_stride_b,
  181. int width) = TransposeUVWx8_C;
  182. #if defined(HAS_TRANSPOSEUVWX8_NEON)
  183. if (TestCpuFlag(kCpuHasNEON)) {
  184. TransposeUVWx8 = TransposeUVWx8_NEON;
  185. }
  186. #endif
  187. #if defined(HAS_TRANSPOSEUVWX8_SSE2)
  188. if (TestCpuFlag(kCpuHasSSE2)) {
  189. TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
  190. if (IS_ALIGNED(width, 8)) {
  191. TransposeUVWx8 = TransposeUVWx8_SSE2;
  192. }
  193. }
  194. #endif
  195. #if defined(HAS_TRANSPOSEUVWX8_DSPR2)
  196. if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 2) &&
  197. IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
  198. TransposeUVWx8 = TransposeUVWx8_DSPR2;
  199. }
  200. #endif
  201. // Work through the source in 8x8 tiles.
  202. while (i >= 8) {
  203. TransposeUVWx8(src, src_stride,
  204. dst_a, dst_stride_a,
  205. dst_b, dst_stride_b,
  206. width);
  207. src += 8 * src_stride; // Go down 8 rows.
  208. dst_a += 8; // Move over 8 columns.
  209. dst_b += 8; // Move over 8 columns.
  210. i -= 8;
  211. }
  212. if (i > 0) {
  213. TransposeUVWxH_C(src, src_stride,
  214. dst_a, dst_stride_a,
  215. dst_b, dst_stride_b,
  216. width, i);
  217. }
  218. }
  219. LIBYUV_API
  220. void RotateUV90(const uint8* src, int src_stride,
  221. uint8* dst_a, int dst_stride_a,
  222. uint8* dst_b, int dst_stride_b,
  223. int width, int height) {
  224. src += src_stride * (height - 1);
  225. src_stride = -src_stride;
  226. TransposeUV(src, src_stride,
  227. dst_a, dst_stride_a,
  228. dst_b, dst_stride_b,
  229. width, height);
  230. }
  231. LIBYUV_API
  232. void RotateUV270(const uint8* src, int src_stride,
  233. uint8* dst_a, int dst_stride_a,
  234. uint8* dst_b, int dst_stride_b,
  235. int width, int height) {
  236. dst_a += dst_stride_a * (width - 1);
  237. dst_b += dst_stride_b * (width - 1);
  238. dst_stride_a = -dst_stride_a;
  239. dst_stride_b = -dst_stride_b;
  240. TransposeUV(src, src_stride,
  241. dst_a, dst_stride_a,
  242. dst_b, dst_stride_b,
  243. width, height);
  244. }
  245. // Rotate 180 is a horizontal and vertical flip.
  246. LIBYUV_API
  247. void RotateUV180(const uint8* src, int src_stride,
  248. uint8* dst_a, int dst_stride_a,
  249. uint8* dst_b, int dst_stride_b,
  250. int width, int height) {
  251. int i;
  252. void (*MirrorUVRow)(const uint8* src, uint8* dst_u, uint8* dst_v, int width) =
  253. MirrorUVRow_C;
  254. #if defined(HAS_MIRRORUVROW_NEON)
  255. if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
  256. MirrorUVRow = MirrorUVRow_NEON;
  257. }
  258. #endif
  259. #if defined(HAS_MIRRORUVROW_SSSE3)
  260. if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
  261. MirrorUVRow = MirrorUVRow_SSSE3;
  262. }
  263. #endif
  264. #if defined(HAS_MIRRORUVROW_DSPR2)
  265. if (TestCpuFlag(kCpuHasDSPR2) &&
  266. IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
  267. MirrorUVRow = MirrorUVRow_DSPR2;
  268. }
  269. #endif
  270. dst_a += dst_stride_a * (height - 1);
  271. dst_b += dst_stride_b * (height - 1);
  272. for (i = 0; i < height; ++i) {
  273. MirrorUVRow(src, dst_a, dst_b, width);
  274. src += src_stride;
  275. dst_a -= dst_stride_a;
  276. dst_b -= dst_stride_b;
  277. }
  278. }
  279. LIBYUV_API
  280. int RotatePlane(const uint8* src, int src_stride,
  281. uint8* dst, int dst_stride,
  282. int width, int height,
  283. enum RotationMode mode) {
  284. if (!src || width <= 0 || height == 0 || !dst) {
  285. return -1;
  286. }
  287. // Negative height means invert the image.
  288. if (height < 0) {
  289. height = -height;
  290. src = src + (height - 1) * src_stride;
  291. src_stride = -src_stride;
  292. }
  293. switch (mode) {
  294. case kRotate0:
  295. // copy frame
  296. CopyPlane(src, src_stride,
  297. dst, dst_stride,
  298. width, height);
  299. return 0;
  300. case kRotate90:
  301. RotatePlane90(src, src_stride,
  302. dst, dst_stride,
  303. width, height);
  304. return 0;
  305. case kRotate270:
  306. RotatePlane270(src, src_stride,
  307. dst, dst_stride,
  308. width, height);
  309. return 0;
  310. case kRotate180:
  311. RotatePlane180(src, src_stride,
  312. dst, dst_stride,
  313. width, height);
  314. return 0;
  315. default:
  316. break;
  317. }
  318. return -1;
  319. }
  320. LIBYUV_API
  321. int I420Rotate(const uint8* src_y, int src_stride_y,
  322. const uint8* src_u, int src_stride_u,
  323. const uint8* src_v, int src_stride_v,
  324. uint8* dst_y, int dst_stride_y,
  325. uint8* dst_u, int dst_stride_u,
  326. uint8* dst_v, int dst_stride_v,
  327. int width, int height,
  328. enum RotationMode mode) {
  329. int halfwidth = (width + 1) >> 1;
  330. int halfheight = (height + 1) >> 1;
  331. if (!src_y || !src_u || !src_v || width <= 0 || height == 0 ||
  332. !dst_y || !dst_u || !dst_v) {
  333. return -1;
  334. }
  335. // Negative height means invert the image.
  336. if (height < 0) {
  337. height = -height;
  338. halfheight = (height + 1) >> 1;
  339. src_y = src_y + (height - 1) * src_stride_y;
  340. src_u = src_u + (halfheight - 1) * src_stride_u;
  341. src_v = src_v + (halfheight - 1) * src_stride_v;
  342. src_stride_y = -src_stride_y;
  343. src_stride_u = -src_stride_u;
  344. src_stride_v = -src_stride_v;
  345. }
  346. switch (mode) {
  347. case kRotate0:
  348. // copy frame
  349. return I420Copy(src_y, src_stride_y,
  350. src_u, src_stride_u,
  351. src_v, src_stride_v,
  352. dst_y, dst_stride_y,
  353. dst_u, dst_stride_u,
  354. dst_v, dst_stride_v,
  355. width, height);
  356. case kRotate90:
  357. RotatePlane90(src_y, src_stride_y,
  358. dst_y, dst_stride_y,
  359. width, height);
  360. RotatePlane90(src_u, src_stride_u,
  361. dst_u, dst_stride_u,
  362. halfwidth, halfheight);
  363. RotatePlane90(src_v, src_stride_v,
  364. dst_v, dst_stride_v,
  365. halfwidth, halfheight);
  366. return 0;
  367. case kRotate270:
  368. RotatePlane270(src_y, src_stride_y,
  369. dst_y, dst_stride_y,
  370. width, height);
  371. RotatePlane270(src_u, src_stride_u,
  372. dst_u, dst_stride_u,
  373. halfwidth, halfheight);
  374. RotatePlane270(src_v, src_stride_v,
  375. dst_v, dst_stride_v,
  376. halfwidth, halfheight);
  377. return 0;
  378. case kRotate180:
  379. RotatePlane180(src_y, src_stride_y,
  380. dst_y, dst_stride_y,
  381. width, height);
  382. RotatePlane180(src_u, src_stride_u,
  383. dst_u, dst_stride_u,
  384. halfwidth, halfheight);
  385. RotatePlane180(src_v, src_stride_v,
  386. dst_v, dst_stride_v,
  387. halfwidth, halfheight);
  388. return 0;
  389. default:
  390. break;
  391. }
  392. return -1;
  393. }
  394. LIBYUV_API
  395. int NV12ToI420Rotate(const uint8* src_y, int src_stride_y,
  396. const uint8* src_uv, int src_stride_uv,
  397. uint8* dst_y, int dst_stride_y,
  398. uint8* dst_u, int dst_stride_u,
  399. uint8* dst_v, int dst_stride_v,
  400. int width, int height,
  401. enum RotationMode mode) {
  402. int halfwidth = (width + 1) >> 1;
  403. int halfheight = (height + 1) >> 1;
  404. if (!src_y || !src_uv || width <= 0 || height == 0 ||
  405. !dst_y || !dst_u || !dst_v) {
  406. return -1;
  407. }
  408. // Negative height means invert the image.
  409. if (height < 0) {
  410. height = -height;
  411. halfheight = (height + 1) >> 1;
  412. src_y = src_y + (height - 1) * src_stride_y;
  413. src_uv = src_uv + (halfheight - 1) * src_stride_uv;
  414. src_stride_y = -src_stride_y;
  415. src_stride_uv = -src_stride_uv;
  416. }
  417. switch (mode) {
  418. case kRotate0:
  419. // copy frame
  420. return NV12ToI420(src_y, src_stride_y,
  421. src_uv, src_stride_uv,
  422. dst_y, dst_stride_y,
  423. dst_u, dst_stride_u,
  424. dst_v, dst_stride_v,
  425. width, height);
  426. case kRotate90:
  427. RotatePlane90(src_y, src_stride_y,
  428. dst_y, dst_stride_y,
  429. width, height);
  430. RotateUV90(src_uv, src_stride_uv,
  431. dst_u, dst_stride_u,
  432. dst_v, dst_stride_v,
  433. halfwidth, halfheight);
  434. return 0;
  435. case kRotate270:
  436. RotatePlane270(src_y, src_stride_y,
  437. dst_y, dst_stride_y,
  438. width, height);
  439. RotateUV270(src_uv, src_stride_uv,
  440. dst_u, dst_stride_u,
  441. dst_v, dst_stride_v,
  442. halfwidth, halfheight);
  443. return 0;
  444. case kRotate180:
  445. RotatePlane180(src_y, src_stride_y,
  446. dst_y, dst_stride_y,
  447. width, height);
  448. RotateUV180(src_uv, src_stride_uv,
  449. dst_u, dst_stride_u,
  450. dst_v, dst_stride_v,
  451. halfwidth, halfheight);
  452. return 0;
  453. default:
  454. break;
  455. }
  456. return -1;
  457. }
  458. #ifdef __cplusplus
  459. } // extern "C"
  460. } // namespace libyuv
  461. #endif