convert.cc 45 KB

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