convert.cc 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390
  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/convert.h"
  11. #include "libyuv/basic_types.h"
  12. #include "libyuv/cpu_id.h"
  13. #include "libyuv/planar_functions.h"
  14. #include "libyuv/rotate.h"
  15. #include "libyuv/scale.h" // For ScalePlane()
  16. #include "libyuv/row.h"
  17. #ifdef __cplusplus
  18. namespace libyuv {
  19. extern "C" {
  20. #endif
  21. #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
  22. static __inline int Abs(int v) {
  23. return v >= 0 ? v : -v;
  24. }
  25. // Any I4xx To I420 format with mirroring.
  26. static int I4xxToI420(const uint8* src_y, int src_stride_y,
  27. const uint8* src_u, int src_stride_u,
  28. const uint8* src_v, int src_stride_v,
  29. uint8* dst_y, int dst_stride_y,
  30. uint8* dst_u, int dst_stride_u,
  31. uint8* dst_v, int dst_stride_v,
  32. int src_y_width, int src_y_height,
  33. int src_uv_width, int src_uv_height) {
  34. const int dst_y_width = Abs(src_y_width);
  35. const int dst_y_height = Abs(src_y_height);
  36. const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
  37. const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
  38. if (src_y_width == 0 || src_y_height == 0 ||
  39. src_uv_width == 0 || src_uv_height == 0) {
  40. return -1;
  41. }
  42. ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
  43. dst_y, dst_stride_y, dst_y_width, dst_y_height,
  44. kFilterBilinear);
  45. ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
  46. dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
  47. kFilterBilinear);
  48. ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
  49. dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
  50. kFilterBilinear);
  51. return 0;
  52. }
  53. // Copy I420 with optional flipping
  54. // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
  55. // is does row coalescing.
  56. LIBYUV_API
  57. int I420Copy(const uint8* src_y, int src_stride_y,
  58. const uint8* src_u, int src_stride_u,
  59. const uint8* src_v, int src_stride_v,
  60. uint8* dst_y, int dst_stride_y,
  61. uint8* dst_u, int dst_stride_u,
  62. uint8* dst_v, int dst_stride_v,
  63. int width, int height) {
  64. int halfwidth = (width + 1) >> 1;
  65. int halfheight = (height + 1) >> 1;
  66. if (!src_y || !src_u || !src_v ||
  67. !dst_y || !dst_u || !dst_v ||
  68. width <= 0 || height == 0) {
  69. return -1;
  70. }
  71. // Negative height means invert the image.
  72. if (height < 0) {
  73. height = -height;
  74. halfheight = (height + 1) >> 1;
  75. src_y = src_y + (height - 1) * src_stride_y;
  76. src_u = src_u + (halfheight - 1) * src_stride_u;
  77. src_v = src_v + (halfheight - 1) * src_stride_v;
  78. src_stride_y = -src_stride_y;
  79. src_stride_u = -src_stride_u;
  80. src_stride_v = -src_stride_v;
  81. }
  82. if (dst_y) {
  83. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  84. }
  85. // Copy UV planes.
  86. CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  87. CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  88. return 0;
  89. }
  90. // 422 chroma is 1/2 width, 1x height
  91. // 420 chroma is 1/2 width, 1/2 height
  92. LIBYUV_API
  93. int I422ToI420(const uint8* src_y, int src_stride_y,
  94. const uint8* src_u, int src_stride_u,
  95. const uint8* src_v, int src_stride_v,
  96. uint8* dst_y, int dst_stride_y,
  97. uint8* dst_u, int dst_stride_u,
  98. uint8* dst_v, int dst_stride_v,
  99. int width, int height) {
  100. const int src_uv_width = SUBSAMPLE(width, 1, 1);
  101. return I4xxToI420(src_y, src_stride_y,
  102. src_u, src_stride_u,
  103. src_v, src_stride_v,
  104. dst_y, dst_stride_y,
  105. dst_u, dst_stride_u,
  106. dst_v, dst_stride_v,
  107. width, height,
  108. src_uv_width, height);
  109. }
  110. // 444 chroma is 1x width, 1x height
  111. // 420 chroma is 1/2 width, 1/2 height
  112. LIBYUV_API
  113. int I444ToI420(const uint8* src_y, int src_stride_y,
  114. const uint8* src_u, int src_stride_u,
  115. const uint8* src_v, int src_stride_v,
  116. uint8* dst_y, int dst_stride_y,
  117. uint8* dst_u, int dst_stride_u,
  118. uint8* dst_v, int dst_stride_v,
  119. int width, int height) {
  120. return I4xxToI420(src_y, src_stride_y,
  121. src_u, src_stride_u,
  122. src_v, src_stride_v,
  123. dst_y, dst_stride_y,
  124. dst_u, dst_stride_u,
  125. dst_v, dst_stride_v,
  126. width, height,
  127. width, height);
  128. }
  129. // 411 chroma is 1/4 width, 1x height
  130. // 420 chroma is 1/2 width, 1/2 height
  131. LIBYUV_API
  132. int I411ToI420(const uint8* src_y, int src_stride_y,
  133. const uint8* src_u, int src_stride_u,
  134. const uint8* src_v, int src_stride_v,
  135. uint8* dst_y, int dst_stride_y,
  136. uint8* dst_u, int dst_stride_u,
  137. uint8* dst_v, int dst_stride_v,
  138. int width, int height) {
  139. const int src_uv_width = SUBSAMPLE(width, 3, 2);
  140. return I4xxToI420(src_y, src_stride_y,
  141. src_u, src_stride_u,
  142. src_v, src_stride_v,
  143. dst_y, dst_stride_y,
  144. dst_u, dst_stride_u,
  145. dst_v, dst_stride_v,
  146. width, height,
  147. src_uv_width, height);
  148. }
  149. // I400 is greyscale typically used in MJPG
  150. LIBYUV_API
  151. int I400ToI420(const uint8* src_y, int src_stride_y,
  152. uint8* dst_y, int dst_stride_y,
  153. uint8* dst_u, int dst_stride_u,
  154. uint8* dst_v, int dst_stride_v,
  155. int width, int height) {
  156. int halfwidth = (width + 1) >> 1;
  157. int halfheight = (height + 1) >> 1;
  158. if (!src_y || !dst_y || !dst_u || !dst_v ||
  159. width <= 0 || height == 0) {
  160. return -1;
  161. }
  162. // Negative height means invert the image.
  163. if (height < 0) {
  164. height = -height;
  165. halfheight = (height + 1) >> 1;
  166. src_y = src_y + (height - 1) * src_stride_y;
  167. src_stride_y = -src_stride_y;
  168. }
  169. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  170. SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
  171. SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
  172. return 0;
  173. }
  174. static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
  175. uint8* dst, int dst_stride,
  176. int width, int height) {
  177. int y;
  178. void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
  179. #if defined(HAS_COPYROW_SSE2)
  180. if (TestCpuFlag(kCpuHasSSE2)) {
  181. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
  182. }
  183. #endif
  184. #if defined(HAS_COPYROW_AVX)
  185. if (TestCpuFlag(kCpuHasAVX)) {
  186. CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
  187. }
  188. #endif
  189. #if defined(HAS_COPYROW_ERMS)
  190. if (TestCpuFlag(kCpuHasERMS)) {
  191. CopyRow = CopyRow_ERMS;
  192. }
  193. #endif
  194. #if defined(HAS_COPYROW_NEON)
  195. if (TestCpuFlag(kCpuHasNEON)) {
  196. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
  197. }
  198. #endif
  199. #if defined(HAS_COPYROW_MIPS)
  200. if (TestCpuFlag(kCpuHasMIPS)) {
  201. CopyRow = CopyRow_MIPS;
  202. }
  203. #endif
  204. // Copy plane
  205. for (y = 0; y < height - 1; y += 2) {
  206. CopyRow(src, dst, width);
  207. CopyRow(src + src_stride_0, dst + dst_stride, width);
  208. src += src_stride_0 + src_stride_1;
  209. dst += dst_stride * 2;
  210. }
  211. if (height & 1) {
  212. CopyRow(src, dst, width);
  213. }
  214. }
  215. // Support converting from FOURCC_M420
  216. // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
  217. // easy conversion to I420.
  218. // M420 format description:
  219. // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
  220. // Chroma is half width / half height. (420)
  221. // src_stride_m420 is row planar. Normally this will be the width in pixels.
  222. // The UV plane is half width, but 2 values, so src_stride_m420 applies to
  223. // this as well as the two Y planes.
  224. static int X420ToI420(const uint8* src_y,
  225. int src_stride_y0, int src_stride_y1,
  226. const uint8* src_uv, int src_stride_uv,
  227. uint8* dst_y, int dst_stride_y,
  228. uint8* dst_u, int dst_stride_u,
  229. uint8* dst_v, int dst_stride_v,
  230. int width, int height) {
  231. int y;
  232. int halfwidth = (width + 1) >> 1;
  233. int halfheight = (height + 1) >> 1;
  234. void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
  235. int width) = SplitUVRow_C;
  236. if (!src_y || !src_uv ||
  237. !dst_y || !dst_u || !dst_v ||
  238. width <= 0 || height == 0) {
  239. return -1;
  240. }
  241. // Negative height means invert the image.
  242. if (height < 0) {
  243. height = -height;
  244. halfheight = (height + 1) >> 1;
  245. dst_y = dst_y + (height - 1) * dst_stride_y;
  246. dst_u = dst_u + (halfheight - 1) * dst_stride_u;
  247. dst_v = dst_v + (halfheight - 1) * dst_stride_v;
  248. dst_stride_y = -dst_stride_y;
  249. dst_stride_u = -dst_stride_u;
  250. dst_stride_v = -dst_stride_v;
  251. }
  252. // Coalesce rows.
  253. if (src_stride_y0 == width &&
  254. src_stride_y1 == width &&
  255. dst_stride_y == width) {
  256. width *= height;
  257. height = 1;
  258. src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
  259. }
  260. // Coalesce rows.
  261. if (src_stride_uv == halfwidth * 2 &&
  262. dst_stride_u == halfwidth &&
  263. dst_stride_v == halfwidth) {
  264. halfwidth *= halfheight;
  265. halfheight = 1;
  266. src_stride_uv = dst_stride_u = dst_stride_v = 0;
  267. }
  268. #if defined(HAS_SPLITUVROW_SSE2)
  269. if (TestCpuFlag(kCpuHasSSE2)) {
  270. SplitUVRow = SplitUVRow_Any_SSE2;
  271. if (IS_ALIGNED(halfwidth, 16)) {
  272. SplitUVRow = SplitUVRow_SSE2;
  273. }
  274. }
  275. #endif
  276. #if defined(HAS_SPLITUVROW_AVX2)
  277. if (TestCpuFlag(kCpuHasAVX2)) {
  278. SplitUVRow = SplitUVRow_Any_AVX2;
  279. if (IS_ALIGNED(halfwidth, 32)) {
  280. SplitUVRow = SplitUVRow_AVX2;
  281. }
  282. }
  283. #endif
  284. #if defined(HAS_SPLITUVROW_NEON)
  285. if (TestCpuFlag(kCpuHasNEON)) {
  286. SplitUVRow = SplitUVRow_Any_NEON;
  287. if (IS_ALIGNED(halfwidth, 16)) {
  288. SplitUVRow = SplitUVRow_NEON;
  289. }
  290. }
  291. #endif
  292. #if defined(HAS_SPLITUVROW_DSPR2)
  293. if (TestCpuFlag(kCpuHasDSPR2) &&
  294. IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
  295. IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
  296. IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
  297. SplitUVRow = SplitUVRow_Any_DSPR2;
  298. if (IS_ALIGNED(halfwidth, 16)) {
  299. SplitUVRow = SplitUVRow_DSPR2;
  300. }
  301. }
  302. #endif
  303. if (dst_y) {
  304. if (src_stride_y0 == src_stride_y1) {
  305. CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
  306. } else {
  307. CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
  308. width, height);
  309. }
  310. }
  311. for (y = 0; y < halfheight; ++y) {
  312. // Copy a row of UV.
  313. SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
  314. dst_u += dst_stride_u;
  315. dst_v += dst_stride_v;
  316. src_uv += src_stride_uv;
  317. }
  318. return 0;
  319. }
  320. // Convert NV12 to I420.
  321. LIBYUV_API
  322. int NV12ToI420(const uint8* src_y, int src_stride_y,
  323. const uint8* src_uv, int src_stride_uv,
  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. return X420ToI420(src_y, src_stride_y, src_stride_y,
  329. src_uv, src_stride_uv,
  330. dst_y, dst_stride_y,
  331. dst_u, dst_stride_u,
  332. dst_v, dst_stride_v,
  333. width, height);
  334. }
  335. // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
  336. LIBYUV_API
  337. int NV21ToI420(const uint8* src_y, int src_stride_y,
  338. const uint8* src_vu, int src_stride_vu,
  339. uint8* dst_y, int dst_stride_y,
  340. uint8* dst_u, int dst_stride_u,
  341. uint8* dst_v, int dst_stride_v,
  342. int width, int height) {
  343. return X420ToI420(src_y, src_stride_y, src_stride_y,
  344. src_vu, src_stride_vu,
  345. dst_y, dst_stride_y,
  346. dst_v, dst_stride_v,
  347. dst_u, dst_stride_u,
  348. width, height);
  349. }
  350. // Convert M420 to I420.
  351. LIBYUV_API
  352. int M420ToI420(const uint8* src_m420, int src_stride_m420,
  353. uint8* dst_y, int dst_stride_y,
  354. uint8* dst_u, int dst_stride_u,
  355. uint8* dst_v, int dst_stride_v,
  356. int width, int height) {
  357. return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
  358. src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
  359. dst_y, dst_stride_y,
  360. dst_u, dst_stride_u,
  361. dst_v, dst_stride_v,
  362. width, height);
  363. }
  364. // Convert YUY2 to I420.
  365. LIBYUV_API
  366. int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
  367. uint8* dst_y, int dst_stride_y,
  368. uint8* dst_u, int dst_stride_u,
  369. uint8* dst_v, int dst_stride_v,
  370. int width, int height) {
  371. int y;
  372. void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
  373. uint8* dst_u, uint8* dst_v, int width) = YUY2ToUVRow_C;
  374. void (*YUY2ToYRow)(const uint8* src_yuy2,
  375. uint8* dst_y, int width) = YUY2ToYRow_C;
  376. // Negative height means invert the image.
  377. if (height < 0) {
  378. height = -height;
  379. src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
  380. src_stride_yuy2 = -src_stride_yuy2;
  381. }
  382. #if defined(HAS_YUY2TOYROW_SSE2)
  383. if (TestCpuFlag(kCpuHasSSE2)) {
  384. YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
  385. YUY2ToYRow = YUY2ToYRow_Any_SSE2;
  386. if (IS_ALIGNED(width, 16)) {
  387. YUY2ToUVRow = YUY2ToUVRow_SSE2;
  388. YUY2ToYRow = YUY2ToYRow_SSE2;
  389. }
  390. }
  391. #endif
  392. #if defined(HAS_YUY2TOYROW_AVX2)
  393. if (TestCpuFlag(kCpuHasAVX2)) {
  394. YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
  395. YUY2ToYRow = YUY2ToYRow_Any_AVX2;
  396. if (IS_ALIGNED(width, 32)) {
  397. YUY2ToUVRow = YUY2ToUVRow_AVX2;
  398. YUY2ToYRow = YUY2ToYRow_AVX2;
  399. }
  400. }
  401. #endif
  402. #if defined(HAS_YUY2TOYROW_NEON)
  403. if (TestCpuFlag(kCpuHasNEON)) {
  404. YUY2ToYRow = YUY2ToYRow_Any_NEON;
  405. YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
  406. if (IS_ALIGNED(width, 16)) {
  407. YUY2ToYRow = YUY2ToYRow_NEON;
  408. YUY2ToUVRow = YUY2ToUVRow_NEON;
  409. }
  410. }
  411. #endif
  412. for (y = 0; y < height - 1; y += 2) {
  413. YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
  414. YUY2ToYRow(src_yuy2, dst_y, width);
  415. YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
  416. src_yuy2 += src_stride_yuy2 * 2;
  417. dst_y += dst_stride_y * 2;
  418. dst_u += dst_stride_u;
  419. dst_v += dst_stride_v;
  420. }
  421. if (height & 1) {
  422. YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
  423. YUY2ToYRow(src_yuy2, dst_y, width);
  424. }
  425. return 0;
  426. }
  427. // Convert UYVY to I420.
  428. LIBYUV_API
  429. int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
  430. uint8* dst_y, int dst_stride_y,
  431. uint8* dst_u, int dst_stride_u,
  432. uint8* dst_v, int dst_stride_v,
  433. int width, int height) {
  434. int y;
  435. void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
  436. uint8* dst_u, uint8* dst_v, int width) = UYVYToUVRow_C;
  437. void (*UYVYToYRow)(const uint8* src_uyvy,
  438. uint8* dst_y, int width) = UYVYToYRow_C;
  439. // Negative height means invert the image.
  440. if (height < 0) {
  441. height = -height;
  442. src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
  443. src_stride_uyvy = -src_stride_uyvy;
  444. }
  445. #if defined(HAS_UYVYTOYROW_SSE2)
  446. if (TestCpuFlag(kCpuHasSSE2)) {
  447. UYVYToUVRow = UYVYToUVRow_Any_SSE2;
  448. UYVYToYRow = UYVYToYRow_Any_SSE2;
  449. if (IS_ALIGNED(width, 16)) {
  450. UYVYToUVRow = UYVYToUVRow_SSE2;
  451. UYVYToYRow = UYVYToYRow_SSE2;
  452. }
  453. }
  454. #endif
  455. #if defined(HAS_UYVYTOYROW_AVX2)
  456. if (TestCpuFlag(kCpuHasAVX2)) {
  457. UYVYToUVRow = UYVYToUVRow_Any_AVX2;
  458. UYVYToYRow = UYVYToYRow_Any_AVX2;
  459. if (IS_ALIGNED(width, 32)) {
  460. UYVYToUVRow = UYVYToUVRow_AVX2;
  461. UYVYToYRow = UYVYToYRow_AVX2;
  462. }
  463. }
  464. #endif
  465. #if defined(HAS_UYVYTOYROW_NEON)
  466. if (TestCpuFlag(kCpuHasNEON)) {
  467. UYVYToYRow = UYVYToYRow_Any_NEON;
  468. UYVYToUVRow = UYVYToUVRow_Any_NEON;
  469. if (IS_ALIGNED(width, 16)) {
  470. UYVYToYRow = UYVYToYRow_NEON;
  471. UYVYToUVRow = UYVYToUVRow_NEON;
  472. }
  473. }
  474. #endif
  475. for (y = 0; y < height - 1; y += 2) {
  476. UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
  477. UYVYToYRow(src_uyvy, dst_y, width);
  478. UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
  479. src_uyvy += src_stride_uyvy * 2;
  480. dst_y += dst_stride_y * 2;
  481. dst_u += dst_stride_u;
  482. dst_v += dst_stride_v;
  483. }
  484. if (height & 1) {
  485. UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
  486. UYVYToYRow(src_uyvy, dst_y, width);
  487. }
  488. return 0;
  489. }
  490. // Convert ARGB to I420.
  491. LIBYUV_API
  492. int ARGBToI420(const uint8* src_argb, int src_stride_argb,
  493. uint8* dst_y, int dst_stride_y,
  494. uint8* dst_u, int dst_stride_u,
  495. uint8* dst_v, int dst_stride_v,
  496. int width, int height) {
  497. int y;
  498. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  499. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  500. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  501. ARGBToYRow_C;
  502. if (!src_argb ||
  503. !dst_y || !dst_u || !dst_v ||
  504. width <= 0 || height == 0) {
  505. return -1;
  506. }
  507. // Negative height means invert the image.
  508. if (height < 0) {
  509. height = -height;
  510. src_argb = src_argb + (height - 1) * src_stride_argb;
  511. src_stride_argb = -src_stride_argb;
  512. }
  513. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  514. if (TestCpuFlag(kCpuHasSSSE3)) {
  515. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  516. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  517. if (IS_ALIGNED(width, 16)) {
  518. ARGBToUVRow = ARGBToUVRow_SSSE3;
  519. ARGBToYRow = ARGBToYRow_SSSE3;
  520. }
  521. }
  522. #endif
  523. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  524. if (TestCpuFlag(kCpuHasAVX2)) {
  525. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  526. ARGBToYRow = ARGBToYRow_Any_AVX2;
  527. if (IS_ALIGNED(width, 32)) {
  528. ARGBToUVRow = ARGBToUVRow_AVX2;
  529. ARGBToYRow = ARGBToYRow_AVX2;
  530. }
  531. }
  532. #endif
  533. #if defined(HAS_ARGBTOYROW_NEON)
  534. if (TestCpuFlag(kCpuHasNEON)) {
  535. ARGBToYRow = ARGBToYRow_Any_NEON;
  536. if (IS_ALIGNED(width, 8)) {
  537. ARGBToYRow = ARGBToYRow_NEON;
  538. }
  539. }
  540. #endif
  541. #if defined(HAS_ARGBTOUVROW_NEON)
  542. if (TestCpuFlag(kCpuHasNEON)) {
  543. ARGBToUVRow = ARGBToUVRow_Any_NEON;
  544. if (IS_ALIGNED(width, 16)) {
  545. ARGBToUVRow = ARGBToUVRow_NEON;
  546. }
  547. }
  548. #endif
  549. for (y = 0; y < height - 1; y += 2) {
  550. ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
  551. ARGBToYRow(src_argb, dst_y, width);
  552. ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
  553. src_argb += src_stride_argb * 2;
  554. dst_y += dst_stride_y * 2;
  555. dst_u += dst_stride_u;
  556. dst_v += dst_stride_v;
  557. }
  558. if (height & 1) {
  559. ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
  560. ARGBToYRow(src_argb, dst_y, width);
  561. }
  562. return 0;
  563. }
  564. // Convert BGRA to I420.
  565. LIBYUV_API
  566. int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
  567. uint8* dst_y, int dst_stride_y,
  568. uint8* dst_u, int dst_stride_u,
  569. uint8* dst_v, int dst_stride_v,
  570. int width, int height) {
  571. int y;
  572. void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
  573. uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
  574. void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) =
  575. BGRAToYRow_C;
  576. if (!src_bgra ||
  577. !dst_y || !dst_u || !dst_v ||
  578. width <= 0 || height == 0) {
  579. return -1;
  580. }
  581. // Negative height means invert the image.
  582. if (height < 0) {
  583. height = -height;
  584. src_bgra = src_bgra + (height - 1) * src_stride_bgra;
  585. src_stride_bgra = -src_stride_bgra;
  586. }
  587. #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
  588. if (TestCpuFlag(kCpuHasSSSE3)) {
  589. BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
  590. BGRAToYRow = BGRAToYRow_Any_SSSE3;
  591. if (IS_ALIGNED(width, 16)) {
  592. BGRAToUVRow = BGRAToUVRow_SSSE3;
  593. BGRAToYRow = BGRAToYRow_SSSE3;
  594. }
  595. }
  596. #endif
  597. #if defined(HAS_BGRATOYROW_NEON)
  598. if (TestCpuFlag(kCpuHasNEON)) {
  599. BGRAToYRow = BGRAToYRow_Any_NEON;
  600. if (IS_ALIGNED(width, 8)) {
  601. BGRAToYRow = BGRAToYRow_NEON;
  602. }
  603. }
  604. #endif
  605. #if defined(HAS_BGRATOUVROW_NEON)
  606. if (TestCpuFlag(kCpuHasNEON)) {
  607. BGRAToUVRow = BGRAToUVRow_Any_NEON;
  608. if (IS_ALIGNED(width, 16)) {
  609. BGRAToUVRow = BGRAToUVRow_NEON;
  610. }
  611. }
  612. #endif
  613. for (y = 0; y < height - 1; y += 2) {
  614. BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
  615. BGRAToYRow(src_bgra, dst_y, width);
  616. BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
  617. src_bgra += src_stride_bgra * 2;
  618. dst_y += dst_stride_y * 2;
  619. dst_u += dst_stride_u;
  620. dst_v += dst_stride_v;
  621. }
  622. if (height & 1) {
  623. BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
  624. BGRAToYRow(src_bgra, dst_y, width);
  625. }
  626. return 0;
  627. }
  628. // Convert ABGR to I420.
  629. LIBYUV_API
  630. int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
  631. uint8* dst_y, int dst_stride_y,
  632. uint8* dst_u, int dst_stride_u,
  633. uint8* dst_v, int dst_stride_v,
  634. int width, int height) {
  635. int y;
  636. void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
  637. uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
  638. void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) =
  639. ABGRToYRow_C;
  640. if (!src_abgr ||
  641. !dst_y || !dst_u || !dst_v ||
  642. width <= 0 || height == 0) {
  643. return -1;
  644. }
  645. // Negative height means invert the image.
  646. if (height < 0) {
  647. height = -height;
  648. src_abgr = src_abgr + (height - 1) * src_stride_abgr;
  649. src_stride_abgr = -src_stride_abgr;
  650. }
  651. #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
  652. if (TestCpuFlag(kCpuHasSSSE3)) {
  653. ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
  654. ABGRToYRow = ABGRToYRow_Any_SSSE3;
  655. if (IS_ALIGNED(width, 16)) {
  656. ABGRToUVRow = ABGRToUVRow_SSSE3;
  657. ABGRToYRow = ABGRToYRow_SSSE3;
  658. }
  659. }
  660. #endif
  661. #if defined(HAS_ABGRTOYROW_NEON)
  662. if (TestCpuFlag(kCpuHasNEON)) {
  663. ABGRToYRow = ABGRToYRow_Any_NEON;
  664. if (IS_ALIGNED(width, 8)) {
  665. ABGRToYRow = ABGRToYRow_NEON;
  666. }
  667. }
  668. #endif
  669. #if defined(HAS_ABGRTOUVROW_NEON)
  670. if (TestCpuFlag(kCpuHasNEON)) {
  671. ABGRToUVRow = ABGRToUVRow_Any_NEON;
  672. if (IS_ALIGNED(width, 16)) {
  673. ABGRToUVRow = ABGRToUVRow_NEON;
  674. }
  675. }
  676. #endif
  677. for (y = 0; y < height - 1; y += 2) {
  678. ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
  679. ABGRToYRow(src_abgr, dst_y, width);
  680. ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
  681. src_abgr += src_stride_abgr * 2;
  682. dst_y += dst_stride_y * 2;
  683. dst_u += dst_stride_u;
  684. dst_v += dst_stride_v;
  685. }
  686. if (height & 1) {
  687. ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
  688. ABGRToYRow(src_abgr, dst_y, width);
  689. }
  690. return 0;
  691. }
  692. // Convert RGBA to I420.
  693. LIBYUV_API
  694. int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
  695. uint8* dst_y, int dst_stride_y,
  696. uint8* dst_u, int dst_stride_u,
  697. uint8* dst_v, int dst_stride_v,
  698. int width, int height) {
  699. int y;
  700. void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
  701. uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
  702. void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) =
  703. RGBAToYRow_C;
  704. if (!src_rgba ||
  705. !dst_y || !dst_u || !dst_v ||
  706. width <= 0 || height == 0) {
  707. return -1;
  708. }
  709. // Negative height means invert the image.
  710. if (height < 0) {
  711. height = -height;
  712. src_rgba = src_rgba + (height - 1) * src_stride_rgba;
  713. src_stride_rgba = -src_stride_rgba;
  714. }
  715. #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
  716. if (TestCpuFlag(kCpuHasSSSE3)) {
  717. RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
  718. RGBAToYRow = RGBAToYRow_Any_SSSE3;
  719. if (IS_ALIGNED(width, 16)) {
  720. RGBAToUVRow = RGBAToUVRow_SSSE3;
  721. RGBAToYRow = RGBAToYRow_SSSE3;
  722. }
  723. }
  724. #endif
  725. #if defined(HAS_RGBATOYROW_NEON)
  726. if (TestCpuFlag(kCpuHasNEON)) {
  727. RGBAToYRow = RGBAToYRow_Any_NEON;
  728. if (IS_ALIGNED(width, 8)) {
  729. RGBAToYRow = RGBAToYRow_NEON;
  730. }
  731. }
  732. #endif
  733. #if defined(HAS_RGBATOUVROW_NEON)
  734. if (TestCpuFlag(kCpuHasNEON)) {
  735. RGBAToUVRow = RGBAToUVRow_Any_NEON;
  736. if (IS_ALIGNED(width, 16)) {
  737. RGBAToUVRow = RGBAToUVRow_NEON;
  738. }
  739. }
  740. #endif
  741. for (y = 0; y < height - 1; y += 2) {
  742. RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
  743. RGBAToYRow(src_rgba, dst_y, width);
  744. RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
  745. src_rgba += src_stride_rgba * 2;
  746. dst_y += dst_stride_y * 2;
  747. dst_u += dst_stride_u;
  748. dst_v += dst_stride_v;
  749. }
  750. if (height & 1) {
  751. RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
  752. RGBAToYRow(src_rgba, dst_y, width);
  753. }
  754. return 0;
  755. }
  756. // Convert RGB24 to I420.
  757. LIBYUV_API
  758. int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
  759. uint8* dst_y, int dst_stride_y,
  760. uint8* dst_u, int dst_stride_u,
  761. uint8* dst_v, int dst_stride_v,
  762. int width, int height) {
  763. int y;
  764. #if defined(HAS_RGB24TOYROW_NEON)
  765. void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
  766. uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
  767. void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int width) =
  768. RGB24ToYRow_C;
  769. #else
  770. void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
  771. RGB24ToARGBRow_C;
  772. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  773. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  774. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  775. ARGBToYRow_C;
  776. #endif
  777. if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
  778. width <= 0 || height == 0) {
  779. return -1;
  780. }
  781. // Negative height means invert the image.
  782. if (height < 0) {
  783. height = -height;
  784. src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
  785. src_stride_rgb24 = -src_stride_rgb24;
  786. }
  787. // Neon version does direct RGB24 to YUV.
  788. #if defined(HAS_RGB24TOYROW_NEON)
  789. if (TestCpuFlag(kCpuHasNEON)) {
  790. RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
  791. RGB24ToYRow = RGB24ToYRow_Any_NEON;
  792. if (IS_ALIGNED(width, 8)) {
  793. RGB24ToYRow = RGB24ToYRow_NEON;
  794. if (IS_ALIGNED(width, 16)) {
  795. RGB24ToUVRow = RGB24ToUVRow_NEON;
  796. }
  797. }
  798. }
  799. // Other platforms do intermediate conversion from RGB24 to ARGB.
  800. #else
  801. #if defined(HAS_RGB24TOARGBROW_SSSE3)
  802. if (TestCpuFlag(kCpuHasSSSE3)) {
  803. RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
  804. if (IS_ALIGNED(width, 16)) {
  805. RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
  806. }
  807. }
  808. #endif
  809. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  810. if (TestCpuFlag(kCpuHasSSSE3)) {
  811. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  812. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  813. if (IS_ALIGNED(width, 16)) {
  814. ARGBToUVRow = ARGBToUVRow_SSSE3;
  815. ARGBToYRow = ARGBToYRow_SSSE3;
  816. }
  817. }
  818. #endif
  819. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  820. if (TestCpuFlag(kCpuHasAVX2)) {
  821. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  822. ARGBToYRow = ARGBToYRow_Any_AVX2;
  823. if (IS_ALIGNED(width, 32)) {
  824. ARGBToUVRow = ARGBToUVRow_AVX2;
  825. ARGBToYRow = ARGBToYRow_AVX2;
  826. }
  827. }
  828. #endif
  829. {
  830. // Allocate 2 rows of ARGB.
  831. const int kRowSize = (width * 4 + 31) & ~31;
  832. align_buffer_64(row, kRowSize * 2);
  833. #endif
  834. for (y = 0; y < height - 1; y += 2) {
  835. #if defined(HAS_RGB24TOYROW_NEON)
  836. RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
  837. RGB24ToYRow(src_rgb24, dst_y, width);
  838. RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
  839. #else
  840. RGB24ToARGBRow(src_rgb24, row, width);
  841. RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
  842. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  843. ARGBToYRow(row, dst_y, width);
  844. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  845. #endif
  846. src_rgb24 += src_stride_rgb24 * 2;
  847. dst_y += dst_stride_y * 2;
  848. dst_u += dst_stride_u;
  849. dst_v += dst_stride_v;
  850. }
  851. if (height & 1) {
  852. #if defined(HAS_RGB24TOYROW_NEON)
  853. RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
  854. RGB24ToYRow(src_rgb24, dst_y, width);
  855. #else
  856. RGB24ToARGBRow(src_rgb24, row, width);
  857. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  858. ARGBToYRow(row, dst_y, width);
  859. #endif
  860. }
  861. #if !defined(HAS_RGB24TOYROW_NEON)
  862. free_aligned_buffer_64(row);
  863. }
  864. #endif
  865. return 0;
  866. }
  867. // Convert RAW to I420.
  868. LIBYUV_API
  869. int RAWToI420(const uint8* src_raw, int src_stride_raw,
  870. uint8* dst_y, int dst_stride_y,
  871. uint8* dst_u, int dst_stride_u,
  872. uint8* dst_v, int dst_stride_v,
  873. int width, int height) {
  874. int y;
  875. #if defined(HAS_RAWTOYROW_NEON)
  876. void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
  877. uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
  878. void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) =
  879. RAWToYRow_C;
  880. #else
  881. void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
  882. RAWToARGBRow_C;
  883. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  884. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  885. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  886. ARGBToYRow_C;
  887. #endif
  888. if (!src_raw || !dst_y || !dst_u || !dst_v ||
  889. width <= 0 || height == 0) {
  890. return -1;
  891. }
  892. // Negative height means invert the image.
  893. if (height < 0) {
  894. height = -height;
  895. src_raw = src_raw + (height - 1) * src_stride_raw;
  896. src_stride_raw = -src_stride_raw;
  897. }
  898. // Neon version does direct RAW to YUV.
  899. #if defined(HAS_RAWTOYROW_NEON)
  900. if (TestCpuFlag(kCpuHasNEON)) {
  901. RAWToUVRow = RAWToUVRow_Any_NEON;
  902. RAWToYRow = RAWToYRow_Any_NEON;
  903. if (IS_ALIGNED(width, 8)) {
  904. RAWToYRow = RAWToYRow_NEON;
  905. if (IS_ALIGNED(width, 16)) {
  906. RAWToUVRow = RAWToUVRow_NEON;
  907. }
  908. }
  909. }
  910. // Other platforms do intermediate conversion from RAW to ARGB.
  911. #else
  912. #if defined(HAS_RAWTOARGBROW_SSSE3)
  913. if (TestCpuFlag(kCpuHasSSSE3)) {
  914. RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
  915. if (IS_ALIGNED(width, 16)) {
  916. RAWToARGBRow = RAWToARGBRow_SSSE3;
  917. }
  918. }
  919. #endif
  920. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  921. if (TestCpuFlag(kCpuHasSSSE3)) {
  922. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  923. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  924. if (IS_ALIGNED(width, 16)) {
  925. ARGBToUVRow = ARGBToUVRow_SSSE3;
  926. ARGBToYRow = ARGBToYRow_SSSE3;
  927. }
  928. }
  929. #endif
  930. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  931. if (TestCpuFlag(kCpuHasAVX2)) {
  932. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  933. ARGBToYRow = ARGBToYRow_Any_AVX2;
  934. if (IS_ALIGNED(width, 32)) {
  935. ARGBToUVRow = ARGBToUVRow_AVX2;
  936. ARGBToYRow = ARGBToYRow_AVX2;
  937. }
  938. }
  939. #endif
  940. {
  941. // Allocate 2 rows of ARGB.
  942. const int kRowSize = (width * 4 + 31) & ~31;
  943. align_buffer_64(row, kRowSize * 2);
  944. #endif
  945. for (y = 0; y < height - 1; y += 2) {
  946. #if defined(HAS_RAWTOYROW_NEON)
  947. RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
  948. RAWToYRow(src_raw, dst_y, width);
  949. RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
  950. #else
  951. RAWToARGBRow(src_raw, row, width);
  952. RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
  953. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  954. ARGBToYRow(row, dst_y, width);
  955. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  956. #endif
  957. src_raw += src_stride_raw * 2;
  958. dst_y += dst_stride_y * 2;
  959. dst_u += dst_stride_u;
  960. dst_v += dst_stride_v;
  961. }
  962. if (height & 1) {
  963. #if defined(HAS_RAWTOYROW_NEON)
  964. RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
  965. RAWToYRow(src_raw, dst_y, width);
  966. #else
  967. RAWToARGBRow(src_raw, row, width);
  968. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  969. ARGBToYRow(row, dst_y, width);
  970. #endif
  971. }
  972. #if !defined(HAS_RAWTOYROW_NEON)
  973. free_aligned_buffer_64(row);
  974. }
  975. #endif
  976. return 0;
  977. }
  978. // Convert RGB565 to I420.
  979. LIBYUV_API
  980. int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
  981. uint8* dst_y, int dst_stride_y,
  982. uint8* dst_u, int dst_stride_u,
  983. uint8* dst_v, int dst_stride_v,
  984. int width, int height) {
  985. int y;
  986. #if defined(HAS_RGB565TOYROW_NEON)
  987. void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
  988. uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
  989. void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) =
  990. RGB565ToYRow_C;
  991. #else
  992. void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
  993. RGB565ToARGBRow_C;
  994. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  995. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  996. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  997. ARGBToYRow_C;
  998. #endif
  999. if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
  1000. width <= 0 || height == 0) {
  1001. return -1;
  1002. }
  1003. // Negative height means invert the image.
  1004. if (height < 0) {
  1005. height = -height;
  1006. src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
  1007. src_stride_rgb565 = -src_stride_rgb565;
  1008. }
  1009. // Neon version does direct RGB565 to YUV.
  1010. #if defined(HAS_RGB565TOYROW_NEON)
  1011. if (TestCpuFlag(kCpuHasNEON)) {
  1012. RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
  1013. RGB565ToYRow = RGB565ToYRow_Any_NEON;
  1014. if (IS_ALIGNED(width, 8)) {
  1015. RGB565ToYRow = RGB565ToYRow_NEON;
  1016. if (IS_ALIGNED(width, 16)) {
  1017. RGB565ToUVRow = RGB565ToUVRow_NEON;
  1018. }
  1019. }
  1020. }
  1021. // Other platforms do intermediate conversion from RGB565 to ARGB.
  1022. #else
  1023. #if defined(HAS_RGB565TOARGBROW_SSE2)
  1024. if (TestCpuFlag(kCpuHasSSE2)) {
  1025. RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
  1026. if (IS_ALIGNED(width, 8)) {
  1027. RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
  1028. }
  1029. }
  1030. #endif
  1031. #if defined(HAS_RGB565TOARGBROW_AVX2)
  1032. if (TestCpuFlag(kCpuHasAVX2)) {
  1033. RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
  1034. if (IS_ALIGNED(width, 16)) {
  1035. RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
  1036. }
  1037. }
  1038. #endif
  1039. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1040. if (TestCpuFlag(kCpuHasSSSE3)) {
  1041. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1042. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1043. if (IS_ALIGNED(width, 16)) {
  1044. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1045. ARGBToYRow = ARGBToYRow_SSSE3;
  1046. }
  1047. }
  1048. #endif
  1049. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1050. if (TestCpuFlag(kCpuHasAVX2)) {
  1051. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1052. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1053. if (IS_ALIGNED(width, 32)) {
  1054. ARGBToUVRow = ARGBToUVRow_AVX2;
  1055. ARGBToYRow = ARGBToYRow_AVX2;
  1056. }
  1057. }
  1058. #endif
  1059. {
  1060. // Allocate 2 rows of ARGB.
  1061. const int kRowSize = (width * 4 + 31) & ~31;
  1062. align_buffer_64(row, kRowSize * 2);
  1063. #endif
  1064. for (y = 0; y < height - 1; y += 2) {
  1065. #if defined(HAS_RGB565TOYROW_NEON)
  1066. RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
  1067. RGB565ToYRow(src_rgb565, dst_y, width);
  1068. RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
  1069. #else
  1070. RGB565ToARGBRow(src_rgb565, row, width);
  1071. RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
  1072. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1073. ARGBToYRow(row, dst_y, width);
  1074. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1075. #endif
  1076. src_rgb565 += src_stride_rgb565 * 2;
  1077. dst_y += dst_stride_y * 2;
  1078. dst_u += dst_stride_u;
  1079. dst_v += dst_stride_v;
  1080. }
  1081. if (height & 1) {
  1082. #if defined(HAS_RGB565TOYROW_NEON)
  1083. RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
  1084. RGB565ToYRow(src_rgb565, dst_y, width);
  1085. #else
  1086. RGB565ToARGBRow(src_rgb565, row, width);
  1087. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1088. ARGBToYRow(row, dst_y, width);
  1089. #endif
  1090. }
  1091. #if !defined(HAS_RGB565TOYROW_NEON)
  1092. free_aligned_buffer_64(row);
  1093. }
  1094. #endif
  1095. return 0;
  1096. }
  1097. // Convert ARGB1555 to I420.
  1098. LIBYUV_API
  1099. int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
  1100. uint8* dst_y, int dst_stride_y,
  1101. uint8* dst_u, int dst_stride_u,
  1102. uint8* dst_v, int dst_stride_v,
  1103. int width, int height) {
  1104. int y;
  1105. #if defined(HAS_ARGB1555TOYROW_NEON)
  1106. void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
  1107. uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
  1108. void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) =
  1109. ARGB1555ToYRow_C;
  1110. #else
  1111. void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
  1112. ARGB1555ToARGBRow_C;
  1113. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1114. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1115. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  1116. ARGBToYRow_C;
  1117. #endif
  1118. if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
  1119. width <= 0 || height == 0) {
  1120. return -1;
  1121. }
  1122. // Negative height means invert the image.
  1123. if (height < 0) {
  1124. height = -height;
  1125. src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
  1126. src_stride_argb1555 = -src_stride_argb1555;
  1127. }
  1128. // Neon version does direct ARGB1555 to YUV.
  1129. #if defined(HAS_ARGB1555TOYROW_NEON)
  1130. if (TestCpuFlag(kCpuHasNEON)) {
  1131. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
  1132. ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
  1133. if (IS_ALIGNED(width, 8)) {
  1134. ARGB1555ToYRow = ARGB1555ToYRow_NEON;
  1135. if (IS_ALIGNED(width, 16)) {
  1136. ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
  1137. }
  1138. }
  1139. }
  1140. // Other platforms do intermediate conversion from ARGB1555 to ARGB.
  1141. #else
  1142. #if defined(HAS_ARGB1555TOARGBROW_SSE2)
  1143. if (TestCpuFlag(kCpuHasSSE2)) {
  1144. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
  1145. if (IS_ALIGNED(width, 8)) {
  1146. ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
  1147. }
  1148. }
  1149. #endif
  1150. #if defined(HAS_ARGB1555TOARGBROW_AVX2)
  1151. if (TestCpuFlag(kCpuHasAVX2)) {
  1152. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
  1153. if (IS_ALIGNED(width, 16)) {
  1154. ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
  1155. }
  1156. }
  1157. #endif
  1158. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1159. if (TestCpuFlag(kCpuHasSSSE3)) {
  1160. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1161. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1162. if (IS_ALIGNED(width, 16)) {
  1163. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1164. ARGBToYRow = ARGBToYRow_SSSE3;
  1165. }
  1166. }
  1167. #endif
  1168. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1169. if (TestCpuFlag(kCpuHasAVX2)) {
  1170. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1171. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1172. if (IS_ALIGNED(width, 32)) {
  1173. ARGBToUVRow = ARGBToUVRow_AVX2;
  1174. ARGBToYRow = ARGBToYRow_AVX2;
  1175. }
  1176. }
  1177. #endif
  1178. {
  1179. // Allocate 2 rows of ARGB.
  1180. const int kRowSize = (width * 4 + 31) & ~31;
  1181. align_buffer_64(row, kRowSize * 2);
  1182. #endif
  1183. for (y = 0; y < height - 1; y += 2) {
  1184. #if defined(HAS_ARGB1555TOYROW_NEON)
  1185. ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
  1186. ARGB1555ToYRow(src_argb1555, dst_y, width);
  1187. ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
  1188. width);
  1189. #else
  1190. ARGB1555ToARGBRow(src_argb1555, row, width);
  1191. ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
  1192. width);
  1193. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1194. ARGBToYRow(row, dst_y, width);
  1195. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1196. #endif
  1197. src_argb1555 += src_stride_argb1555 * 2;
  1198. dst_y += dst_stride_y * 2;
  1199. dst_u += dst_stride_u;
  1200. dst_v += dst_stride_v;
  1201. }
  1202. if (height & 1) {
  1203. #if defined(HAS_ARGB1555TOYROW_NEON)
  1204. ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
  1205. ARGB1555ToYRow(src_argb1555, dst_y, width);
  1206. #else
  1207. ARGB1555ToARGBRow(src_argb1555, row, width);
  1208. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1209. ARGBToYRow(row, dst_y, width);
  1210. #endif
  1211. }
  1212. #if !defined(HAS_ARGB1555TOYROW_NEON)
  1213. free_aligned_buffer_64(row);
  1214. }
  1215. #endif
  1216. return 0;
  1217. }
  1218. // Convert ARGB4444 to I420.
  1219. LIBYUV_API
  1220. int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
  1221. uint8* dst_y, int dst_stride_y,
  1222. uint8* dst_u, int dst_stride_u,
  1223. uint8* dst_v, int dst_stride_v,
  1224. int width, int height) {
  1225. int y;
  1226. #if defined(HAS_ARGB4444TOYROW_NEON)
  1227. void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
  1228. uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
  1229. void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) =
  1230. ARGB4444ToYRow_C;
  1231. #else
  1232. void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
  1233. ARGB4444ToARGBRow_C;
  1234. void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1235. uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1236. void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
  1237. ARGBToYRow_C;
  1238. #endif
  1239. if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
  1240. width <= 0 || height == 0) {
  1241. return -1;
  1242. }
  1243. // Negative height means invert the image.
  1244. if (height < 0) {
  1245. height = -height;
  1246. src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
  1247. src_stride_argb4444 = -src_stride_argb4444;
  1248. }
  1249. // Neon version does direct ARGB4444 to YUV.
  1250. #if defined(HAS_ARGB4444TOYROW_NEON)
  1251. if (TestCpuFlag(kCpuHasNEON)) {
  1252. ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
  1253. ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
  1254. if (IS_ALIGNED(width, 8)) {
  1255. ARGB4444ToYRow = ARGB4444ToYRow_NEON;
  1256. if (IS_ALIGNED(width, 16)) {
  1257. ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
  1258. }
  1259. }
  1260. }
  1261. // Other platforms do intermediate conversion from ARGB4444 to ARGB.
  1262. #else
  1263. #if defined(HAS_ARGB4444TOARGBROW_SSE2)
  1264. if (TestCpuFlag(kCpuHasSSE2)) {
  1265. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
  1266. if (IS_ALIGNED(width, 8)) {
  1267. ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
  1268. }
  1269. }
  1270. #endif
  1271. #if defined(HAS_ARGB4444TOARGBROW_AVX2)
  1272. if (TestCpuFlag(kCpuHasAVX2)) {
  1273. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
  1274. if (IS_ALIGNED(width, 16)) {
  1275. ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
  1276. }
  1277. }
  1278. #endif
  1279. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1280. if (TestCpuFlag(kCpuHasSSSE3)) {
  1281. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1282. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1283. if (IS_ALIGNED(width, 16)) {
  1284. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1285. ARGBToYRow = ARGBToYRow_SSSE3;
  1286. }
  1287. }
  1288. #endif
  1289. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1290. if (TestCpuFlag(kCpuHasAVX2)) {
  1291. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1292. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1293. if (IS_ALIGNED(width, 32)) {
  1294. ARGBToUVRow = ARGBToUVRow_AVX2;
  1295. ARGBToYRow = ARGBToYRow_AVX2;
  1296. }
  1297. }
  1298. #endif
  1299. {
  1300. // Allocate 2 rows of ARGB.
  1301. const int kRowSize = (width * 4 + 31) & ~31;
  1302. align_buffer_64(row, kRowSize * 2);
  1303. #endif
  1304. for (y = 0; y < height - 1; y += 2) {
  1305. #if defined(HAS_ARGB4444TOYROW_NEON)
  1306. ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
  1307. ARGB4444ToYRow(src_argb4444, dst_y, width);
  1308. ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
  1309. width);
  1310. #else
  1311. ARGB4444ToARGBRow(src_argb4444, row, width);
  1312. ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
  1313. width);
  1314. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1315. ARGBToYRow(row, dst_y, width);
  1316. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1317. #endif
  1318. src_argb4444 += src_stride_argb4444 * 2;
  1319. dst_y += dst_stride_y * 2;
  1320. dst_u += dst_stride_u;
  1321. dst_v += dst_stride_v;
  1322. }
  1323. if (height & 1) {
  1324. #if defined(HAS_ARGB4444TOYROW_NEON)
  1325. ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
  1326. ARGB4444ToYRow(src_argb4444, dst_y, width);
  1327. #else
  1328. ARGB4444ToARGBRow(src_argb4444, row, width);
  1329. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1330. ARGBToYRow(row, dst_y, width);
  1331. #endif
  1332. }
  1333. #if !defined(HAS_ARGB4444TOYROW_NEON)
  1334. free_aligned_buffer_64(row);
  1335. }
  1336. #endif
  1337. return 0;
  1338. }
  1339. #ifdef __cplusplus
  1340. } // extern "C"
  1341. } // namespace libyuv
  1342. #endif