rotate.cc 16 KB

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