convert.cc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  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/row.h"
  16. #include "libyuv/scale.h" // For ScalePlane()
  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_t* src_y,
  27. int src_stride_y,
  28. const uint8_t* src_u,
  29. int src_stride_u,
  30. const uint8_t* src_v,
  31. int src_stride_v,
  32. uint8_t* dst_y,
  33. int dst_stride_y,
  34. uint8_t* dst_u,
  35. int dst_stride_u,
  36. uint8_t* dst_v,
  37. int dst_stride_v,
  38. int src_y_width,
  39. int src_y_height,
  40. int src_uv_width,
  41. int src_uv_height) {
  42. const int dst_y_width = Abs(src_y_width);
  43. const int dst_y_height = Abs(src_y_height);
  44. const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
  45. const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
  46. if (src_uv_width == 0 || src_uv_height == 0) {
  47. return -1;
  48. }
  49. if (dst_y) {
  50. ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
  51. dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
  52. }
  53. ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
  54. dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
  55. ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
  56. dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
  57. return 0;
  58. }
  59. // Copy I420 with optional flipping.
  60. // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
  61. // is does row coalescing.
  62. LIBYUV_API
  63. int I420Copy(const uint8_t* src_y,
  64. int src_stride_y,
  65. const uint8_t* src_u,
  66. int src_stride_u,
  67. const uint8_t* src_v,
  68. int src_stride_v,
  69. uint8_t* dst_y,
  70. int dst_stride_y,
  71. uint8_t* dst_u,
  72. int dst_stride_u,
  73. uint8_t* dst_v,
  74. int dst_stride_v,
  75. int width,
  76. int height) {
  77. int halfwidth = (width + 1) >> 1;
  78. int halfheight = (height + 1) >> 1;
  79. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  80. return -1;
  81. }
  82. // Negative height means invert the image.
  83. if (height < 0) {
  84. height = -height;
  85. halfheight = (height + 1) >> 1;
  86. src_y = src_y + (height - 1) * src_stride_y;
  87. src_u = src_u + (halfheight - 1) * src_stride_u;
  88. src_v = src_v + (halfheight - 1) * src_stride_v;
  89. src_stride_y = -src_stride_y;
  90. src_stride_u = -src_stride_u;
  91. src_stride_v = -src_stride_v;
  92. }
  93. if (dst_y) {
  94. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  95. }
  96. // Copy UV planes.
  97. CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  98. CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  99. return 0;
  100. }
  101. // Copy I010 with optional flipping.
  102. LIBYUV_API
  103. int I010Copy(const uint16_t* src_y,
  104. int src_stride_y,
  105. const uint16_t* src_u,
  106. int src_stride_u,
  107. const uint16_t* src_v,
  108. int src_stride_v,
  109. uint16_t* dst_y,
  110. int dst_stride_y,
  111. uint16_t* dst_u,
  112. int dst_stride_u,
  113. uint16_t* dst_v,
  114. int dst_stride_v,
  115. int width,
  116. int height) {
  117. int halfwidth = (width + 1) >> 1;
  118. int halfheight = (height + 1) >> 1;
  119. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  120. return -1;
  121. }
  122. // Negative height means invert the image.
  123. if (height < 0) {
  124. height = -height;
  125. halfheight = (height + 1) >> 1;
  126. src_y = src_y + (height - 1) * src_stride_y;
  127. src_u = src_u + (halfheight - 1) * src_stride_u;
  128. src_v = src_v + (halfheight - 1) * src_stride_v;
  129. src_stride_y = -src_stride_y;
  130. src_stride_u = -src_stride_u;
  131. src_stride_v = -src_stride_v;
  132. }
  133. if (dst_y) {
  134. CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  135. }
  136. // Copy UV planes.
  137. CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  138. CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  139. return 0;
  140. }
  141. // Convert 10 bit YUV to 8 bit.
  142. LIBYUV_API
  143. int I010ToI420(const uint16_t* src_y,
  144. int src_stride_y,
  145. const uint16_t* src_u,
  146. int src_stride_u,
  147. const uint16_t* src_v,
  148. int src_stride_v,
  149. uint8_t* dst_y,
  150. int dst_stride_y,
  151. uint8_t* dst_u,
  152. int dst_stride_u,
  153. uint8_t* dst_v,
  154. int dst_stride_v,
  155. int width,
  156. int height) {
  157. int halfwidth = (width + 1) >> 1;
  158. int halfheight = (height + 1) >> 1;
  159. if (!src_u || !src_v || !dst_u || !dst_v || 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_u = src_u + (halfheight - 1) * src_stride_u;
  168. src_v = src_v + (halfheight - 1) * src_stride_v;
  169. src_stride_y = -src_stride_y;
  170. src_stride_u = -src_stride_u;
  171. src_stride_v = -src_stride_v;
  172. }
  173. // Convert Y plane.
  174. Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width,
  175. height);
  176. // Convert UV planes.
  177. Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth,
  178. halfheight);
  179. Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth,
  180. halfheight);
  181. return 0;
  182. }
  183. // 422 chroma is 1/2 width, 1x height
  184. // 420 chroma is 1/2 width, 1/2 height
  185. LIBYUV_API
  186. int I422ToI420(const uint8_t* src_y,
  187. int src_stride_y,
  188. const uint8_t* src_u,
  189. int src_stride_u,
  190. const uint8_t* src_v,
  191. int src_stride_v,
  192. uint8_t* dst_y,
  193. int dst_stride_y,
  194. uint8_t* dst_u,
  195. int dst_stride_u,
  196. uint8_t* dst_v,
  197. int dst_stride_v,
  198. int width,
  199. int height) {
  200. const int src_uv_width = SUBSAMPLE(width, 1, 1);
  201. return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
  202. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  203. dst_v, dst_stride_v, width, height, src_uv_width, height);
  204. }
  205. // 444 chroma is 1x width, 1x height
  206. // 420 chroma is 1/2 width, 1/2 height
  207. LIBYUV_API
  208. int I444ToI420(const uint8_t* src_y,
  209. int src_stride_y,
  210. const uint8_t* src_u,
  211. int src_stride_u,
  212. const uint8_t* src_v,
  213. int src_stride_v,
  214. uint8_t* dst_y,
  215. int dst_stride_y,
  216. uint8_t* dst_u,
  217. int dst_stride_u,
  218. uint8_t* dst_v,
  219. int dst_stride_v,
  220. int width,
  221. int height) {
  222. return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
  223. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  224. dst_v, dst_stride_v, width, height, width, height);
  225. }
  226. // I400 is greyscale typically used in MJPG
  227. LIBYUV_API
  228. int I400ToI420(const uint8_t* src_y,
  229. int src_stride_y,
  230. uint8_t* dst_y,
  231. int dst_stride_y,
  232. uint8_t* dst_u,
  233. int dst_stride_u,
  234. uint8_t* dst_v,
  235. int dst_stride_v,
  236. int width,
  237. int height) {
  238. int halfwidth = (width + 1) >> 1;
  239. int halfheight = (height + 1) >> 1;
  240. if (!dst_u || !dst_v || width <= 0 || height == 0) {
  241. return -1;
  242. }
  243. // Negative height means invert the image.
  244. if (height < 0) {
  245. height = -height;
  246. halfheight = (height + 1) >> 1;
  247. src_y = src_y + (height - 1) * src_stride_y;
  248. src_stride_y = -src_stride_y;
  249. }
  250. if (dst_y) {
  251. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  252. }
  253. SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
  254. SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
  255. return 0;
  256. }
  257. static void CopyPlane2(const uint8_t* src,
  258. int src_stride_0,
  259. int src_stride_1,
  260. uint8_t* dst,
  261. int dst_stride,
  262. int width,
  263. int height) {
  264. int y;
  265. void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
  266. #if defined(HAS_COPYROW_SSE2)
  267. if (TestCpuFlag(kCpuHasSSE2)) {
  268. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
  269. }
  270. #endif
  271. #if defined(HAS_COPYROW_AVX)
  272. if (TestCpuFlag(kCpuHasAVX)) {
  273. CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
  274. }
  275. #endif
  276. #if defined(HAS_COPYROW_ERMS)
  277. if (TestCpuFlag(kCpuHasERMS)) {
  278. CopyRow = CopyRow_ERMS;
  279. }
  280. #endif
  281. #if defined(HAS_COPYROW_NEON)
  282. if (TestCpuFlag(kCpuHasNEON)) {
  283. CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
  284. }
  285. #endif
  286. // Copy plane
  287. for (y = 0; y < height - 1; y += 2) {
  288. CopyRow(src, dst, width);
  289. CopyRow(src + src_stride_0, dst + dst_stride, width);
  290. src += src_stride_0 + src_stride_1;
  291. dst += dst_stride * 2;
  292. }
  293. if (height & 1) {
  294. CopyRow(src, dst, width);
  295. }
  296. }
  297. // Support converting from FOURCC_M420
  298. // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
  299. // easy conversion to I420.
  300. // M420 format description:
  301. // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
  302. // Chroma is half width / half height. (420)
  303. // src_stride_m420 is row planar. Normally this will be the width in pixels.
  304. // The UV plane is half width, but 2 values, so src_stride_m420 applies to
  305. // this as well as the two Y planes.
  306. static int X420ToI420(const uint8_t* src_y,
  307. int src_stride_y0,
  308. int src_stride_y1,
  309. const uint8_t* src_uv,
  310. int src_stride_uv,
  311. uint8_t* dst_y,
  312. int dst_stride_y,
  313. uint8_t* dst_u,
  314. int dst_stride_u,
  315. uint8_t* dst_v,
  316. int dst_stride_v,
  317. int width,
  318. int height) {
  319. int halfwidth = (width + 1) >> 1;
  320. int halfheight = (height + 1) >> 1;
  321. if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
  322. return -1;
  323. }
  324. // Negative height means invert the image.
  325. if (height < 0) {
  326. height = -height;
  327. halfheight = (height + 1) >> 1;
  328. if (dst_y) {
  329. dst_y = dst_y + (height - 1) * dst_stride_y;
  330. }
  331. dst_u = dst_u + (halfheight - 1) * dst_stride_u;
  332. dst_v = dst_v + (halfheight - 1) * dst_stride_v;
  333. dst_stride_y = -dst_stride_y;
  334. dst_stride_u = -dst_stride_u;
  335. dst_stride_v = -dst_stride_v;
  336. }
  337. // Coalesce rows.
  338. if (src_stride_y0 == width && src_stride_y1 == width &&
  339. dst_stride_y == width) {
  340. width *= height;
  341. height = 1;
  342. src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
  343. }
  344. // Coalesce rows.
  345. if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
  346. dst_stride_v == halfwidth) {
  347. halfwidth *= halfheight;
  348. halfheight = 1;
  349. src_stride_uv = dst_stride_u = dst_stride_v = 0;
  350. }
  351. if (dst_y) {
  352. if (src_stride_y0 == src_stride_y1) {
  353. CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
  354. } else {
  355. CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
  356. width, height);
  357. }
  358. }
  359. // Split UV plane - NV12 / NV21
  360. SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
  361. halfwidth, halfheight);
  362. return 0;
  363. }
  364. // Convert NV12 to I420.
  365. LIBYUV_API
  366. int NV12ToI420(const uint8_t* src_y,
  367. int src_stride_y,
  368. const uint8_t* src_uv,
  369. int src_stride_uv,
  370. uint8_t* dst_y,
  371. int dst_stride_y,
  372. uint8_t* dst_u,
  373. int dst_stride_u,
  374. uint8_t* dst_v,
  375. int dst_stride_v,
  376. int width,
  377. int height) {
  378. return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
  379. dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
  380. dst_stride_v, width, height);
  381. }
  382. // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
  383. LIBYUV_API
  384. int NV21ToI420(const uint8_t* src_y,
  385. int src_stride_y,
  386. const uint8_t* src_vu,
  387. int src_stride_vu,
  388. uint8_t* dst_y,
  389. int dst_stride_y,
  390. uint8_t* dst_u,
  391. int dst_stride_u,
  392. uint8_t* dst_v,
  393. int dst_stride_v,
  394. int width,
  395. int height) {
  396. return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu,
  397. dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u,
  398. dst_stride_u, width, height);
  399. }
  400. // Convert M420 to I420.
  401. LIBYUV_API
  402. int M420ToI420(const uint8_t* src_m420,
  403. int src_stride_m420,
  404. uint8_t* dst_y,
  405. int dst_stride_y,
  406. uint8_t* dst_u,
  407. int dst_stride_u,
  408. uint8_t* dst_v,
  409. int dst_stride_v,
  410. int width,
  411. int height) {
  412. return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
  413. src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y,
  414. dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
  415. width, height);
  416. }
  417. // Convert YUY2 to I420.
  418. LIBYUV_API
  419. int YUY2ToI420(const uint8_t* src_yuy2,
  420. int src_stride_yuy2,
  421. uint8_t* dst_y,
  422. int dst_stride_y,
  423. uint8_t* dst_u,
  424. int dst_stride_u,
  425. uint8_t* dst_v,
  426. int dst_stride_v,
  427. int width,
  428. int height) {
  429. int y;
  430. void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
  431. uint8_t* dst_u, uint8_t* dst_v, int width) =
  432. YUY2ToUVRow_C;
  433. void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
  434. YUY2ToYRow_C;
  435. // Negative height means invert the image.
  436. if (height < 0) {
  437. height = -height;
  438. src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
  439. src_stride_yuy2 = -src_stride_yuy2;
  440. }
  441. #if defined(HAS_YUY2TOYROW_SSE2)
  442. if (TestCpuFlag(kCpuHasSSE2)) {
  443. YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
  444. YUY2ToYRow = YUY2ToYRow_Any_SSE2;
  445. if (IS_ALIGNED(width, 16)) {
  446. YUY2ToUVRow = YUY2ToUVRow_SSE2;
  447. YUY2ToYRow = YUY2ToYRow_SSE2;
  448. }
  449. }
  450. #endif
  451. #if defined(HAS_YUY2TOYROW_AVX2)
  452. if (TestCpuFlag(kCpuHasAVX2)) {
  453. YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
  454. YUY2ToYRow = YUY2ToYRow_Any_AVX2;
  455. if (IS_ALIGNED(width, 32)) {
  456. YUY2ToUVRow = YUY2ToUVRow_AVX2;
  457. YUY2ToYRow = YUY2ToYRow_AVX2;
  458. }
  459. }
  460. #endif
  461. #if defined(HAS_YUY2TOYROW_NEON)
  462. if (TestCpuFlag(kCpuHasNEON)) {
  463. YUY2ToYRow = YUY2ToYRow_Any_NEON;
  464. YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
  465. if (IS_ALIGNED(width, 16)) {
  466. YUY2ToYRow = YUY2ToYRow_NEON;
  467. YUY2ToUVRow = YUY2ToUVRow_NEON;
  468. }
  469. }
  470. #endif
  471. #if defined(HAS_YUY2TOYROW_MSA)
  472. if (TestCpuFlag(kCpuHasMSA)) {
  473. YUY2ToYRow = YUY2ToYRow_Any_MSA;
  474. YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
  475. if (IS_ALIGNED(width, 32)) {
  476. YUY2ToYRow = YUY2ToYRow_MSA;
  477. YUY2ToUVRow = YUY2ToUVRow_MSA;
  478. }
  479. }
  480. #endif
  481. for (y = 0; y < height - 1; y += 2) {
  482. YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
  483. YUY2ToYRow(src_yuy2, dst_y, width);
  484. YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
  485. src_yuy2 += src_stride_yuy2 * 2;
  486. dst_y += dst_stride_y * 2;
  487. dst_u += dst_stride_u;
  488. dst_v += dst_stride_v;
  489. }
  490. if (height & 1) {
  491. YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
  492. YUY2ToYRow(src_yuy2, dst_y, width);
  493. }
  494. return 0;
  495. }
  496. // Convert UYVY to I420.
  497. LIBYUV_API
  498. int UYVYToI420(const uint8_t* src_uyvy,
  499. int src_stride_uyvy,
  500. uint8_t* dst_y,
  501. int dst_stride_y,
  502. uint8_t* dst_u,
  503. int dst_stride_u,
  504. uint8_t* dst_v,
  505. int dst_stride_v,
  506. int width,
  507. int height) {
  508. int y;
  509. void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
  510. uint8_t* dst_u, uint8_t* dst_v, int width) =
  511. UYVYToUVRow_C;
  512. void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
  513. UYVYToYRow_C;
  514. // Negative height means invert the image.
  515. if (height < 0) {
  516. height = -height;
  517. src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
  518. src_stride_uyvy = -src_stride_uyvy;
  519. }
  520. #if defined(HAS_UYVYTOYROW_SSE2)
  521. if (TestCpuFlag(kCpuHasSSE2)) {
  522. UYVYToUVRow = UYVYToUVRow_Any_SSE2;
  523. UYVYToYRow = UYVYToYRow_Any_SSE2;
  524. if (IS_ALIGNED(width, 16)) {
  525. UYVYToUVRow = UYVYToUVRow_SSE2;
  526. UYVYToYRow = UYVYToYRow_SSE2;
  527. }
  528. }
  529. #endif
  530. #if defined(HAS_UYVYTOYROW_AVX2)
  531. if (TestCpuFlag(kCpuHasAVX2)) {
  532. UYVYToUVRow = UYVYToUVRow_Any_AVX2;
  533. UYVYToYRow = UYVYToYRow_Any_AVX2;
  534. if (IS_ALIGNED(width, 32)) {
  535. UYVYToUVRow = UYVYToUVRow_AVX2;
  536. UYVYToYRow = UYVYToYRow_AVX2;
  537. }
  538. }
  539. #endif
  540. #if defined(HAS_UYVYTOYROW_NEON)
  541. if (TestCpuFlag(kCpuHasNEON)) {
  542. UYVYToYRow = UYVYToYRow_Any_NEON;
  543. UYVYToUVRow = UYVYToUVRow_Any_NEON;
  544. if (IS_ALIGNED(width, 16)) {
  545. UYVYToYRow = UYVYToYRow_NEON;
  546. UYVYToUVRow = UYVYToUVRow_NEON;
  547. }
  548. }
  549. #endif
  550. #if defined(HAS_UYVYTOYROW_MSA)
  551. if (TestCpuFlag(kCpuHasMSA)) {
  552. UYVYToYRow = UYVYToYRow_Any_MSA;
  553. UYVYToUVRow = UYVYToUVRow_Any_MSA;
  554. if (IS_ALIGNED(width, 32)) {
  555. UYVYToYRow = UYVYToYRow_MSA;
  556. UYVYToUVRow = UYVYToUVRow_MSA;
  557. }
  558. }
  559. #endif
  560. for (y = 0; y < height - 1; y += 2) {
  561. UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
  562. UYVYToYRow(src_uyvy, dst_y, width);
  563. UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
  564. src_uyvy += src_stride_uyvy * 2;
  565. dst_y += dst_stride_y * 2;
  566. dst_u += dst_stride_u;
  567. dst_v += dst_stride_v;
  568. }
  569. if (height & 1) {
  570. UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
  571. UYVYToYRow(src_uyvy, dst_y, width);
  572. }
  573. return 0;
  574. }
  575. // Convert ARGB to I420.
  576. LIBYUV_API
  577. int ARGBToI420(const uint8_t* src_argb,
  578. int src_stride_argb,
  579. uint8_t* dst_y,
  580. int dst_stride_y,
  581. uint8_t* dst_u,
  582. int dst_stride_u,
  583. uint8_t* dst_v,
  584. int dst_stride_v,
  585. int width,
  586. int height) {
  587. int y;
  588. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  589. uint8_t* dst_u, uint8_t* dst_v, int width) =
  590. ARGBToUVRow_C;
  591. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  592. ARGBToYRow_C;
  593. if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  594. return -1;
  595. }
  596. // Negative height means invert the image.
  597. if (height < 0) {
  598. height = -height;
  599. src_argb = src_argb + (height - 1) * src_stride_argb;
  600. src_stride_argb = -src_stride_argb;
  601. }
  602. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  603. if (TestCpuFlag(kCpuHasSSSE3)) {
  604. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  605. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  606. if (IS_ALIGNED(width, 16)) {
  607. ARGBToUVRow = ARGBToUVRow_SSSE3;
  608. ARGBToYRow = ARGBToYRow_SSSE3;
  609. }
  610. }
  611. #endif
  612. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  613. if (TestCpuFlag(kCpuHasAVX2)) {
  614. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  615. ARGBToYRow = ARGBToYRow_Any_AVX2;
  616. if (IS_ALIGNED(width, 32)) {
  617. ARGBToUVRow = ARGBToUVRow_AVX2;
  618. ARGBToYRow = ARGBToYRow_AVX2;
  619. }
  620. }
  621. #endif
  622. #if defined(HAS_ARGBTOYROW_NEON)
  623. if (TestCpuFlag(kCpuHasNEON)) {
  624. ARGBToYRow = ARGBToYRow_Any_NEON;
  625. if (IS_ALIGNED(width, 8)) {
  626. ARGBToYRow = ARGBToYRow_NEON;
  627. }
  628. }
  629. #endif
  630. #if defined(HAS_ARGBTOUVROW_NEON)
  631. if (TestCpuFlag(kCpuHasNEON)) {
  632. ARGBToUVRow = ARGBToUVRow_Any_NEON;
  633. if (IS_ALIGNED(width, 16)) {
  634. ARGBToUVRow = ARGBToUVRow_NEON;
  635. }
  636. }
  637. #endif
  638. #if defined(HAS_ARGBTOYROW_MSA)
  639. if (TestCpuFlag(kCpuHasMSA)) {
  640. ARGBToYRow = ARGBToYRow_Any_MSA;
  641. if (IS_ALIGNED(width, 16)) {
  642. ARGBToYRow = ARGBToYRow_MSA;
  643. }
  644. }
  645. #endif
  646. #if defined(HAS_ARGBTOUVROW_MSA)
  647. if (TestCpuFlag(kCpuHasMSA)) {
  648. ARGBToUVRow = ARGBToUVRow_Any_MSA;
  649. if (IS_ALIGNED(width, 32)) {
  650. ARGBToUVRow = ARGBToUVRow_MSA;
  651. }
  652. }
  653. #endif
  654. for (y = 0; y < height - 1; y += 2) {
  655. ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
  656. ARGBToYRow(src_argb, dst_y, width);
  657. ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
  658. src_argb += src_stride_argb * 2;
  659. dst_y += dst_stride_y * 2;
  660. dst_u += dst_stride_u;
  661. dst_v += dst_stride_v;
  662. }
  663. if (height & 1) {
  664. ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
  665. ARGBToYRow(src_argb, dst_y, width);
  666. }
  667. return 0;
  668. }
  669. // Convert BGRA to I420.
  670. LIBYUV_API
  671. int BGRAToI420(const uint8_t* src_bgra,
  672. int src_stride_bgra,
  673. uint8_t* dst_y,
  674. int dst_stride_y,
  675. uint8_t* dst_u,
  676. int dst_stride_u,
  677. uint8_t* dst_v,
  678. int dst_stride_v,
  679. int width,
  680. int height) {
  681. int y;
  682. void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
  683. uint8_t* dst_u, uint8_t* dst_v, int width) =
  684. BGRAToUVRow_C;
  685. void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
  686. BGRAToYRow_C;
  687. if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  688. return -1;
  689. }
  690. // Negative height means invert the image.
  691. if (height < 0) {
  692. height = -height;
  693. src_bgra = src_bgra + (height - 1) * src_stride_bgra;
  694. src_stride_bgra = -src_stride_bgra;
  695. }
  696. #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
  697. if (TestCpuFlag(kCpuHasSSSE3)) {
  698. BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
  699. BGRAToYRow = BGRAToYRow_Any_SSSE3;
  700. if (IS_ALIGNED(width, 16)) {
  701. BGRAToUVRow = BGRAToUVRow_SSSE3;
  702. BGRAToYRow = BGRAToYRow_SSSE3;
  703. }
  704. }
  705. #endif
  706. #if defined(HAS_BGRATOYROW_NEON)
  707. if (TestCpuFlag(kCpuHasNEON)) {
  708. BGRAToYRow = BGRAToYRow_Any_NEON;
  709. if (IS_ALIGNED(width, 8)) {
  710. BGRAToYRow = BGRAToYRow_NEON;
  711. }
  712. }
  713. #endif
  714. #if defined(HAS_BGRATOUVROW_NEON)
  715. if (TestCpuFlag(kCpuHasNEON)) {
  716. BGRAToUVRow = BGRAToUVRow_Any_NEON;
  717. if (IS_ALIGNED(width, 16)) {
  718. BGRAToUVRow = BGRAToUVRow_NEON;
  719. }
  720. }
  721. #endif
  722. #if defined(HAS_BGRATOYROW_MSA)
  723. if (TestCpuFlag(kCpuHasMSA)) {
  724. BGRAToYRow = BGRAToYRow_Any_MSA;
  725. if (IS_ALIGNED(width, 16)) {
  726. BGRAToYRow = BGRAToYRow_MSA;
  727. }
  728. }
  729. #endif
  730. #if defined(HAS_BGRATOUVROW_MSA)
  731. if (TestCpuFlag(kCpuHasMSA)) {
  732. BGRAToUVRow = BGRAToUVRow_Any_MSA;
  733. if (IS_ALIGNED(width, 16)) {
  734. BGRAToUVRow = BGRAToUVRow_MSA;
  735. }
  736. }
  737. #endif
  738. for (y = 0; y < height - 1; y += 2) {
  739. BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
  740. BGRAToYRow(src_bgra, dst_y, width);
  741. BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
  742. src_bgra += src_stride_bgra * 2;
  743. dst_y += dst_stride_y * 2;
  744. dst_u += dst_stride_u;
  745. dst_v += dst_stride_v;
  746. }
  747. if (height & 1) {
  748. BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
  749. BGRAToYRow(src_bgra, dst_y, width);
  750. }
  751. return 0;
  752. }
  753. // Convert ABGR to I420.
  754. LIBYUV_API
  755. int ABGRToI420(const uint8_t* src_abgr,
  756. int src_stride_abgr,
  757. uint8_t* dst_y,
  758. int dst_stride_y,
  759. uint8_t* dst_u,
  760. int dst_stride_u,
  761. uint8_t* dst_v,
  762. int dst_stride_v,
  763. int width,
  764. int height) {
  765. int y;
  766. void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
  767. uint8_t* dst_u, uint8_t* dst_v, int width) =
  768. ABGRToUVRow_C;
  769. void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
  770. ABGRToYRow_C;
  771. if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  772. return -1;
  773. }
  774. // Negative height means invert the image.
  775. if (height < 0) {
  776. height = -height;
  777. src_abgr = src_abgr + (height - 1) * src_stride_abgr;
  778. src_stride_abgr = -src_stride_abgr;
  779. }
  780. #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
  781. if (TestCpuFlag(kCpuHasSSSE3)) {
  782. ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
  783. ABGRToYRow = ABGRToYRow_Any_SSSE3;
  784. if (IS_ALIGNED(width, 16)) {
  785. ABGRToUVRow = ABGRToUVRow_SSSE3;
  786. ABGRToYRow = ABGRToYRow_SSSE3;
  787. }
  788. }
  789. #endif
  790. #if defined(HAS_ABGRTOYROW_NEON)
  791. if (TestCpuFlag(kCpuHasNEON)) {
  792. ABGRToYRow = ABGRToYRow_Any_NEON;
  793. if (IS_ALIGNED(width, 8)) {
  794. ABGRToYRow = ABGRToYRow_NEON;
  795. }
  796. }
  797. #endif
  798. #if defined(HAS_ABGRTOUVROW_NEON)
  799. if (TestCpuFlag(kCpuHasNEON)) {
  800. ABGRToUVRow = ABGRToUVRow_Any_NEON;
  801. if (IS_ALIGNED(width, 16)) {
  802. ABGRToUVRow = ABGRToUVRow_NEON;
  803. }
  804. }
  805. #endif
  806. #if defined(HAS_ABGRTOYROW_MSA)
  807. if (TestCpuFlag(kCpuHasMSA)) {
  808. ABGRToYRow = ABGRToYRow_Any_MSA;
  809. if (IS_ALIGNED(width, 16)) {
  810. ABGRToYRow = ABGRToYRow_MSA;
  811. }
  812. }
  813. #endif
  814. #if defined(HAS_ABGRTOUVROW_MSA)
  815. if (TestCpuFlag(kCpuHasMSA)) {
  816. ABGRToUVRow = ABGRToUVRow_Any_MSA;
  817. if (IS_ALIGNED(width, 16)) {
  818. ABGRToUVRow = ABGRToUVRow_MSA;
  819. }
  820. }
  821. #endif
  822. for (y = 0; y < height - 1; y += 2) {
  823. ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
  824. ABGRToYRow(src_abgr, dst_y, width);
  825. ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
  826. src_abgr += src_stride_abgr * 2;
  827. dst_y += dst_stride_y * 2;
  828. dst_u += dst_stride_u;
  829. dst_v += dst_stride_v;
  830. }
  831. if (height & 1) {
  832. ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
  833. ABGRToYRow(src_abgr, dst_y, width);
  834. }
  835. return 0;
  836. }
  837. // Convert RGBA to I420.
  838. LIBYUV_API
  839. int RGBAToI420(const uint8_t* src_rgba,
  840. int src_stride_rgba,
  841. uint8_t* dst_y,
  842. int dst_stride_y,
  843. uint8_t* dst_u,
  844. int dst_stride_u,
  845. uint8_t* dst_v,
  846. int dst_stride_v,
  847. int width,
  848. int height) {
  849. int y;
  850. void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
  851. uint8_t* dst_u, uint8_t* dst_v, int width) =
  852. RGBAToUVRow_C;
  853. void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
  854. RGBAToYRow_C;
  855. if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  856. return -1;
  857. }
  858. // Negative height means invert the image.
  859. if (height < 0) {
  860. height = -height;
  861. src_rgba = src_rgba + (height - 1) * src_stride_rgba;
  862. src_stride_rgba = -src_stride_rgba;
  863. }
  864. #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
  865. if (TestCpuFlag(kCpuHasSSSE3)) {
  866. RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
  867. RGBAToYRow = RGBAToYRow_Any_SSSE3;
  868. if (IS_ALIGNED(width, 16)) {
  869. RGBAToUVRow = RGBAToUVRow_SSSE3;
  870. RGBAToYRow = RGBAToYRow_SSSE3;
  871. }
  872. }
  873. #endif
  874. #if defined(HAS_RGBATOYROW_NEON)
  875. if (TestCpuFlag(kCpuHasNEON)) {
  876. RGBAToYRow = RGBAToYRow_Any_NEON;
  877. if (IS_ALIGNED(width, 8)) {
  878. RGBAToYRow = RGBAToYRow_NEON;
  879. }
  880. }
  881. #endif
  882. #if defined(HAS_RGBATOUVROW_NEON)
  883. if (TestCpuFlag(kCpuHasNEON)) {
  884. RGBAToUVRow = RGBAToUVRow_Any_NEON;
  885. if (IS_ALIGNED(width, 16)) {
  886. RGBAToUVRow = RGBAToUVRow_NEON;
  887. }
  888. }
  889. #endif
  890. #if defined(HAS_RGBATOYROW_MSA)
  891. if (TestCpuFlag(kCpuHasMSA)) {
  892. RGBAToYRow = RGBAToYRow_Any_MSA;
  893. if (IS_ALIGNED(width, 16)) {
  894. RGBAToYRow = RGBAToYRow_MSA;
  895. }
  896. }
  897. #endif
  898. #if defined(HAS_RGBATOUVROW_MSA)
  899. if (TestCpuFlag(kCpuHasMSA)) {
  900. RGBAToUVRow = RGBAToUVRow_Any_MSA;
  901. if (IS_ALIGNED(width, 16)) {
  902. RGBAToUVRow = RGBAToUVRow_MSA;
  903. }
  904. }
  905. #endif
  906. for (y = 0; y < height - 1; y += 2) {
  907. RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
  908. RGBAToYRow(src_rgba, dst_y, width);
  909. RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
  910. src_rgba += src_stride_rgba * 2;
  911. dst_y += dst_stride_y * 2;
  912. dst_u += dst_stride_u;
  913. dst_v += dst_stride_v;
  914. }
  915. if (height & 1) {
  916. RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
  917. RGBAToYRow(src_rgba, dst_y, width);
  918. }
  919. return 0;
  920. }
  921. // Convert RGB24 to I420.
  922. LIBYUV_API
  923. int RGB24ToI420(const uint8_t* src_rgb24,
  924. int src_stride_rgb24,
  925. uint8_t* dst_y,
  926. int dst_stride_y,
  927. uint8_t* dst_u,
  928. int dst_stride_u,
  929. uint8_t* dst_v,
  930. int dst_stride_v,
  931. int width,
  932. int height) {
  933. int y;
  934. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
  935. void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
  936. uint8_t* dst_u, uint8_t* dst_v, int width) =
  937. RGB24ToUVRow_C;
  938. void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
  939. RGB24ToYRow_C;
  940. #else
  941. void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
  942. RGB24ToARGBRow_C;
  943. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  944. uint8_t* dst_u, uint8_t* dst_v, int width) =
  945. ARGBToUVRow_C;
  946. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  947. ARGBToYRow_C;
  948. #endif
  949. if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  950. return -1;
  951. }
  952. // Negative height means invert the image.
  953. if (height < 0) {
  954. height = -height;
  955. src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
  956. src_stride_rgb24 = -src_stride_rgb24;
  957. }
  958. // Neon version does direct RGB24 to YUV.
  959. #if defined(HAS_RGB24TOYROW_NEON)
  960. if (TestCpuFlag(kCpuHasNEON)) {
  961. RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
  962. RGB24ToYRow = RGB24ToYRow_Any_NEON;
  963. if (IS_ALIGNED(width, 8)) {
  964. RGB24ToYRow = RGB24ToYRow_NEON;
  965. if (IS_ALIGNED(width, 16)) {
  966. RGB24ToUVRow = RGB24ToUVRow_NEON;
  967. }
  968. }
  969. }
  970. #elif defined(HAS_RGB24TOYROW_MSA)
  971. if (TestCpuFlag(kCpuHasMSA)) {
  972. RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
  973. RGB24ToYRow = RGB24ToYRow_Any_MSA;
  974. if (IS_ALIGNED(width, 16)) {
  975. RGB24ToYRow = RGB24ToYRow_MSA;
  976. RGB24ToUVRow = RGB24ToUVRow_MSA;
  977. }
  978. }
  979. // Other platforms do intermediate conversion from RGB24 to ARGB.
  980. #else
  981. #if defined(HAS_RGB24TOARGBROW_SSSE3)
  982. if (TestCpuFlag(kCpuHasSSSE3)) {
  983. RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
  984. if (IS_ALIGNED(width, 16)) {
  985. RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
  986. }
  987. }
  988. #endif
  989. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  990. if (TestCpuFlag(kCpuHasSSSE3)) {
  991. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  992. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  993. if (IS_ALIGNED(width, 16)) {
  994. ARGBToUVRow = ARGBToUVRow_SSSE3;
  995. ARGBToYRow = ARGBToYRow_SSSE3;
  996. }
  997. }
  998. #endif
  999. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1000. if (TestCpuFlag(kCpuHasAVX2)) {
  1001. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1002. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1003. if (IS_ALIGNED(width, 32)) {
  1004. ARGBToUVRow = ARGBToUVRow_AVX2;
  1005. ARGBToYRow = ARGBToYRow_AVX2;
  1006. }
  1007. }
  1008. #endif
  1009. #endif
  1010. {
  1011. #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
  1012. // Allocate 2 rows of ARGB.
  1013. const int kRowSize = (width * 4 + 31) & ~31;
  1014. align_buffer_64(row, kRowSize * 2);
  1015. #endif
  1016. for (y = 0; y < height - 1; y += 2) {
  1017. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
  1018. RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
  1019. RGB24ToYRow(src_rgb24, dst_y, width);
  1020. RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
  1021. #else
  1022. RGB24ToARGBRow(src_rgb24, row, width);
  1023. RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
  1024. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1025. ARGBToYRow(row, dst_y, width);
  1026. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1027. #endif
  1028. src_rgb24 += src_stride_rgb24 * 2;
  1029. dst_y += dst_stride_y * 2;
  1030. dst_u += dst_stride_u;
  1031. dst_v += dst_stride_v;
  1032. }
  1033. if (height & 1) {
  1034. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
  1035. RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
  1036. RGB24ToYRow(src_rgb24, dst_y, width);
  1037. #else
  1038. RGB24ToARGBRow(src_rgb24, row, width);
  1039. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1040. ARGBToYRow(row, dst_y, width);
  1041. #endif
  1042. }
  1043. #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
  1044. free_aligned_buffer_64(row);
  1045. #endif
  1046. }
  1047. return 0;
  1048. }
  1049. // Convert RAW to I420.
  1050. LIBYUV_API
  1051. int RAWToI420(const uint8_t* src_raw,
  1052. int src_stride_raw,
  1053. uint8_t* dst_y,
  1054. int dst_stride_y,
  1055. uint8_t* dst_u,
  1056. int dst_stride_u,
  1057. uint8_t* dst_v,
  1058. int dst_stride_v,
  1059. int width,
  1060. int height) {
  1061. int y;
  1062. #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
  1063. void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
  1064. uint8_t* dst_v, int width) = RAWToUVRow_C;
  1065. void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
  1066. RAWToYRow_C;
  1067. #else
  1068. void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
  1069. RAWToARGBRow_C;
  1070. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1071. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1072. ARGBToUVRow_C;
  1073. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1074. ARGBToYRow_C;
  1075. #endif
  1076. if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1077. return -1;
  1078. }
  1079. // Negative height means invert the image.
  1080. if (height < 0) {
  1081. height = -height;
  1082. src_raw = src_raw + (height - 1) * src_stride_raw;
  1083. src_stride_raw = -src_stride_raw;
  1084. }
  1085. // Neon version does direct RAW to YUV.
  1086. #if defined(HAS_RAWTOYROW_NEON)
  1087. if (TestCpuFlag(kCpuHasNEON)) {
  1088. RAWToUVRow = RAWToUVRow_Any_NEON;
  1089. RAWToYRow = RAWToYRow_Any_NEON;
  1090. if (IS_ALIGNED(width, 8)) {
  1091. RAWToYRow = RAWToYRow_NEON;
  1092. if (IS_ALIGNED(width, 16)) {
  1093. RAWToUVRow = RAWToUVRow_NEON;
  1094. }
  1095. }
  1096. }
  1097. #elif defined(HAS_RAWTOYROW_MSA)
  1098. if (TestCpuFlag(kCpuHasMSA)) {
  1099. RAWToUVRow = RAWToUVRow_Any_MSA;
  1100. RAWToYRow = RAWToYRow_Any_MSA;
  1101. if (IS_ALIGNED(width, 16)) {
  1102. RAWToYRow = RAWToYRow_MSA;
  1103. RAWToUVRow = RAWToUVRow_MSA;
  1104. }
  1105. }
  1106. // Other platforms do intermediate conversion from RAW to ARGB.
  1107. #else
  1108. #if defined(HAS_RAWTOARGBROW_SSSE3)
  1109. if (TestCpuFlag(kCpuHasSSSE3)) {
  1110. RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
  1111. if (IS_ALIGNED(width, 16)) {
  1112. RAWToARGBRow = RAWToARGBRow_SSSE3;
  1113. }
  1114. }
  1115. #endif
  1116. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1117. if (TestCpuFlag(kCpuHasSSSE3)) {
  1118. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1119. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1120. if (IS_ALIGNED(width, 16)) {
  1121. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1122. ARGBToYRow = ARGBToYRow_SSSE3;
  1123. }
  1124. }
  1125. #endif
  1126. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1127. if (TestCpuFlag(kCpuHasAVX2)) {
  1128. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1129. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1130. if (IS_ALIGNED(width, 32)) {
  1131. ARGBToUVRow = ARGBToUVRow_AVX2;
  1132. ARGBToYRow = ARGBToYRow_AVX2;
  1133. }
  1134. }
  1135. #endif
  1136. #endif
  1137. {
  1138. #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
  1139. // Allocate 2 rows of ARGB.
  1140. const int kRowSize = (width * 4 + 31) & ~31;
  1141. align_buffer_64(row, kRowSize * 2);
  1142. #endif
  1143. for (y = 0; y < height - 1; y += 2) {
  1144. #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
  1145. RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
  1146. RAWToYRow(src_raw, dst_y, width);
  1147. RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
  1148. #else
  1149. RAWToARGBRow(src_raw, row, width);
  1150. RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
  1151. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1152. ARGBToYRow(row, dst_y, width);
  1153. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1154. #endif
  1155. src_raw += src_stride_raw * 2;
  1156. dst_y += dst_stride_y * 2;
  1157. dst_u += dst_stride_u;
  1158. dst_v += dst_stride_v;
  1159. }
  1160. if (height & 1) {
  1161. #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
  1162. RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
  1163. RAWToYRow(src_raw, dst_y, width);
  1164. #else
  1165. RAWToARGBRow(src_raw, row, width);
  1166. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1167. ARGBToYRow(row, dst_y, width);
  1168. #endif
  1169. }
  1170. #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
  1171. free_aligned_buffer_64(row);
  1172. #endif
  1173. }
  1174. return 0;
  1175. }
  1176. // Convert RGB565 to I420.
  1177. LIBYUV_API
  1178. int RGB565ToI420(const uint8_t* src_rgb565,
  1179. int src_stride_rgb565,
  1180. uint8_t* dst_y,
  1181. int dst_stride_y,
  1182. uint8_t* dst_u,
  1183. int dst_stride_u,
  1184. uint8_t* dst_v,
  1185. int dst_stride_v,
  1186. int width,
  1187. int height) {
  1188. int y;
  1189. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
  1190. void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
  1191. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1192. RGB565ToUVRow_C;
  1193. void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
  1194. RGB565ToYRow_C;
  1195. #else
  1196. void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  1197. int width) = RGB565ToARGBRow_C;
  1198. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1199. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1200. ARGBToUVRow_C;
  1201. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1202. ARGBToYRow_C;
  1203. #endif
  1204. if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1205. return -1;
  1206. }
  1207. // Negative height means invert the image.
  1208. if (height < 0) {
  1209. height = -height;
  1210. src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
  1211. src_stride_rgb565 = -src_stride_rgb565;
  1212. }
  1213. // Neon version does direct RGB565 to YUV.
  1214. #if defined(HAS_RGB565TOYROW_NEON)
  1215. if (TestCpuFlag(kCpuHasNEON)) {
  1216. RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
  1217. RGB565ToYRow = RGB565ToYRow_Any_NEON;
  1218. if (IS_ALIGNED(width, 8)) {
  1219. RGB565ToYRow = RGB565ToYRow_NEON;
  1220. if (IS_ALIGNED(width, 16)) {
  1221. RGB565ToUVRow = RGB565ToUVRow_NEON;
  1222. }
  1223. }
  1224. }
  1225. #elif defined(HAS_RGB565TOYROW_MSA)
  1226. if (TestCpuFlag(kCpuHasMSA)) {
  1227. RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
  1228. RGB565ToYRow = RGB565ToYRow_Any_MSA;
  1229. if (IS_ALIGNED(width, 16)) {
  1230. RGB565ToYRow = RGB565ToYRow_MSA;
  1231. RGB565ToUVRow = RGB565ToUVRow_MSA;
  1232. }
  1233. }
  1234. // Other platforms do intermediate conversion from RGB565 to ARGB.
  1235. #else
  1236. #if defined(HAS_RGB565TOARGBROW_SSE2)
  1237. if (TestCpuFlag(kCpuHasSSE2)) {
  1238. RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
  1239. if (IS_ALIGNED(width, 8)) {
  1240. RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
  1241. }
  1242. }
  1243. #endif
  1244. #if defined(HAS_RGB565TOARGBROW_AVX2)
  1245. if (TestCpuFlag(kCpuHasAVX2)) {
  1246. RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
  1247. if (IS_ALIGNED(width, 16)) {
  1248. RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
  1249. }
  1250. }
  1251. #endif
  1252. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1253. if (TestCpuFlag(kCpuHasSSSE3)) {
  1254. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1255. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1256. if (IS_ALIGNED(width, 16)) {
  1257. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1258. ARGBToYRow = ARGBToYRow_SSSE3;
  1259. }
  1260. }
  1261. #endif
  1262. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1263. if (TestCpuFlag(kCpuHasAVX2)) {
  1264. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1265. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1266. if (IS_ALIGNED(width, 32)) {
  1267. ARGBToUVRow = ARGBToUVRow_AVX2;
  1268. ARGBToYRow = ARGBToYRow_AVX2;
  1269. }
  1270. }
  1271. #endif
  1272. #endif
  1273. {
  1274. #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
  1275. // Allocate 2 rows of ARGB.
  1276. const int kRowSize = (width * 4 + 31) & ~31;
  1277. align_buffer_64(row, kRowSize * 2);
  1278. #endif
  1279. for (y = 0; y < height - 1; y += 2) {
  1280. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
  1281. RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
  1282. RGB565ToYRow(src_rgb565, dst_y, width);
  1283. RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
  1284. #else
  1285. RGB565ToARGBRow(src_rgb565, row, width);
  1286. RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
  1287. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1288. ARGBToYRow(row, dst_y, width);
  1289. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1290. #endif
  1291. src_rgb565 += src_stride_rgb565 * 2;
  1292. dst_y += dst_stride_y * 2;
  1293. dst_u += dst_stride_u;
  1294. dst_v += dst_stride_v;
  1295. }
  1296. if (height & 1) {
  1297. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
  1298. RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
  1299. RGB565ToYRow(src_rgb565, dst_y, width);
  1300. #else
  1301. RGB565ToARGBRow(src_rgb565, row, width);
  1302. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1303. ARGBToYRow(row, dst_y, width);
  1304. #endif
  1305. }
  1306. #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
  1307. free_aligned_buffer_64(row);
  1308. #endif
  1309. }
  1310. return 0;
  1311. }
  1312. // Convert ARGB1555 to I420.
  1313. LIBYUV_API
  1314. int ARGB1555ToI420(const uint8_t* src_argb1555,
  1315. int src_stride_argb1555,
  1316. uint8_t* dst_y,
  1317. int dst_stride_y,
  1318. uint8_t* dst_u,
  1319. int dst_stride_u,
  1320. uint8_t* dst_v,
  1321. int dst_stride_v,
  1322. int width,
  1323. int height) {
  1324. int y;
  1325. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
  1326. void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
  1327. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1328. ARGB1555ToUVRow_C;
  1329. void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
  1330. int width) = ARGB1555ToYRow_C;
  1331. #else
  1332. void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  1333. int width) = ARGB1555ToARGBRow_C;
  1334. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1335. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1336. ARGBToUVRow_C;
  1337. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1338. ARGBToYRow_C;
  1339. #endif
  1340. if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
  1341. height == 0) {
  1342. return -1;
  1343. }
  1344. // Negative height means invert the image.
  1345. if (height < 0) {
  1346. height = -height;
  1347. src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
  1348. src_stride_argb1555 = -src_stride_argb1555;
  1349. }
  1350. // Neon version does direct ARGB1555 to YUV.
  1351. #if defined(HAS_ARGB1555TOYROW_NEON)
  1352. if (TestCpuFlag(kCpuHasNEON)) {
  1353. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
  1354. ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
  1355. if (IS_ALIGNED(width, 8)) {
  1356. ARGB1555ToYRow = ARGB1555ToYRow_NEON;
  1357. if (IS_ALIGNED(width, 16)) {
  1358. ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
  1359. }
  1360. }
  1361. }
  1362. #elif defined(HAS_ARGB1555TOYROW_MSA)
  1363. if (TestCpuFlag(kCpuHasMSA)) {
  1364. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
  1365. ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
  1366. if (IS_ALIGNED(width, 16)) {
  1367. ARGB1555ToYRow = ARGB1555ToYRow_MSA;
  1368. ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
  1369. }
  1370. }
  1371. // Other platforms do intermediate conversion from ARGB1555 to ARGB.
  1372. #else
  1373. #if defined(HAS_ARGB1555TOARGBROW_SSE2)
  1374. if (TestCpuFlag(kCpuHasSSE2)) {
  1375. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
  1376. if (IS_ALIGNED(width, 8)) {
  1377. ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
  1378. }
  1379. }
  1380. #endif
  1381. #if defined(HAS_ARGB1555TOARGBROW_AVX2)
  1382. if (TestCpuFlag(kCpuHasAVX2)) {
  1383. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
  1384. if (IS_ALIGNED(width, 16)) {
  1385. ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
  1386. }
  1387. }
  1388. #endif
  1389. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1390. if (TestCpuFlag(kCpuHasSSSE3)) {
  1391. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1392. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1393. if (IS_ALIGNED(width, 16)) {
  1394. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1395. ARGBToYRow = ARGBToYRow_SSSE3;
  1396. }
  1397. }
  1398. #endif
  1399. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1400. if (TestCpuFlag(kCpuHasAVX2)) {
  1401. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1402. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1403. if (IS_ALIGNED(width, 32)) {
  1404. ARGBToUVRow = ARGBToUVRow_AVX2;
  1405. ARGBToYRow = ARGBToYRow_AVX2;
  1406. }
  1407. }
  1408. #endif
  1409. #endif
  1410. {
  1411. #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
  1412. // Allocate 2 rows of ARGB.
  1413. const int kRowSize = (width * 4 + 31) & ~31;
  1414. align_buffer_64(row, kRowSize * 2);
  1415. #endif
  1416. for (y = 0; y < height - 1; y += 2) {
  1417. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
  1418. ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
  1419. ARGB1555ToYRow(src_argb1555, dst_y, width);
  1420. ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
  1421. width);
  1422. #else
  1423. ARGB1555ToARGBRow(src_argb1555, row, width);
  1424. ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
  1425. width);
  1426. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1427. ARGBToYRow(row, dst_y, width);
  1428. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1429. #endif
  1430. src_argb1555 += src_stride_argb1555 * 2;
  1431. dst_y += dst_stride_y * 2;
  1432. dst_u += dst_stride_u;
  1433. dst_v += dst_stride_v;
  1434. }
  1435. if (height & 1) {
  1436. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
  1437. ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
  1438. ARGB1555ToYRow(src_argb1555, dst_y, width);
  1439. #else
  1440. ARGB1555ToARGBRow(src_argb1555, row, width);
  1441. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1442. ARGBToYRow(row, dst_y, width);
  1443. #endif
  1444. }
  1445. #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
  1446. free_aligned_buffer_64(row);
  1447. #endif
  1448. }
  1449. return 0;
  1450. }
  1451. // Convert ARGB4444 to I420.
  1452. LIBYUV_API
  1453. int ARGB4444ToI420(const uint8_t* src_argb4444,
  1454. int src_stride_argb4444,
  1455. uint8_t* dst_y,
  1456. int dst_stride_y,
  1457. uint8_t* dst_u,
  1458. int dst_stride_u,
  1459. uint8_t* dst_v,
  1460. int dst_stride_v,
  1461. int width,
  1462. int height) {
  1463. int y;
  1464. #if defined(HAS_ARGB4444TOYROW_NEON)
  1465. void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
  1466. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1467. ARGB4444ToUVRow_C;
  1468. void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
  1469. int width) = ARGB4444ToYRow_C;
  1470. #else
  1471. void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  1472. int width) = ARGB4444ToARGBRow_C;
  1473. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1474. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1475. ARGBToUVRow_C;
  1476. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1477. ARGBToYRow_C;
  1478. #endif
  1479. if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
  1480. height == 0) {
  1481. return -1;
  1482. }
  1483. // Negative height means invert the image.
  1484. if (height < 0) {
  1485. height = -height;
  1486. src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
  1487. src_stride_argb4444 = -src_stride_argb4444;
  1488. }
  1489. // Neon version does direct ARGB4444 to YUV.
  1490. #if defined(HAS_ARGB4444TOYROW_NEON)
  1491. if (TestCpuFlag(kCpuHasNEON)) {
  1492. ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
  1493. ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
  1494. if (IS_ALIGNED(width, 8)) {
  1495. ARGB4444ToYRow = ARGB4444ToYRow_NEON;
  1496. if (IS_ALIGNED(width, 16)) {
  1497. ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
  1498. }
  1499. }
  1500. }
  1501. // Other platforms do intermediate conversion from ARGB4444 to ARGB.
  1502. #else
  1503. #if defined(HAS_ARGB4444TOARGBROW_SSE2)
  1504. if (TestCpuFlag(kCpuHasSSE2)) {
  1505. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
  1506. if (IS_ALIGNED(width, 8)) {
  1507. ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
  1508. }
  1509. }
  1510. #endif
  1511. #if defined(HAS_ARGB4444TOARGBROW_AVX2)
  1512. if (TestCpuFlag(kCpuHasAVX2)) {
  1513. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
  1514. if (IS_ALIGNED(width, 16)) {
  1515. ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
  1516. }
  1517. }
  1518. #endif
  1519. #if defined(HAS_ARGB4444TOARGBROW_MSA)
  1520. if (TestCpuFlag(kCpuHasMSA)) {
  1521. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
  1522. if (IS_ALIGNED(width, 16)) {
  1523. ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
  1524. }
  1525. }
  1526. #endif
  1527. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1528. if (TestCpuFlag(kCpuHasSSSE3)) {
  1529. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1530. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1531. if (IS_ALIGNED(width, 16)) {
  1532. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1533. ARGBToYRow = ARGBToYRow_SSSE3;
  1534. }
  1535. }
  1536. #endif
  1537. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1538. if (TestCpuFlag(kCpuHasAVX2)) {
  1539. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1540. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1541. if (IS_ALIGNED(width, 32)) {
  1542. ARGBToUVRow = ARGBToUVRow_AVX2;
  1543. ARGBToYRow = ARGBToYRow_AVX2;
  1544. }
  1545. }
  1546. #endif
  1547. #if defined(HAS_ARGBTOYROW_MSA)
  1548. if (TestCpuFlag(kCpuHasMSA)) {
  1549. ARGBToUVRow = ARGBToUVRow_Any_MSA;
  1550. ARGBToYRow = ARGBToYRow_Any_MSA;
  1551. if (IS_ALIGNED(width, 16)) {
  1552. ARGBToYRow = ARGBToYRow_MSA;
  1553. if (IS_ALIGNED(width, 32)) {
  1554. ARGBToUVRow = ARGBToUVRow_MSA;
  1555. }
  1556. }
  1557. }
  1558. #endif
  1559. #endif
  1560. {
  1561. #if !defined(HAS_ARGB4444TOYROW_NEON)
  1562. // Allocate 2 rows of ARGB.
  1563. const int kRowSize = (width * 4 + 31) & ~31;
  1564. align_buffer_64(row, kRowSize * 2);
  1565. #endif
  1566. for (y = 0; y < height - 1; y += 2) {
  1567. #if defined(HAS_ARGB4444TOYROW_NEON)
  1568. ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
  1569. ARGB4444ToYRow(src_argb4444, dst_y, width);
  1570. ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
  1571. width);
  1572. #else
  1573. ARGB4444ToARGBRow(src_argb4444, row, width);
  1574. ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
  1575. width);
  1576. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1577. ARGBToYRow(row, dst_y, width);
  1578. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1579. #endif
  1580. src_argb4444 += src_stride_argb4444 * 2;
  1581. dst_y += dst_stride_y * 2;
  1582. dst_u += dst_stride_u;
  1583. dst_v += dst_stride_v;
  1584. }
  1585. if (height & 1) {
  1586. #if defined(HAS_ARGB4444TOYROW_NEON)
  1587. ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
  1588. ARGB4444ToYRow(src_argb4444, dst_y, width);
  1589. #else
  1590. ARGB4444ToARGBRow(src_argb4444, row, width);
  1591. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1592. ARGBToYRow(row, dst_y, width);
  1593. #endif
  1594. }
  1595. #if !defined(HAS_ARGB4444TOYROW_NEON)
  1596. free_aligned_buffer_64(row);
  1597. #endif
  1598. }
  1599. return 0;
  1600. }
  1601. static void SplitPixels(const uint8_t* src_u,
  1602. int src_pixel_stride_uv,
  1603. uint8_t* dst_u,
  1604. int width) {
  1605. int i;
  1606. for (i = 0; i < width; ++i) {
  1607. *dst_u = *src_u;
  1608. ++dst_u;
  1609. src_u += src_pixel_stride_uv;
  1610. }
  1611. }
  1612. // Convert Android420 to I420.
  1613. LIBYUV_API
  1614. int Android420ToI420(const uint8_t* src_y,
  1615. int src_stride_y,
  1616. const uint8_t* src_u,
  1617. int src_stride_u,
  1618. const uint8_t* src_v,
  1619. int src_stride_v,
  1620. int src_pixel_stride_uv,
  1621. uint8_t* dst_y,
  1622. int dst_stride_y,
  1623. uint8_t* dst_u,
  1624. int dst_stride_u,
  1625. uint8_t* dst_v,
  1626. int dst_stride_v,
  1627. int width,
  1628. int height) {
  1629. int y;
  1630. const ptrdiff_t vu_off = src_v - src_u;
  1631. int halfwidth = (width + 1) >> 1;
  1632. int halfheight = (height + 1) >> 1;
  1633. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  1634. return -1;
  1635. }
  1636. // Negative height means invert the image.
  1637. if (height < 0) {
  1638. height = -height;
  1639. halfheight = (height + 1) >> 1;
  1640. src_y = src_y + (height - 1) * src_stride_y;
  1641. src_u = src_u + (halfheight - 1) * src_stride_u;
  1642. src_v = src_v + (halfheight - 1) * src_stride_v;
  1643. src_stride_y = -src_stride_y;
  1644. src_stride_u = -src_stride_u;
  1645. src_stride_v = -src_stride_v;
  1646. }
  1647. if (dst_y) {
  1648. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  1649. }
  1650. // Copy UV planes as is - I420
  1651. if (src_pixel_stride_uv == 1) {
  1652. CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  1653. CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  1654. return 0;
  1655. // Split UV planes - NV21
  1656. }
  1657. if (src_pixel_stride_uv == 2 && vu_off == -1 &&
  1658. src_stride_u == src_stride_v) {
  1659. SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
  1660. halfwidth, halfheight);
  1661. return 0;
  1662. // Split UV planes - NV12
  1663. }
  1664. if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
  1665. SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
  1666. halfwidth, halfheight);
  1667. return 0;
  1668. }
  1669. for (y = 0; y < halfheight; ++y) {
  1670. SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
  1671. SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
  1672. src_u += src_stride_u;
  1673. src_v += src_stride_v;
  1674. dst_u += dst_stride_u;
  1675. dst_v += dst_stride_v;
  1676. }
  1677. return 0;
  1678. }
  1679. #ifdef __cplusplus
  1680. } // extern "C"
  1681. } // namespace libyuv
  1682. #endif