convert.cc 52 KB

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