convert.cc 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514
  1. /*
  2. * Copyright 2011 The LibYuv Project Authors. All rights reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include "libyuv/convert.h"
  11. #include "libyuv/basic_types.h"
  12. #include "libyuv/cpu_id.h"
  13. #include "libyuv/planar_functions.h"
  14. #include "libyuv/rotate.h"
  15. #include "libyuv/row.h"
  16. #include "libyuv/scale.h" // For ScalePlane()
  17. #ifdef __cplusplus
  18. namespace libyuv {
  19. extern "C" {
  20. #endif
  21. #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
  22. static __inline int Abs(int v) {
  23. return v >= 0 ? v : -v;
  24. }
  25. // Any I4xx To I420 format with mirroring.
  26. static int I4xxToI420(const uint8_t* src_y,
  27. int src_stride_y,
  28. const uint8_t* src_u,
  29. int src_stride_u,
  30. const uint8_t* src_v,
  31. int src_stride_v,
  32. uint8_t* dst_y,
  33. int dst_stride_y,
  34. uint8_t* dst_u,
  35. int dst_stride_u,
  36. uint8_t* dst_v,
  37. int dst_stride_v,
  38. int src_y_width,
  39. int src_y_height,
  40. int src_uv_width,
  41. int src_uv_height) {
  42. const int dst_y_width = Abs(src_y_width);
  43. const int dst_y_height = Abs(src_y_height);
  44. const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
  45. const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
  46. if (src_uv_width == 0 || src_uv_height == 0) {
  47. return -1;
  48. }
  49. if (dst_y) {
  50. ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
  51. dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
  52. }
  53. ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
  54. dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
  55. ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
  56. dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
  57. return 0;
  58. }
  59. // Copy I420 with optional flipping.
  60. // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
  61. // is does row coalescing.
  62. LIBYUV_API
  63. int I420Copy(const uint8_t* src_y,
  64. int src_stride_y,
  65. const uint8_t* src_u,
  66. int src_stride_u,
  67. const uint8_t* src_v,
  68. int src_stride_v,
  69. uint8_t* dst_y,
  70. int dst_stride_y,
  71. uint8_t* dst_u,
  72. int dst_stride_u,
  73. uint8_t* dst_v,
  74. int dst_stride_v,
  75. int width,
  76. int height) {
  77. int halfwidth = (width + 1) >> 1;
  78. int halfheight = (height + 1) >> 1;
  79. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  80. return -1;
  81. }
  82. // Negative height means invert the image.
  83. if (height < 0) {
  84. height = -height;
  85. halfheight = (height + 1) >> 1;
  86. src_y = src_y + (height - 1) * src_stride_y;
  87. src_u = src_u + (halfheight - 1) * src_stride_u;
  88. src_v = src_v + (halfheight - 1) * src_stride_v;
  89. src_stride_y = -src_stride_y;
  90. src_stride_u = -src_stride_u;
  91. src_stride_v = -src_stride_v;
  92. }
  93. if (dst_y) {
  94. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  95. }
  96. // Copy UV planes.
  97. CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  98. CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  99. return 0;
  100. }
  101. // Copy I010 with optional flipping.
  102. LIBYUV_API
  103. int I010Copy(const uint16_t* src_y,
  104. int src_stride_y,
  105. const uint16_t* src_u,
  106. int src_stride_u,
  107. const uint16_t* src_v,
  108. int src_stride_v,
  109. uint16_t* dst_y,
  110. int dst_stride_y,
  111. uint16_t* dst_u,
  112. int dst_stride_u,
  113. uint16_t* dst_v,
  114. int dst_stride_v,
  115. int width,
  116. int height) {
  117. int halfwidth = (width + 1) >> 1;
  118. int halfheight = (height + 1) >> 1;
  119. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  120. return -1;
  121. }
  122. // Negative height means invert the image.
  123. if (height < 0) {
  124. height = -height;
  125. halfheight = (height + 1) >> 1;
  126. src_y = src_y + (height - 1) * src_stride_y;
  127. src_u = src_u + (halfheight - 1) * src_stride_u;
  128. src_v = src_v + (halfheight - 1) * src_stride_v;
  129. src_stride_y = -src_stride_y;
  130. src_stride_u = -src_stride_u;
  131. src_stride_v = -src_stride_v;
  132. }
  133. if (dst_y) {
  134. CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  135. }
  136. // Copy UV planes.
  137. CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  138. CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  139. return 0;
  140. }
  141. // Convert 10 bit YUV to 8 bit.
  142. LIBYUV_API
  143. int I010ToI420(const uint16_t* src_y,
  144. int src_stride_y,
  145. const uint16_t* src_u,
  146. int src_stride_u,
  147. const uint16_t* src_v,
  148. int src_stride_v,
  149. uint8_t* dst_y,
  150. int dst_stride_y,
  151. uint8_t* dst_u,
  152. int dst_stride_u,
  153. uint8_t* dst_v,
  154. int dst_stride_v,
  155. int width,
  156. int height) {
  157. int halfwidth = (width + 1) >> 1;
  158. int halfheight = (height + 1) >> 1;
  159. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  160. return -1;
  161. }
  162. // Negative height means invert the image.
  163. if (height < 0) {
  164. height = -height;
  165. halfheight = (height + 1) >> 1;
  166. src_y = src_y + (height - 1) * src_stride_y;
  167. src_u = src_u + (halfheight - 1) * src_stride_u;
  168. src_v = src_v + (halfheight - 1) * src_stride_v;
  169. src_stride_y = -src_stride_y;
  170. src_stride_u = -src_stride_u;
  171. src_stride_v = -src_stride_v;
  172. }
  173. // Convert Y plane.
  174. Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width,
  175. height);
  176. // Convert UV planes.
  177. Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth,
  178. halfheight);
  179. Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth,
  180. halfheight);
  181. return 0;
  182. }
  183. // 422 chroma is 1/2 width, 1x height
  184. // 420 chroma is 1/2 width, 1/2 height
  185. LIBYUV_API
  186. int I422ToI420(const uint8_t* src_y,
  187. int src_stride_y,
  188. const uint8_t* src_u,
  189. int src_stride_u,
  190. const uint8_t* src_v,
  191. int src_stride_v,
  192. uint8_t* dst_y,
  193. int dst_stride_y,
  194. uint8_t* dst_u,
  195. int dst_stride_u,
  196. uint8_t* dst_v,
  197. int dst_stride_v,
  198. int width,
  199. int height) {
  200. const int src_uv_width = SUBSAMPLE(width, 1, 1);
  201. return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
  202. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  203. dst_v, dst_stride_v, width, height, src_uv_width, height);
  204. }
  205. // TODO(fbarchard): Implement row conversion.
  206. LIBYUV_API
  207. int I422ToNV21(const uint8_t* src_y,
  208. int src_stride_y,
  209. const uint8_t* src_u,
  210. int src_stride_u,
  211. const uint8_t* src_v,
  212. int src_stride_v,
  213. uint8_t* dst_y,
  214. int dst_stride_y,
  215. uint8_t* dst_vu,
  216. int dst_stride_vu,
  217. int width,
  218. int height) {
  219. int halfwidth = (width + 1) >> 1;
  220. int halfheight = (height + 1) >> 1;
  221. // Negative height means invert the image.
  222. if (height < 0) {
  223. height = -height;
  224. halfheight = (height + 1) >> 1;
  225. src_y = src_y + (height - 1) * src_stride_y;
  226. src_u = src_u + (height - 1) * src_stride_u;
  227. src_v = src_v + (height - 1) * src_stride_v;
  228. src_stride_y = -src_stride_y;
  229. src_stride_u = -src_stride_u;
  230. src_stride_v = -src_stride_v;
  231. }
  232. // Allocate u and v buffers
  233. align_buffer_64(plane_u, halfwidth * halfheight * 2);
  234. uint8_t* plane_v = plane_u + halfwidth * halfheight;
  235. I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
  236. dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
  237. height);
  238. MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
  239. halfwidth, halfheight);
  240. free_aligned_buffer_64(plane_u);
  241. return 0;
  242. }
  243. #ifdef I422TONV21_ROW_VERSION
  244. // Unittest fails for this version.
  245. // 422 chroma is 1/2 width, 1x height
  246. // 420 chroma is 1/2 width, 1/2 height
  247. // Swap src_u and src_v to implement I422ToNV12
  248. LIBYUV_API
  249. int I422ToNV21(const uint8_t* src_y,
  250. int src_stride_y,
  251. const uint8_t* src_u,
  252. int src_stride_u,
  253. const uint8_t* src_v,
  254. int src_stride_v,
  255. uint8_t* dst_y,
  256. int dst_stride_y,
  257. uint8_t* dst_vu,
  258. int dst_stride_vu,
  259. int width,
  260. int height) {
  261. int y;
  262. void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
  263. uint8_t* dst_uv, int width) = MergeUVRow_C;
  264. void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr,
  265. ptrdiff_t src_stride, int dst_width,
  266. int source_y_fraction) = InterpolateRow_C;
  267. int halfwidth = (width + 1) >> 1;
  268. int halfheight = (height + 1) >> 1;
  269. if (!src_u || !src_v || !dst_vu || width <= 0 || height == 0) {
  270. return -1;
  271. }
  272. // Negative height means invert the image.
  273. if (height < 0) {
  274. height = -height;
  275. halfheight = (height + 1) >> 1;
  276. src_y = src_y + (height - 1) * src_stride_y;
  277. src_u = src_u + (halfheight - 1) * src_stride_u;
  278. src_v = src_v + (halfheight - 1) * src_stride_v;
  279. src_stride_y = -src_stride_y;
  280. src_stride_u = -src_stride_u;
  281. src_stride_v = -src_stride_v;
  282. }
  283. #if defined(HAS_MERGEUVROW_SSE2)
  284. if (TestCpuFlag(kCpuHasSSE2)) {
  285. MergeUVRow = MergeUVRow_Any_SSE2;
  286. if (IS_ALIGNED(halfwidth, 16)) {
  287. MergeUVRow = MergeUVRow_SSE2;
  288. }
  289. }
  290. #endif
  291. #if defined(HAS_MERGEUVROW_AVX2)
  292. if (TestCpuFlag(kCpuHasAVX2)) {
  293. MergeUVRow = MergeUVRow_Any_AVX2;
  294. if (IS_ALIGNED(halfwidth, 32)) {
  295. MergeUVRow = MergeUVRow_AVX2;
  296. }
  297. }
  298. #endif
  299. #if defined(HAS_MERGEUVROW_NEON)
  300. if (TestCpuFlag(kCpuHasNEON)) {
  301. MergeUVRow = MergeUVRow_Any_NEON;
  302. if (IS_ALIGNED(halfwidth, 16)) {
  303. MergeUVRow = MergeUVRow_NEON;
  304. }
  305. }
  306. #endif
  307. #if defined(HAS_MERGEUVROW_MMI)
  308. if (TestCpuFlag(kCpuHasMMI)) {
  309. MergeUVRow = MergeUVRow_Any_MMI;
  310. if (IS_ALIGNED(halfwidth, 8)) {
  311. MergeUVRow = MergeUVRow_MMI;
  312. }
  313. }
  314. #endif
  315. #if defined(HAS_MERGEUVROW_MSA)
  316. if (TestCpuFlag(kCpuHasMSA)) {
  317. MergeUVRow = MergeUVRow_Any_MSA;
  318. if (IS_ALIGNED(halfwidth, 16)) {
  319. MergeUVRow = MergeUVRow_MSA;
  320. }
  321. }
  322. #endif
  323. #if defined(HAS_INTERPOLATEROW_SSSE3)
  324. if (TestCpuFlag(kCpuHasSSSE3)) {
  325. InterpolateRow = InterpolateRow_Any_SSSE3;
  326. if (IS_ALIGNED(width, 16)) {
  327. InterpolateRow = InterpolateRow_SSSE3;
  328. }
  329. }
  330. #endif
  331. #if defined(HAS_INTERPOLATEROW_AVX2)
  332. if (TestCpuFlag(kCpuHasAVX2)) {
  333. InterpolateRow = InterpolateRow_Any_AVX2;
  334. if (IS_ALIGNED(width, 32)) {
  335. InterpolateRow = InterpolateRow_AVX2;
  336. }
  337. }
  338. #endif
  339. #if defined(HAS_INTERPOLATEROW_NEON)
  340. if (TestCpuFlag(kCpuHasNEON)) {
  341. InterpolateRow = InterpolateRow_Any_NEON;
  342. if (IS_ALIGNED(width, 16)) {
  343. InterpolateRow = InterpolateRow_NEON;
  344. }
  345. }
  346. #endif
  347. #if defined(HAS_INTERPOLATEROW_MMI)
  348. if (TestCpuFlag(kCpuHasMMI)) {
  349. InterpolateRow = InterpolateRow_Any_MMI;
  350. if (IS_ALIGNED(width, 8)) {
  351. InterpolateRow = InterpolateRow_MMI;
  352. }
  353. }
  354. #endif
  355. #if defined(HAS_INTERPOLATEROW_MSA)
  356. if (TestCpuFlag(kCpuHasMSA)) {
  357. InterpolateRow = InterpolateRow_Any_MSA;
  358. if (IS_ALIGNED(width, 32)) {
  359. InterpolateRow = InterpolateRow_MSA;
  360. }
  361. }
  362. #endif
  363. if (dst_y) {
  364. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
  365. }
  366. {
  367. // Allocate 2 rows of vu.
  368. int awidth = halfwidth * 2;
  369. align_buffer_64(row_vu_0, awidth * 2);
  370. uint8_t* row_vu_1 = row_vu_0 + awidth;
  371. for (y = 0; y < height - 1; y += 2) {
  372. MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
  373. MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
  374. halfwidth);
  375. InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
  376. src_u += src_stride_u * 2;
  377. src_v += src_stride_v * 2;
  378. dst_vu += dst_stride_vu;
  379. }
  380. if (height & 1) {
  381. MergeUVRow(src_v, src_u, dst_vu, halfwidth);
  382. }
  383. free_aligned_buffer_64(row_vu_0);
  384. }
  385. return 0;
  386. }
  387. #endif // I422TONV21_ROW_VERSION
  388. // 444 chroma is 1x width, 1x height
  389. // 420 chroma is 1/2 width, 1/2 height
  390. LIBYUV_API
  391. int I444ToI420(const uint8_t* src_y,
  392. int src_stride_y,
  393. const uint8_t* src_u,
  394. int src_stride_u,
  395. const uint8_t* src_v,
  396. int src_stride_v,
  397. uint8_t* dst_y,
  398. int dst_stride_y,
  399. uint8_t* dst_u,
  400. int dst_stride_u,
  401. uint8_t* dst_v,
  402. int dst_stride_v,
  403. int width,
  404. int height) {
  405. return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
  406. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  407. dst_v, dst_stride_v, width, height, width, height);
  408. }
  409. LIBYUV_API
  410. int I444ToNV12(const uint8_t* src_y,
  411. int src_stride_y,
  412. const uint8_t* src_u,
  413. int src_stride_u,
  414. const uint8_t* src_v,
  415. int src_stride_v,
  416. uint8_t* dst_y,
  417. int dst_stride_y,
  418. uint8_t* dst_uv,
  419. int dst_stride_uv,
  420. int width,
  421. int height) {
  422. if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
  423. height == 0) {
  424. return -1;
  425. }
  426. // Negative height means invert the image.
  427. if (height < 0) {
  428. height = -height;
  429. src_y = src_y + (height - 1) * src_stride_y;
  430. src_u = src_u + (height - 1) * src_stride_u;
  431. src_v = src_v + (height - 1) * src_stride_v;
  432. src_stride_y = -src_stride_y;
  433. src_stride_u = -src_stride_u;
  434. src_stride_v = -src_stride_v;
  435. }
  436. if (dst_y) {
  437. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  438. }
  439. HalfMergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
  440. dst_stride_uv, width, height);
  441. return 0;
  442. }
  443. LIBYUV_API
  444. int I444ToNV21(const uint8_t* src_y,
  445. int src_stride_y,
  446. const uint8_t* src_u,
  447. int src_stride_u,
  448. const uint8_t* src_v,
  449. int src_stride_v,
  450. uint8_t* dst_y,
  451. int dst_stride_y,
  452. uint8_t* dst_vu,
  453. int dst_stride_vu,
  454. int width,
  455. int height) {
  456. return I444ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
  457. src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
  458. width, height);
  459. }
  460. // I400 is greyscale typically used in MJPG
  461. LIBYUV_API
  462. int I400ToI420(const uint8_t* src_y,
  463. int src_stride_y,
  464. uint8_t* dst_y,
  465. int dst_stride_y,
  466. uint8_t* dst_u,
  467. int dst_stride_u,
  468. uint8_t* dst_v,
  469. int dst_stride_v,
  470. int width,
  471. int height) {
  472. int halfwidth = (width + 1) >> 1;
  473. int halfheight = (height + 1) >> 1;
  474. if (!dst_u || !dst_v || width <= 0 || height == 0) {
  475. return -1;
  476. }
  477. // Negative height means invert the image.
  478. if (height < 0) {
  479. height = -height;
  480. halfheight = (height + 1) >> 1;
  481. src_y = src_y + (height - 1) * src_stride_y;
  482. src_stride_y = -src_stride_y;
  483. }
  484. if (dst_y) {
  485. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  486. }
  487. SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
  488. SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
  489. return 0;
  490. }
  491. // I400 is greyscale typically used in MJPG
  492. LIBYUV_API
  493. int I400ToNV21(const uint8_t* src_y,
  494. int src_stride_y,
  495. uint8_t* dst_y,
  496. int dst_stride_y,
  497. uint8_t* dst_vu,
  498. int dst_stride_vu,
  499. int width,
  500. int height) {
  501. int halfwidth = (width + 1) >> 1;
  502. int halfheight = (height + 1) >> 1;
  503. if (!dst_vu || width <= 0 || height == 0) {
  504. return -1;
  505. }
  506. // Negative height means invert the image.
  507. if (height < 0) {
  508. height = -height;
  509. halfheight = (height + 1) >> 1;
  510. src_y = src_y + (height - 1) * src_stride_y;
  511. src_stride_y = -src_stride_y;
  512. }
  513. if (dst_y) {
  514. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  515. }
  516. SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
  517. return 0;
  518. }
  519. // Convert NV12 to I420.
  520. // TODO(fbarchard): Consider inverting destination. Faster on ARM with prfm.
  521. LIBYUV_API
  522. int NV12ToI420(const uint8_t* src_y,
  523. int src_stride_y,
  524. const uint8_t* src_uv,
  525. int src_stride_uv,
  526. uint8_t* dst_y,
  527. int dst_stride_y,
  528. uint8_t* dst_u,
  529. int dst_stride_u,
  530. uint8_t* dst_v,
  531. int dst_stride_v,
  532. int width,
  533. int height) {
  534. int halfwidth = (width + 1) >> 1;
  535. int halfheight = (height + 1) >> 1;
  536. if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
  537. return -1;
  538. }
  539. // Negative height means invert the image.
  540. if (height < 0) {
  541. height = -height;
  542. halfheight = (height + 1) >> 1;
  543. src_y = src_y + (height - 1) * src_stride_y;
  544. src_uv = src_uv + (halfheight - 1) * src_stride_uv;
  545. src_stride_y = -src_stride_y;
  546. src_stride_uv = -src_stride_uv;
  547. }
  548. // Coalesce rows.
  549. if (src_stride_y == width && dst_stride_y == width) {
  550. width *= height;
  551. height = 1;
  552. src_stride_y = dst_stride_y = 0;
  553. }
  554. // Coalesce rows.
  555. if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
  556. dst_stride_v == halfwidth) {
  557. halfwidth *= halfheight;
  558. halfheight = 1;
  559. src_stride_uv = dst_stride_u = dst_stride_v = 0;
  560. }
  561. if (dst_y) {
  562. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  563. }
  564. // Split UV plane - NV12 / NV21
  565. SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
  566. halfwidth, halfheight);
  567. return 0;
  568. }
  569. // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
  570. LIBYUV_API
  571. int NV21ToI420(const uint8_t* src_y,
  572. int src_stride_y,
  573. const uint8_t* src_vu,
  574. int src_stride_vu,
  575. uint8_t* dst_y,
  576. int dst_stride_y,
  577. uint8_t* dst_u,
  578. int dst_stride_u,
  579. uint8_t* dst_v,
  580. int dst_stride_v,
  581. int width,
  582. int height) {
  583. return NV12ToI420(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
  584. dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u,
  585. width, height);
  586. }
  587. // Convert YUY2 to I420.
  588. LIBYUV_API
  589. int YUY2ToI420(const uint8_t* src_yuy2,
  590. int src_stride_yuy2,
  591. uint8_t* dst_y,
  592. int dst_stride_y,
  593. uint8_t* dst_u,
  594. int dst_stride_u,
  595. uint8_t* dst_v,
  596. int dst_stride_v,
  597. int width,
  598. int height) {
  599. int y;
  600. void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
  601. uint8_t* dst_u, uint8_t* dst_v, int width) =
  602. YUY2ToUVRow_C;
  603. void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
  604. YUY2ToYRow_C;
  605. // Negative height means invert the image.
  606. if (height < 0) {
  607. height = -height;
  608. src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
  609. src_stride_yuy2 = -src_stride_yuy2;
  610. }
  611. #if defined(HAS_YUY2TOYROW_SSE2)
  612. if (TestCpuFlag(kCpuHasSSE2)) {
  613. YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
  614. YUY2ToYRow = YUY2ToYRow_Any_SSE2;
  615. if (IS_ALIGNED(width, 16)) {
  616. YUY2ToUVRow = YUY2ToUVRow_SSE2;
  617. YUY2ToYRow = YUY2ToYRow_SSE2;
  618. }
  619. }
  620. #endif
  621. #if defined(HAS_YUY2TOYROW_AVX2)
  622. if (TestCpuFlag(kCpuHasAVX2)) {
  623. YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
  624. YUY2ToYRow = YUY2ToYRow_Any_AVX2;
  625. if (IS_ALIGNED(width, 32)) {
  626. YUY2ToUVRow = YUY2ToUVRow_AVX2;
  627. YUY2ToYRow = YUY2ToYRow_AVX2;
  628. }
  629. }
  630. #endif
  631. #if defined(HAS_YUY2TOYROW_NEON)
  632. if (TestCpuFlag(kCpuHasNEON)) {
  633. YUY2ToYRow = YUY2ToYRow_Any_NEON;
  634. YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
  635. if (IS_ALIGNED(width, 16)) {
  636. YUY2ToYRow = YUY2ToYRow_NEON;
  637. YUY2ToUVRow = YUY2ToUVRow_NEON;
  638. }
  639. }
  640. #endif
  641. #if defined(HAS_YUY2TOYROW_MMI) && defined(HAS_YUY2TOUVROW_MMI)
  642. if (TestCpuFlag(kCpuHasMMI)) {
  643. YUY2ToYRow = YUY2ToYRow_Any_MMI;
  644. YUY2ToUVRow = YUY2ToUVRow_Any_MMI;
  645. if (IS_ALIGNED(width, 8)) {
  646. YUY2ToYRow = YUY2ToYRow_MMI;
  647. if (IS_ALIGNED(width, 16)) {
  648. YUY2ToUVRow = YUY2ToUVRow_MMI;
  649. }
  650. }
  651. }
  652. #endif
  653. #if defined(HAS_YUY2TOYROW_MSA) && defined(HAS_YUY2TOUVROW_MSA)
  654. if (TestCpuFlag(kCpuHasMSA)) {
  655. YUY2ToYRow = YUY2ToYRow_Any_MSA;
  656. YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
  657. if (IS_ALIGNED(width, 32)) {
  658. YUY2ToYRow = YUY2ToYRow_MSA;
  659. YUY2ToUVRow = YUY2ToUVRow_MSA;
  660. }
  661. }
  662. #endif
  663. for (y = 0; y < height - 1; y += 2) {
  664. YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
  665. YUY2ToYRow(src_yuy2, dst_y, width);
  666. YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
  667. src_yuy2 += src_stride_yuy2 * 2;
  668. dst_y += dst_stride_y * 2;
  669. dst_u += dst_stride_u;
  670. dst_v += dst_stride_v;
  671. }
  672. if (height & 1) {
  673. YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
  674. YUY2ToYRow(src_yuy2, dst_y, width);
  675. }
  676. return 0;
  677. }
  678. // Convert UYVY to I420.
  679. LIBYUV_API
  680. int UYVYToI420(const uint8_t* src_uyvy,
  681. int src_stride_uyvy,
  682. uint8_t* dst_y,
  683. int dst_stride_y,
  684. uint8_t* dst_u,
  685. int dst_stride_u,
  686. uint8_t* dst_v,
  687. int dst_stride_v,
  688. int width,
  689. int height) {
  690. int y;
  691. void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
  692. uint8_t* dst_u, uint8_t* dst_v, int width) =
  693. UYVYToUVRow_C;
  694. void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
  695. UYVYToYRow_C;
  696. // Negative height means invert the image.
  697. if (height < 0) {
  698. height = -height;
  699. src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
  700. src_stride_uyvy = -src_stride_uyvy;
  701. }
  702. #if defined(HAS_UYVYTOYROW_SSE2)
  703. if (TestCpuFlag(kCpuHasSSE2)) {
  704. UYVYToUVRow = UYVYToUVRow_Any_SSE2;
  705. UYVYToYRow = UYVYToYRow_Any_SSE2;
  706. if (IS_ALIGNED(width, 16)) {
  707. UYVYToUVRow = UYVYToUVRow_SSE2;
  708. UYVYToYRow = UYVYToYRow_SSE2;
  709. }
  710. }
  711. #endif
  712. #if defined(HAS_UYVYTOYROW_AVX2)
  713. if (TestCpuFlag(kCpuHasAVX2)) {
  714. UYVYToUVRow = UYVYToUVRow_Any_AVX2;
  715. UYVYToYRow = UYVYToYRow_Any_AVX2;
  716. if (IS_ALIGNED(width, 32)) {
  717. UYVYToUVRow = UYVYToUVRow_AVX2;
  718. UYVYToYRow = UYVYToYRow_AVX2;
  719. }
  720. }
  721. #endif
  722. #if defined(HAS_UYVYTOYROW_NEON)
  723. if (TestCpuFlag(kCpuHasNEON)) {
  724. UYVYToYRow = UYVYToYRow_Any_NEON;
  725. UYVYToUVRow = UYVYToUVRow_Any_NEON;
  726. if (IS_ALIGNED(width, 16)) {
  727. UYVYToYRow = UYVYToYRow_NEON;
  728. UYVYToUVRow = UYVYToUVRow_NEON;
  729. }
  730. }
  731. #endif
  732. #if defined(HAS_UYVYTOYROW_MMI) && defined(HAS_UYVYTOUVROW_MMI)
  733. if (TestCpuFlag(kCpuHasMMI)) {
  734. UYVYToYRow = UYVYToYRow_Any_MMI;
  735. UYVYToUVRow = UYVYToUVRow_Any_MMI;
  736. if (IS_ALIGNED(width, 16)) {
  737. UYVYToYRow = UYVYToYRow_MMI;
  738. UYVYToUVRow = UYVYToUVRow_MMI;
  739. }
  740. }
  741. #endif
  742. #if defined(HAS_UYVYTOYROW_MSA)
  743. if (TestCpuFlag(kCpuHasMSA)) {
  744. UYVYToYRow = UYVYToYRow_Any_MSA;
  745. UYVYToUVRow = UYVYToUVRow_Any_MSA;
  746. if (IS_ALIGNED(width, 32)) {
  747. UYVYToYRow = UYVYToYRow_MSA;
  748. UYVYToUVRow = UYVYToUVRow_MSA;
  749. }
  750. }
  751. #endif
  752. for (y = 0; y < height - 1; y += 2) {
  753. UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
  754. UYVYToYRow(src_uyvy, dst_y, width);
  755. UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
  756. src_uyvy += src_stride_uyvy * 2;
  757. dst_y += dst_stride_y * 2;
  758. dst_u += dst_stride_u;
  759. dst_v += dst_stride_v;
  760. }
  761. if (height & 1) {
  762. UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
  763. UYVYToYRow(src_uyvy, dst_y, width);
  764. }
  765. return 0;
  766. }
  767. // Convert AYUV to NV12.
  768. LIBYUV_API
  769. int AYUVToNV12(const uint8_t* src_ayuv,
  770. int src_stride_ayuv,
  771. uint8_t* dst_y,
  772. int dst_stride_y,
  773. uint8_t* dst_uv,
  774. int dst_stride_uv,
  775. int width,
  776. int height) {
  777. int y;
  778. void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
  779. uint8_t* dst_uv, int width) = AYUVToUVRow_C;
  780. void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
  781. AYUVToYRow_C;
  782. // Negative height means invert the image.
  783. if (height < 0) {
  784. height = -height;
  785. src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
  786. src_stride_ayuv = -src_stride_ayuv;
  787. }
  788. // place holders for future intel code
  789. #if defined(HAS_AYUVTOYROW_SSE2)
  790. if (TestCpuFlag(kCpuHasSSE2)) {
  791. AYUVToUVRow = AYUVToUVRow_Any_SSE2;
  792. AYUVToYRow = AYUVToYRow_Any_SSE2;
  793. if (IS_ALIGNED(width, 16)) {
  794. AYUVToUVRow = AYUVToUVRow_SSE2;
  795. AYUVToYRow = AYUVToYRow_SSE2;
  796. }
  797. }
  798. #endif
  799. #if defined(HAS_AYUVTOYROW_AVX2)
  800. if (TestCpuFlag(kCpuHasAVX2)) {
  801. AYUVToUVRow = AYUVToUVRow_Any_AVX2;
  802. AYUVToYRow = AYUVToYRow_Any_AVX2;
  803. if (IS_ALIGNED(width, 32)) {
  804. AYUVToUVRow = AYUVToUVRow_AVX2;
  805. AYUVToYRow = AYUVToYRow_AVX2;
  806. }
  807. }
  808. #endif
  809. #if defined(HAS_AYUVTOYROW_NEON)
  810. if (TestCpuFlag(kCpuHasNEON)) {
  811. AYUVToYRow = AYUVToYRow_Any_NEON;
  812. AYUVToUVRow = AYUVToUVRow_Any_NEON;
  813. if (IS_ALIGNED(width, 16)) {
  814. AYUVToYRow = AYUVToYRow_NEON;
  815. AYUVToUVRow = AYUVToUVRow_NEON;
  816. }
  817. }
  818. #endif
  819. for (y = 0; y < height - 1; y += 2) {
  820. AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
  821. AYUVToYRow(src_ayuv, dst_y, width);
  822. AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
  823. src_ayuv += src_stride_ayuv * 2;
  824. dst_y += dst_stride_y * 2;
  825. dst_uv += dst_stride_uv;
  826. }
  827. if (height & 1) {
  828. AYUVToUVRow(src_ayuv, 0, dst_uv, width);
  829. AYUVToYRow(src_ayuv, dst_y, width);
  830. }
  831. return 0;
  832. }
  833. // Convert AYUV to NV21.
  834. LIBYUV_API
  835. int AYUVToNV21(const uint8_t* src_ayuv,
  836. int src_stride_ayuv,
  837. uint8_t* dst_y,
  838. int dst_stride_y,
  839. uint8_t* dst_vu,
  840. int dst_stride_vu,
  841. int width,
  842. int height) {
  843. int y;
  844. void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
  845. uint8_t* dst_vu, int width) = AYUVToVURow_C;
  846. void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
  847. AYUVToYRow_C;
  848. // Negative height means invert the image.
  849. if (height < 0) {
  850. height = -height;
  851. src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
  852. src_stride_ayuv = -src_stride_ayuv;
  853. }
  854. // place holders for future intel code
  855. #if defined(HAS_AYUVTOYROW_SSE2)
  856. if (TestCpuFlag(kCpuHasSSE2)) {
  857. AYUVToVURow = AYUVToVURow_Any_SSE2;
  858. AYUVToYRow = AYUVToYRow_Any_SSE2;
  859. if (IS_ALIGNED(width, 16)) {
  860. AYUVToVURow = AYUVToVURow_SSE2;
  861. AYUVToYRow = AYUVToYRow_SSE2;
  862. }
  863. }
  864. #endif
  865. #if defined(HAS_AYUVTOYROW_AVX2)
  866. if (TestCpuFlag(kCpuHasAVX2)) {
  867. AYUVToVURow = AYUVToVURow_Any_AVX2;
  868. AYUVToYRow = AYUVToYRow_Any_AVX2;
  869. if (IS_ALIGNED(width, 32)) {
  870. AYUVToVURow = AYUVToVURow_AVX2;
  871. AYUVToYRow = AYUVToYRow_AVX2;
  872. }
  873. }
  874. #endif
  875. #if defined(HAS_AYUVTOYROW_NEON)
  876. if (TestCpuFlag(kCpuHasNEON)) {
  877. AYUVToYRow = AYUVToYRow_Any_NEON;
  878. AYUVToVURow = AYUVToVURow_Any_NEON;
  879. if (IS_ALIGNED(width, 16)) {
  880. AYUVToYRow = AYUVToYRow_NEON;
  881. AYUVToVURow = AYUVToVURow_NEON;
  882. }
  883. }
  884. #endif
  885. for (y = 0; y < height - 1; y += 2) {
  886. AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
  887. AYUVToYRow(src_ayuv, dst_y, width);
  888. AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
  889. src_ayuv += src_stride_ayuv * 2;
  890. dst_y += dst_stride_y * 2;
  891. dst_vu += dst_stride_vu;
  892. }
  893. if (height & 1) {
  894. AYUVToVURow(src_ayuv, 0, dst_vu, width);
  895. AYUVToYRow(src_ayuv, dst_y, width);
  896. }
  897. return 0;
  898. }
  899. // Convert ARGB to I420.
  900. LIBYUV_API
  901. int ARGBToI420(const uint8_t* src_argb,
  902. int src_stride_argb,
  903. uint8_t* dst_y,
  904. int dst_stride_y,
  905. uint8_t* dst_u,
  906. int dst_stride_u,
  907. uint8_t* dst_v,
  908. int dst_stride_v,
  909. int width,
  910. int height) {
  911. int y;
  912. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  913. uint8_t* dst_u, uint8_t* dst_v, int width) =
  914. ARGBToUVRow_C;
  915. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  916. ARGBToYRow_C;
  917. if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  918. return -1;
  919. }
  920. // Negative height means invert the image.
  921. if (height < 0) {
  922. height = -height;
  923. src_argb = src_argb + (height - 1) * src_stride_argb;
  924. src_stride_argb = -src_stride_argb;
  925. }
  926. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  927. if (TestCpuFlag(kCpuHasSSSE3)) {
  928. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  929. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  930. if (IS_ALIGNED(width, 16)) {
  931. ARGBToUVRow = ARGBToUVRow_SSSE3;
  932. ARGBToYRow = ARGBToYRow_SSSE3;
  933. }
  934. }
  935. #endif
  936. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  937. if (TestCpuFlag(kCpuHasAVX2)) {
  938. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  939. ARGBToYRow = ARGBToYRow_Any_AVX2;
  940. if (IS_ALIGNED(width, 32)) {
  941. ARGBToUVRow = ARGBToUVRow_AVX2;
  942. ARGBToYRow = ARGBToYRow_AVX2;
  943. }
  944. }
  945. #endif
  946. #if defined(HAS_ARGBTOYROW_NEON)
  947. if (TestCpuFlag(kCpuHasNEON)) {
  948. ARGBToYRow = ARGBToYRow_Any_NEON;
  949. if (IS_ALIGNED(width, 8)) {
  950. ARGBToYRow = ARGBToYRow_NEON;
  951. }
  952. }
  953. #endif
  954. #if defined(HAS_ARGBTOUVROW_NEON)
  955. if (TestCpuFlag(kCpuHasNEON)) {
  956. ARGBToUVRow = ARGBToUVRow_Any_NEON;
  957. if (IS_ALIGNED(width, 16)) {
  958. ARGBToUVRow = ARGBToUVRow_NEON;
  959. }
  960. }
  961. #endif
  962. #if defined(HAS_ARGBTOYROW_MMI) && defined(HAS_ARGBTOUVROW_MMI)
  963. if (TestCpuFlag(kCpuHasMMI)) {
  964. ARGBToYRow = ARGBToYRow_Any_MMI;
  965. ARGBToUVRow = ARGBToUVRow_Any_MMI;
  966. if (IS_ALIGNED(width, 8)) {
  967. ARGBToYRow = ARGBToYRow_MMI;
  968. }
  969. if (IS_ALIGNED(width, 16)) {
  970. ARGBToUVRow = ARGBToUVRow_MMI;
  971. }
  972. }
  973. #endif
  974. #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
  975. if (TestCpuFlag(kCpuHasMSA)) {
  976. ARGBToYRow = ARGBToYRow_Any_MSA;
  977. ARGBToUVRow = ARGBToUVRow_Any_MSA;
  978. if (IS_ALIGNED(width, 16)) {
  979. ARGBToYRow = ARGBToYRow_MSA;
  980. }
  981. if (IS_ALIGNED(width, 32)) {
  982. ARGBToUVRow = ARGBToUVRow_MSA;
  983. }
  984. }
  985. #endif
  986. for (y = 0; y < height - 1; y += 2) {
  987. ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
  988. ARGBToYRow(src_argb, dst_y, width);
  989. ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
  990. src_argb += src_stride_argb * 2;
  991. dst_y += dst_stride_y * 2;
  992. dst_u += dst_stride_u;
  993. dst_v += dst_stride_v;
  994. }
  995. if (height & 1) {
  996. ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
  997. ARGBToYRow(src_argb, dst_y, width);
  998. }
  999. return 0;
  1000. }
  1001. // Convert BGRA to I420.
  1002. LIBYUV_API
  1003. int BGRAToI420(const uint8_t* src_bgra,
  1004. int src_stride_bgra,
  1005. uint8_t* dst_y,
  1006. int dst_stride_y,
  1007. uint8_t* dst_u,
  1008. int dst_stride_u,
  1009. uint8_t* dst_v,
  1010. int dst_stride_v,
  1011. int width,
  1012. int height) {
  1013. int y;
  1014. void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
  1015. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1016. BGRAToUVRow_C;
  1017. void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
  1018. BGRAToYRow_C;
  1019. if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1020. return -1;
  1021. }
  1022. // Negative height means invert the image.
  1023. if (height < 0) {
  1024. height = -height;
  1025. src_bgra = src_bgra + (height - 1) * src_stride_bgra;
  1026. src_stride_bgra = -src_stride_bgra;
  1027. }
  1028. #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
  1029. if (TestCpuFlag(kCpuHasSSSE3)) {
  1030. BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
  1031. BGRAToYRow = BGRAToYRow_Any_SSSE3;
  1032. if (IS_ALIGNED(width, 16)) {
  1033. BGRAToUVRow = BGRAToUVRow_SSSE3;
  1034. BGRAToYRow = BGRAToYRow_SSSE3;
  1035. }
  1036. }
  1037. #endif
  1038. #if defined(HAS_BGRATOYROW_NEON)
  1039. if (TestCpuFlag(kCpuHasNEON)) {
  1040. BGRAToYRow = BGRAToYRow_Any_NEON;
  1041. if (IS_ALIGNED(width, 8)) {
  1042. BGRAToYRow = BGRAToYRow_NEON;
  1043. }
  1044. }
  1045. #endif
  1046. #if defined(HAS_BGRATOUVROW_NEON)
  1047. if (TestCpuFlag(kCpuHasNEON)) {
  1048. BGRAToUVRow = BGRAToUVRow_Any_NEON;
  1049. if (IS_ALIGNED(width, 16)) {
  1050. BGRAToUVRow = BGRAToUVRow_NEON;
  1051. }
  1052. }
  1053. #endif
  1054. #if defined(HAS_BGRATOYROW_MMI) && defined(HAS_BGRATOUVROW_MMI)
  1055. if (TestCpuFlag(kCpuHasMMI)) {
  1056. BGRAToYRow = BGRAToYRow_Any_MMI;
  1057. BGRAToUVRow = BGRAToUVRow_Any_MMI;
  1058. if (IS_ALIGNED(width, 8)) {
  1059. BGRAToYRow = BGRAToYRow_MMI;
  1060. }
  1061. if (IS_ALIGNED(width, 16)) {
  1062. BGRAToUVRow = BGRAToUVRow_MMI;
  1063. }
  1064. }
  1065. #endif
  1066. #if defined(HAS_BGRATOYROW_MSA) && defined(HAS_BGRATOUVROW_MSA)
  1067. if (TestCpuFlag(kCpuHasMSA)) {
  1068. BGRAToYRow = BGRAToYRow_Any_MSA;
  1069. BGRAToUVRow = BGRAToUVRow_Any_MSA;
  1070. if (IS_ALIGNED(width, 16)) {
  1071. BGRAToYRow = BGRAToYRow_MSA;
  1072. BGRAToUVRow = BGRAToUVRow_MSA;
  1073. }
  1074. }
  1075. #endif
  1076. for (y = 0; y < height - 1; y += 2) {
  1077. BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
  1078. BGRAToYRow(src_bgra, dst_y, width);
  1079. BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
  1080. src_bgra += src_stride_bgra * 2;
  1081. dst_y += dst_stride_y * 2;
  1082. dst_u += dst_stride_u;
  1083. dst_v += dst_stride_v;
  1084. }
  1085. if (height & 1) {
  1086. BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
  1087. BGRAToYRow(src_bgra, dst_y, width);
  1088. }
  1089. return 0;
  1090. }
  1091. // Convert ABGR to I420.
  1092. LIBYUV_API
  1093. int ABGRToI420(const uint8_t* src_abgr,
  1094. int src_stride_abgr,
  1095. uint8_t* dst_y,
  1096. int dst_stride_y,
  1097. uint8_t* dst_u,
  1098. int dst_stride_u,
  1099. uint8_t* dst_v,
  1100. int dst_stride_v,
  1101. int width,
  1102. int height) {
  1103. int y;
  1104. void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
  1105. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1106. ABGRToUVRow_C;
  1107. void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
  1108. ABGRToYRow_C;
  1109. if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1110. return -1;
  1111. }
  1112. // Negative height means invert the image.
  1113. if (height < 0) {
  1114. height = -height;
  1115. src_abgr = src_abgr + (height - 1) * src_stride_abgr;
  1116. src_stride_abgr = -src_stride_abgr;
  1117. }
  1118. #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
  1119. if (TestCpuFlag(kCpuHasSSSE3)) {
  1120. ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
  1121. ABGRToYRow = ABGRToYRow_Any_SSSE3;
  1122. if (IS_ALIGNED(width, 16)) {
  1123. ABGRToUVRow = ABGRToUVRow_SSSE3;
  1124. ABGRToYRow = ABGRToYRow_SSSE3;
  1125. }
  1126. }
  1127. #endif
  1128. #if defined(HAS_ABGRTOYROW_AVX2) && defined(HAS_ABGRTOUVROW_AVX2)
  1129. if (TestCpuFlag(kCpuHasAVX2)) {
  1130. ABGRToUVRow = ABGRToUVRow_Any_AVX2;
  1131. ABGRToYRow = ABGRToYRow_Any_AVX2;
  1132. if (IS_ALIGNED(width, 32)) {
  1133. ABGRToUVRow = ABGRToUVRow_AVX2;
  1134. ABGRToYRow = ABGRToYRow_AVX2;
  1135. }
  1136. }
  1137. #endif
  1138. #if defined(HAS_ABGRTOYROW_NEON)
  1139. if (TestCpuFlag(kCpuHasNEON)) {
  1140. ABGRToYRow = ABGRToYRow_Any_NEON;
  1141. if (IS_ALIGNED(width, 8)) {
  1142. ABGRToYRow = ABGRToYRow_NEON;
  1143. }
  1144. }
  1145. #endif
  1146. #if defined(HAS_ABGRTOUVROW_NEON)
  1147. if (TestCpuFlag(kCpuHasNEON)) {
  1148. ABGRToUVRow = ABGRToUVRow_Any_NEON;
  1149. if (IS_ALIGNED(width, 16)) {
  1150. ABGRToUVRow = ABGRToUVRow_NEON;
  1151. }
  1152. }
  1153. #endif
  1154. #if defined(HAS_ABGRTOYROW_MMI) && defined(HAS_ABGRTOUVROW_MMI)
  1155. if (TestCpuFlag(kCpuHasMMI)) {
  1156. ABGRToYRow = ABGRToYRow_Any_MMI;
  1157. ABGRToUVRow = ABGRToUVRow_Any_MMI;
  1158. if (IS_ALIGNED(width, 8)) {
  1159. ABGRToYRow = ABGRToYRow_MMI;
  1160. }
  1161. if (IS_ALIGNED(width, 16)) {
  1162. ABGRToUVRow = ABGRToUVRow_MMI;
  1163. }
  1164. }
  1165. #endif
  1166. #if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
  1167. if (TestCpuFlag(kCpuHasMSA)) {
  1168. ABGRToYRow = ABGRToYRow_Any_MSA;
  1169. ABGRToUVRow = ABGRToUVRow_Any_MSA;
  1170. if (IS_ALIGNED(width, 16)) {
  1171. ABGRToYRow = ABGRToYRow_MSA;
  1172. ABGRToUVRow = ABGRToUVRow_MSA;
  1173. }
  1174. }
  1175. #endif
  1176. for (y = 0; y < height - 1; y += 2) {
  1177. ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
  1178. ABGRToYRow(src_abgr, dst_y, width);
  1179. ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
  1180. src_abgr += src_stride_abgr * 2;
  1181. dst_y += dst_stride_y * 2;
  1182. dst_u += dst_stride_u;
  1183. dst_v += dst_stride_v;
  1184. }
  1185. if (height & 1) {
  1186. ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
  1187. ABGRToYRow(src_abgr, dst_y, width);
  1188. }
  1189. return 0;
  1190. }
  1191. // Convert RGBA to I420.
  1192. LIBYUV_API
  1193. int RGBAToI420(const uint8_t* src_rgba,
  1194. int src_stride_rgba,
  1195. uint8_t* dst_y,
  1196. int dst_stride_y,
  1197. uint8_t* dst_u,
  1198. int dst_stride_u,
  1199. uint8_t* dst_v,
  1200. int dst_stride_v,
  1201. int width,
  1202. int height) {
  1203. int y;
  1204. void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
  1205. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1206. RGBAToUVRow_C;
  1207. void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
  1208. RGBAToYRow_C;
  1209. if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1210. return -1;
  1211. }
  1212. // Negative height means invert the image.
  1213. if (height < 0) {
  1214. height = -height;
  1215. src_rgba = src_rgba + (height - 1) * src_stride_rgba;
  1216. src_stride_rgba = -src_stride_rgba;
  1217. }
  1218. #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
  1219. if (TestCpuFlag(kCpuHasSSSE3)) {
  1220. RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
  1221. RGBAToYRow = RGBAToYRow_Any_SSSE3;
  1222. if (IS_ALIGNED(width, 16)) {
  1223. RGBAToUVRow = RGBAToUVRow_SSSE3;
  1224. RGBAToYRow = RGBAToYRow_SSSE3;
  1225. }
  1226. }
  1227. #endif
  1228. #if defined(HAS_RGBATOYROW_NEON)
  1229. if (TestCpuFlag(kCpuHasNEON)) {
  1230. RGBAToYRow = RGBAToYRow_Any_NEON;
  1231. if (IS_ALIGNED(width, 8)) {
  1232. RGBAToYRow = RGBAToYRow_NEON;
  1233. }
  1234. }
  1235. #endif
  1236. #if defined(HAS_RGBATOUVROW_NEON)
  1237. if (TestCpuFlag(kCpuHasNEON)) {
  1238. RGBAToUVRow = RGBAToUVRow_Any_NEON;
  1239. if (IS_ALIGNED(width, 16)) {
  1240. RGBAToUVRow = RGBAToUVRow_NEON;
  1241. }
  1242. }
  1243. #endif
  1244. #if defined(HAS_RGBATOYROW_MMI) && defined(HAS_RGBATOUVROW_MMI)
  1245. if (TestCpuFlag(kCpuHasMMI)) {
  1246. RGBAToYRow = RGBAToYRow_Any_MMI;
  1247. RGBAToUVRow = RGBAToUVRow_Any_MMI;
  1248. if (IS_ALIGNED(width, 8)) {
  1249. RGBAToYRow = RGBAToYRow_MMI;
  1250. }
  1251. if (IS_ALIGNED(width, 16)) {
  1252. RGBAToUVRow = RGBAToUVRow_MMI;
  1253. }
  1254. }
  1255. #endif
  1256. #if defined(HAS_RGBATOYROW_MSA) && defined(HAS_RGBATOUVROW_MSA)
  1257. if (TestCpuFlag(kCpuHasMSA)) {
  1258. RGBAToYRow = RGBAToYRow_Any_MSA;
  1259. RGBAToUVRow = RGBAToUVRow_Any_MSA;
  1260. if (IS_ALIGNED(width, 16)) {
  1261. RGBAToYRow = RGBAToYRow_MSA;
  1262. RGBAToUVRow = RGBAToUVRow_MSA;
  1263. }
  1264. }
  1265. #endif
  1266. for (y = 0; y < height - 1; y += 2) {
  1267. RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
  1268. RGBAToYRow(src_rgba, dst_y, width);
  1269. RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
  1270. src_rgba += src_stride_rgba * 2;
  1271. dst_y += dst_stride_y * 2;
  1272. dst_u += dst_stride_u;
  1273. dst_v += dst_stride_v;
  1274. }
  1275. if (height & 1) {
  1276. RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
  1277. RGBAToYRow(src_rgba, dst_y, width);
  1278. }
  1279. return 0;
  1280. }
  1281. // Convert RGB24 to I420.
  1282. LIBYUV_API
  1283. int RGB24ToI420(const uint8_t* src_rgb24,
  1284. int src_stride_rgb24,
  1285. uint8_t* dst_y,
  1286. int dst_stride_y,
  1287. uint8_t* dst_u,
  1288. int dst_stride_u,
  1289. uint8_t* dst_v,
  1290. int dst_stride_v,
  1291. int width,
  1292. int height) {
  1293. int y;
  1294. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
  1295. defined(HAS_RGB24TOYROW_MMI))
  1296. void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
  1297. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1298. RGB24ToUVRow_C;
  1299. void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
  1300. RGB24ToYRow_C;
  1301. #else
  1302. void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
  1303. RGB24ToARGBRow_C;
  1304. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1305. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1306. ARGBToUVRow_C;
  1307. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1308. ARGBToYRow_C;
  1309. #endif
  1310. if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1311. return -1;
  1312. }
  1313. // Negative height means invert the image.
  1314. if (height < 0) {
  1315. height = -height;
  1316. src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
  1317. src_stride_rgb24 = -src_stride_rgb24;
  1318. }
  1319. // Neon version does direct RGB24 to YUV.
  1320. #if defined(HAS_RGB24TOYROW_NEON)
  1321. if (TestCpuFlag(kCpuHasNEON)) {
  1322. RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
  1323. RGB24ToYRow = RGB24ToYRow_Any_NEON;
  1324. if (IS_ALIGNED(width, 8)) {
  1325. RGB24ToYRow = RGB24ToYRow_NEON;
  1326. if (IS_ALIGNED(width, 16)) {
  1327. RGB24ToUVRow = RGB24ToUVRow_NEON;
  1328. }
  1329. }
  1330. }
  1331. // MMI and MSA version does direct RGB24 to YUV.
  1332. #elif (defined(HAS_RGB24TOYROW_MMI) || defined(HAS_RGB24TOYROW_MSA))
  1333. #if defined(HAS_RGB24TOYROW_MMI) && defined(HAS_RGB24TOUVROW_MMI)
  1334. if (TestCpuFlag(kCpuHasMMI)) {
  1335. RGB24ToUVRow = RGB24ToUVRow_Any_MMI;
  1336. RGB24ToYRow = RGB24ToYRow_Any_MMI;
  1337. if (IS_ALIGNED(width, 8)) {
  1338. RGB24ToYRow = RGB24ToYRow_MMI;
  1339. if (IS_ALIGNED(width, 16)) {
  1340. RGB24ToUVRow = RGB24ToUVRow_MMI;
  1341. }
  1342. }
  1343. }
  1344. #endif
  1345. #if defined(HAS_RGB24TOYROW_MSA) && defined(HAS_RGB24TOUVROW_MSA)
  1346. if (TestCpuFlag(kCpuHasMSA)) {
  1347. RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
  1348. RGB24ToYRow = RGB24ToYRow_Any_MSA;
  1349. if (IS_ALIGNED(width, 16)) {
  1350. RGB24ToYRow = RGB24ToYRow_MSA;
  1351. RGB24ToUVRow = RGB24ToUVRow_MSA;
  1352. }
  1353. }
  1354. #endif
  1355. // Other platforms do intermediate conversion from RGB24 to ARGB.
  1356. #else
  1357. #if defined(HAS_RGB24TOARGBROW_SSSE3)
  1358. if (TestCpuFlag(kCpuHasSSSE3)) {
  1359. RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
  1360. if (IS_ALIGNED(width, 16)) {
  1361. RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
  1362. }
  1363. }
  1364. #endif
  1365. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1366. if (TestCpuFlag(kCpuHasSSSE3)) {
  1367. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1368. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1369. if (IS_ALIGNED(width, 16)) {
  1370. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1371. ARGBToYRow = ARGBToYRow_SSSE3;
  1372. }
  1373. }
  1374. #endif
  1375. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1376. if (TestCpuFlag(kCpuHasAVX2)) {
  1377. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1378. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1379. if (IS_ALIGNED(width, 32)) {
  1380. ARGBToUVRow = ARGBToUVRow_AVX2;
  1381. ARGBToYRow = ARGBToYRow_AVX2;
  1382. }
  1383. }
  1384. #endif
  1385. #endif
  1386. {
  1387. #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
  1388. defined(HAS_RGB24TOYROW_MMI))
  1389. // Allocate 2 rows of ARGB.
  1390. const int kRowSize = (width * 4 + 31) & ~31;
  1391. align_buffer_64(row, kRowSize * 2);
  1392. #endif
  1393. for (y = 0; y < height - 1; y += 2) {
  1394. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
  1395. defined(HAS_RGB24TOYROW_MMI))
  1396. RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
  1397. RGB24ToYRow(src_rgb24, dst_y, width);
  1398. RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
  1399. #else
  1400. RGB24ToARGBRow(src_rgb24, row, width);
  1401. RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
  1402. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1403. ARGBToYRow(row, dst_y, width);
  1404. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1405. #endif
  1406. src_rgb24 += src_stride_rgb24 * 2;
  1407. dst_y += dst_stride_y * 2;
  1408. dst_u += dst_stride_u;
  1409. dst_v += dst_stride_v;
  1410. }
  1411. if (height & 1) {
  1412. #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
  1413. defined(HAS_RGB24TOYROW_MMI))
  1414. RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
  1415. RGB24ToYRow(src_rgb24, dst_y, width);
  1416. #else
  1417. RGB24ToARGBRow(src_rgb24, row, width);
  1418. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1419. ARGBToYRow(row, dst_y, width);
  1420. #endif
  1421. }
  1422. #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
  1423. defined(HAS_RGB24TOYROW_MMI))
  1424. free_aligned_buffer_64(row);
  1425. #endif
  1426. }
  1427. return 0;
  1428. }
  1429. // TODO(fbarchard): Use Matrix version to implement I420 and J420.
  1430. // Convert RGB24 to J420.
  1431. LIBYUV_API
  1432. int RGB24ToJ420(const uint8_t* src_rgb24,
  1433. int src_stride_rgb24,
  1434. uint8_t* dst_y,
  1435. int dst_stride_y,
  1436. uint8_t* dst_u,
  1437. int dst_stride_u,
  1438. uint8_t* dst_v,
  1439. int dst_stride_v,
  1440. int width,
  1441. int height) {
  1442. int y;
  1443. #if (defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)) || \
  1444. defined(HAS_RGB24TOYJROW_MSA) || defined(HAS_RGB24TOYJROW_MMI)
  1445. void (*RGB24ToUVJRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
  1446. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1447. RGB24ToUVJRow_C;
  1448. void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
  1449. RGB24ToYJRow_C;
  1450. #else
  1451. void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
  1452. RGB24ToARGBRow_C;
  1453. void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
  1454. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1455. ARGBToUVJRow_C;
  1456. void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1457. ARGBToYJRow_C;
  1458. #endif
  1459. if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1460. return -1;
  1461. }
  1462. // Negative height means invert the image.
  1463. if (height < 0) {
  1464. height = -height;
  1465. src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
  1466. src_stride_rgb24 = -src_stride_rgb24;
  1467. }
  1468. // Neon version does direct RGB24 to YUV.
  1469. #if defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)
  1470. if (TestCpuFlag(kCpuHasNEON)) {
  1471. RGB24ToUVJRow = RGB24ToUVJRow_Any_NEON;
  1472. RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
  1473. if (IS_ALIGNED(width, 8)) {
  1474. RGB24ToYJRow = RGB24ToYJRow_NEON;
  1475. if (IS_ALIGNED(width, 16)) {
  1476. RGB24ToUVJRow = RGB24ToUVJRow_NEON;
  1477. }
  1478. }
  1479. }
  1480. // MMI and MSA version does direct RGB24 to YUV.
  1481. #elif (defined(HAS_RGB24TOYJROW_MMI) || defined(HAS_RGB24TOYJROW_MSA))
  1482. #if defined(HAS_RGB24TOYJROW_MMI) && defined(HAS_RGB24TOUVJROW_MMI)
  1483. if (TestCpuFlag(kCpuHasMMI)) {
  1484. RGB24ToUVJRow = RGB24ToUVJRow_Any_MMI;
  1485. RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
  1486. if (IS_ALIGNED(width, 8)) {
  1487. RGB24ToYJRow = RGB24ToYJRow_MMI;
  1488. if (IS_ALIGNED(width, 16)) {
  1489. RGB24ToUVJRow = RGB24ToUVJRow_MMI;
  1490. }
  1491. }
  1492. }
  1493. #endif
  1494. #if defined(HAS_RGB24TOYJROW_MSA) && defined(HAS_RGB24TOUVJROW_MSA)
  1495. if (TestCpuFlag(kCpuHasMSA)) {
  1496. RGB24ToUVJRow = RGB24ToUVJRow_Any_MSA;
  1497. RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
  1498. if (IS_ALIGNED(width, 16)) {
  1499. RGB24ToYJRow = RGB24ToYJRow_MSA;
  1500. RGB24ToUVJRow = RGB24ToUVJRow_MSA;
  1501. }
  1502. }
  1503. #endif
  1504. #else
  1505. #if defined(HAS_RGB24TOARGBROW_SSSE3)
  1506. if (TestCpuFlag(kCpuHasSSSE3)) {
  1507. RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
  1508. if (IS_ALIGNED(width, 16)) {
  1509. RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
  1510. }
  1511. }
  1512. #endif
  1513. #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
  1514. if (TestCpuFlag(kCpuHasSSSE3)) {
  1515. ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
  1516. ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
  1517. if (IS_ALIGNED(width, 16)) {
  1518. ARGBToUVJRow = ARGBToUVJRow_SSSE3;
  1519. ARGBToYJRow = ARGBToYJRow_SSSE3;
  1520. }
  1521. }
  1522. #endif
  1523. #if defined(HAS_ARGBTOYJROW_AVX2) && defined(HAS_ARGBTOUVJROW_AVX2)
  1524. if (TestCpuFlag(kCpuHasAVX2)) {
  1525. ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
  1526. ARGBToYJRow = ARGBToYJRow_Any_AVX2;
  1527. if (IS_ALIGNED(width, 32)) {
  1528. ARGBToUVJRow = ARGBToUVJRow_AVX2;
  1529. ARGBToYJRow = ARGBToYJRow_AVX2;
  1530. }
  1531. }
  1532. #endif
  1533. #endif
  1534. {
  1535. #if !((defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)) || \
  1536. defined(HAS_RGB24TOYJROW_MSA) || defined(HAS_RGB24TOYJROW_MMI))
  1537. // Allocate 2 rows of ARGB.
  1538. const int kRowSize = (width * 4 + 31) & ~31;
  1539. align_buffer_64(row, kRowSize * 2);
  1540. #endif
  1541. for (y = 0; y < height - 1; y += 2) {
  1542. #if ((defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)) || \
  1543. defined(HAS_RGB24TOYJROW_MSA) || defined(HAS_RGB24TOYJROW_MMI))
  1544. RGB24ToUVJRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
  1545. RGB24ToYJRow(src_rgb24, dst_y, width);
  1546. RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
  1547. #else
  1548. RGB24ToARGBRow(src_rgb24, row, width);
  1549. RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
  1550. ARGBToUVJRow(row, kRowSize, dst_u, dst_v, width);
  1551. ARGBToYJRow(row, dst_y, width);
  1552. ARGBToYJRow(row + kRowSize, dst_y + dst_stride_y, width);
  1553. #endif
  1554. src_rgb24 += src_stride_rgb24 * 2;
  1555. dst_y += dst_stride_y * 2;
  1556. dst_u += dst_stride_u;
  1557. dst_v += dst_stride_v;
  1558. }
  1559. if (height & 1) {
  1560. #if ((defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)) || \
  1561. defined(HAS_RGB24TOYJROW_MSA) || defined(HAS_RGB24TOYJROW_MMI))
  1562. RGB24ToUVJRow(src_rgb24, 0, dst_u, dst_v, width);
  1563. RGB24ToYJRow(src_rgb24, dst_y, width);
  1564. #else
  1565. RGB24ToARGBRow(src_rgb24, row, width);
  1566. ARGBToUVJRow(row, 0, dst_u, dst_v, width);
  1567. ARGBToYJRow(row, dst_y, width);
  1568. #endif
  1569. }
  1570. #if !((defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)) || \
  1571. defined(HAS_RGB24TOYJROW_MSA) || defined(HAS_RGB24TOYJROW_MMI))
  1572. free_aligned_buffer_64(row);
  1573. #endif
  1574. }
  1575. return 0;
  1576. }
  1577. // Convert RAW to I420.
  1578. LIBYUV_API
  1579. int RAWToI420(const uint8_t* src_raw,
  1580. int src_stride_raw,
  1581. uint8_t* dst_y,
  1582. int dst_stride_y,
  1583. uint8_t* dst_u,
  1584. int dst_stride_u,
  1585. uint8_t* dst_v,
  1586. int dst_stride_v,
  1587. int width,
  1588. int height) {
  1589. int y;
  1590. #if (defined(HAS_RAWTOYROW_NEON) && defined(HAS_RAWTOUVROW_NEON)) || \
  1591. defined(HAS_RAWTOYROW_MSA) || defined(HAS_RAWTOYROW_MMI)
  1592. void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
  1593. uint8_t* dst_v, int width) = RAWToUVRow_C;
  1594. void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
  1595. RAWToYRow_C;
  1596. #else
  1597. void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
  1598. RAWToARGBRow_C;
  1599. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1600. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1601. ARGBToUVRow_C;
  1602. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1603. ARGBToYRow_C;
  1604. #endif
  1605. if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1606. return -1;
  1607. }
  1608. // Negative height means invert the image.
  1609. if (height < 0) {
  1610. height = -height;
  1611. src_raw = src_raw + (height - 1) * src_stride_raw;
  1612. src_stride_raw = -src_stride_raw;
  1613. }
  1614. // Neon version does direct RAW to YUV.
  1615. #if defined(HAS_RAWTOYROW_NEON) && defined(HAS_RAWTOUVROW_NEON)
  1616. if (TestCpuFlag(kCpuHasNEON)) {
  1617. RAWToUVRow = RAWToUVRow_Any_NEON;
  1618. RAWToYRow = RAWToYRow_Any_NEON;
  1619. if (IS_ALIGNED(width, 8)) {
  1620. RAWToYRow = RAWToYRow_NEON;
  1621. if (IS_ALIGNED(width, 16)) {
  1622. RAWToUVRow = RAWToUVRow_NEON;
  1623. }
  1624. }
  1625. }
  1626. // MMI and MSA version does direct RAW to YUV.
  1627. #elif (defined(HAS_RAWTOYROW_MMI) || defined(HAS_RAWTOYROW_MSA))
  1628. #if defined(HAS_RAWTOYROW_MMI) && defined(HAS_RAWTOUVROW_MMI)
  1629. if (TestCpuFlag(kCpuHasMMI)) {
  1630. RAWToUVRow = RAWToUVRow_Any_MMI;
  1631. RAWToYRow = RAWToYRow_Any_MMI;
  1632. if (IS_ALIGNED(width, 8)) {
  1633. RAWToYRow = RAWToYRow_MMI;
  1634. if (IS_ALIGNED(width, 16)) {
  1635. RAWToUVRow = RAWToUVRow_MMI;
  1636. }
  1637. }
  1638. }
  1639. #endif
  1640. #if defined(HAS_RAWTOYROW_MSA) && defined(HAS_RAWTOUVROW_MSA)
  1641. if (TestCpuFlag(kCpuHasMSA)) {
  1642. RAWToUVRow = RAWToUVRow_Any_MSA;
  1643. RAWToYRow = RAWToYRow_Any_MSA;
  1644. if (IS_ALIGNED(width, 16)) {
  1645. RAWToYRow = RAWToYRow_MSA;
  1646. RAWToUVRow = RAWToUVRow_MSA;
  1647. }
  1648. }
  1649. #endif
  1650. // Other platforms do intermediate conversion from RAW to ARGB.
  1651. #else
  1652. #if defined(HAS_RAWTOARGBROW_SSSE3)
  1653. if (TestCpuFlag(kCpuHasSSSE3)) {
  1654. RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
  1655. if (IS_ALIGNED(width, 16)) {
  1656. RAWToARGBRow = RAWToARGBRow_SSSE3;
  1657. }
  1658. }
  1659. #endif
  1660. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1661. if (TestCpuFlag(kCpuHasSSSE3)) {
  1662. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1663. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1664. if (IS_ALIGNED(width, 16)) {
  1665. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1666. ARGBToYRow = ARGBToYRow_SSSE3;
  1667. }
  1668. }
  1669. #endif
  1670. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1671. if (TestCpuFlag(kCpuHasAVX2)) {
  1672. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1673. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1674. if (IS_ALIGNED(width, 32)) {
  1675. ARGBToUVRow = ARGBToUVRow_AVX2;
  1676. ARGBToYRow = ARGBToYRow_AVX2;
  1677. }
  1678. }
  1679. #endif
  1680. #endif
  1681. {
  1682. #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
  1683. defined(HAS_RAWTOYROW_MMI))
  1684. // Allocate 2 rows of ARGB.
  1685. const int kRowSize = (width * 4 + 31) & ~31;
  1686. align_buffer_64(row, kRowSize * 2);
  1687. #endif
  1688. for (y = 0; y < height - 1; y += 2) {
  1689. #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
  1690. defined(HAS_RAWTOYROW_MMI))
  1691. RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
  1692. RAWToYRow(src_raw, dst_y, width);
  1693. RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
  1694. #else
  1695. RAWToARGBRow(src_raw, row, width);
  1696. RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
  1697. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1698. ARGBToYRow(row, dst_y, width);
  1699. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1700. #endif
  1701. src_raw += src_stride_raw * 2;
  1702. dst_y += dst_stride_y * 2;
  1703. dst_u += dst_stride_u;
  1704. dst_v += dst_stride_v;
  1705. }
  1706. if (height & 1) {
  1707. #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
  1708. defined(HAS_RAWTOYROW_MMI))
  1709. RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
  1710. RAWToYRow(src_raw, dst_y, width);
  1711. #else
  1712. RAWToARGBRow(src_raw, row, width);
  1713. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1714. ARGBToYRow(row, dst_y, width);
  1715. #endif
  1716. }
  1717. #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
  1718. defined(HAS_RAWTOYROW_MMI))
  1719. free_aligned_buffer_64(row);
  1720. #endif
  1721. }
  1722. return 0;
  1723. }
  1724. // Convert RGB565 to I420.
  1725. LIBYUV_API
  1726. int RGB565ToI420(const uint8_t* src_rgb565,
  1727. int src_stride_rgb565,
  1728. uint8_t* dst_y,
  1729. int dst_stride_y,
  1730. uint8_t* dst_u,
  1731. int dst_stride_u,
  1732. uint8_t* dst_v,
  1733. int dst_stride_v,
  1734. int width,
  1735. int height) {
  1736. int y;
  1737. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
  1738. defined(HAS_RGB565TOYROW_MMI))
  1739. void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
  1740. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1741. RGB565ToUVRow_C;
  1742. void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
  1743. RGB565ToYRow_C;
  1744. #else
  1745. void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  1746. int width) = RGB565ToARGBRow_C;
  1747. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1748. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1749. ARGBToUVRow_C;
  1750. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1751. ARGBToYRow_C;
  1752. #endif
  1753. if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
  1754. return -1;
  1755. }
  1756. // Negative height means invert the image.
  1757. if (height < 0) {
  1758. height = -height;
  1759. src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
  1760. src_stride_rgb565 = -src_stride_rgb565;
  1761. }
  1762. // Neon version does direct RGB565 to YUV.
  1763. #if defined(HAS_RGB565TOYROW_NEON)
  1764. if (TestCpuFlag(kCpuHasNEON)) {
  1765. RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
  1766. RGB565ToYRow = RGB565ToYRow_Any_NEON;
  1767. if (IS_ALIGNED(width, 8)) {
  1768. RGB565ToYRow = RGB565ToYRow_NEON;
  1769. if (IS_ALIGNED(width, 16)) {
  1770. RGB565ToUVRow = RGB565ToUVRow_NEON;
  1771. }
  1772. }
  1773. }
  1774. // MMI and MSA version does direct RGB565 to YUV.
  1775. #elif (defined(HAS_RGB565TOYROW_MMI) || defined(HAS_RGB565TOYROW_MSA))
  1776. #if defined(HAS_RGB565TOYROW_MMI) && defined(HAS_RGB565TOUVROW_MMI)
  1777. if (TestCpuFlag(kCpuHasMMI)) {
  1778. RGB565ToUVRow = RGB565ToUVRow_Any_MMI;
  1779. RGB565ToYRow = RGB565ToYRow_Any_MMI;
  1780. if (IS_ALIGNED(width, 8)) {
  1781. RGB565ToYRow = RGB565ToYRow_MMI;
  1782. if (IS_ALIGNED(width, 16)) {
  1783. RGB565ToUVRow = RGB565ToUVRow_MMI;
  1784. }
  1785. }
  1786. }
  1787. #endif
  1788. #if defined(HAS_RGB565TOYROW_MSA) && defined(HAS_RGB565TOUVROW_MSA)
  1789. if (TestCpuFlag(kCpuHasMSA)) {
  1790. RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
  1791. RGB565ToYRow = RGB565ToYRow_Any_MSA;
  1792. if (IS_ALIGNED(width, 16)) {
  1793. RGB565ToYRow = RGB565ToYRow_MSA;
  1794. RGB565ToUVRow = RGB565ToUVRow_MSA;
  1795. }
  1796. }
  1797. #endif
  1798. // Other platforms do intermediate conversion from RGB565 to ARGB.
  1799. #else
  1800. #if defined(HAS_RGB565TOARGBROW_SSE2)
  1801. if (TestCpuFlag(kCpuHasSSE2)) {
  1802. RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
  1803. if (IS_ALIGNED(width, 8)) {
  1804. RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
  1805. }
  1806. }
  1807. #endif
  1808. #if defined(HAS_RGB565TOARGBROW_AVX2)
  1809. if (TestCpuFlag(kCpuHasAVX2)) {
  1810. RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
  1811. if (IS_ALIGNED(width, 16)) {
  1812. RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
  1813. }
  1814. }
  1815. #endif
  1816. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1817. if (TestCpuFlag(kCpuHasSSSE3)) {
  1818. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1819. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1820. if (IS_ALIGNED(width, 16)) {
  1821. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1822. ARGBToYRow = ARGBToYRow_SSSE3;
  1823. }
  1824. }
  1825. #endif
  1826. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1827. if (TestCpuFlag(kCpuHasAVX2)) {
  1828. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1829. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1830. if (IS_ALIGNED(width, 32)) {
  1831. ARGBToUVRow = ARGBToUVRow_AVX2;
  1832. ARGBToYRow = ARGBToYRow_AVX2;
  1833. }
  1834. }
  1835. #endif
  1836. #endif
  1837. {
  1838. #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
  1839. defined(HAS_RGB565TOYROW_MMI))
  1840. // Allocate 2 rows of ARGB.
  1841. const int kRowSize = (width * 4 + 31) & ~31;
  1842. align_buffer_64(row, kRowSize * 2);
  1843. #endif
  1844. for (y = 0; y < height - 1; y += 2) {
  1845. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
  1846. defined(HAS_RGB565TOYROW_MMI))
  1847. RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
  1848. RGB565ToYRow(src_rgb565, dst_y, width);
  1849. RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
  1850. #else
  1851. RGB565ToARGBRow(src_rgb565, row, width);
  1852. RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
  1853. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1854. ARGBToYRow(row, dst_y, width);
  1855. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1856. #endif
  1857. src_rgb565 += src_stride_rgb565 * 2;
  1858. dst_y += dst_stride_y * 2;
  1859. dst_u += dst_stride_u;
  1860. dst_v += dst_stride_v;
  1861. }
  1862. if (height & 1) {
  1863. #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
  1864. defined(HAS_RGB565TOYROW_MMI))
  1865. RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
  1866. RGB565ToYRow(src_rgb565, dst_y, width);
  1867. #else
  1868. RGB565ToARGBRow(src_rgb565, row, width);
  1869. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1870. ARGBToYRow(row, dst_y, width);
  1871. #endif
  1872. }
  1873. #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
  1874. defined(HAS_RGB565TOYROW_MMI))
  1875. free_aligned_buffer_64(row);
  1876. #endif
  1877. }
  1878. return 0;
  1879. }
  1880. // Convert ARGB1555 to I420.
  1881. LIBYUV_API
  1882. int ARGB1555ToI420(const uint8_t* src_argb1555,
  1883. int src_stride_argb1555,
  1884. uint8_t* dst_y,
  1885. int dst_stride_y,
  1886. uint8_t* dst_u,
  1887. int dst_stride_u,
  1888. uint8_t* dst_v,
  1889. int dst_stride_v,
  1890. int width,
  1891. int height) {
  1892. int y;
  1893. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
  1894. defined(HAS_ARGB1555TOYROW_MMI))
  1895. void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
  1896. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1897. ARGB1555ToUVRow_C;
  1898. void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
  1899. int width) = ARGB1555ToYRow_C;
  1900. #else
  1901. void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  1902. int width) = ARGB1555ToARGBRow_C;
  1903. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  1904. uint8_t* dst_u, uint8_t* dst_v, int width) =
  1905. ARGBToUVRow_C;
  1906. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  1907. ARGBToYRow_C;
  1908. #endif
  1909. if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
  1910. height == 0) {
  1911. return -1;
  1912. }
  1913. // Negative height means invert the image.
  1914. if (height < 0) {
  1915. height = -height;
  1916. src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
  1917. src_stride_argb1555 = -src_stride_argb1555;
  1918. }
  1919. // Neon version does direct ARGB1555 to YUV.
  1920. #if defined(HAS_ARGB1555TOYROW_NEON)
  1921. if (TestCpuFlag(kCpuHasNEON)) {
  1922. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
  1923. ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
  1924. if (IS_ALIGNED(width, 8)) {
  1925. ARGB1555ToYRow = ARGB1555ToYRow_NEON;
  1926. if (IS_ALIGNED(width, 16)) {
  1927. ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
  1928. }
  1929. }
  1930. }
  1931. // MMI and MSA version does direct ARGB1555 to YUV.
  1932. #elif (defined(HAS_ARGB1555TOYROW_MMI) || defined(HAS_ARGB1555TOYROW_MSA))
  1933. #if defined(HAS_ARGB1555TOYROW_MMI) && defined(HAS_ARGB1555TOUVROW_MMI)
  1934. if (TestCpuFlag(kCpuHasMMI)) {
  1935. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MMI;
  1936. ARGB1555ToYRow = ARGB1555ToYRow_Any_MMI;
  1937. if (IS_ALIGNED(width, 8)) {
  1938. ARGB1555ToYRow = ARGB1555ToYRow_MMI;
  1939. if (IS_ALIGNED(width, 16)) {
  1940. ARGB1555ToUVRow = ARGB1555ToUVRow_MMI;
  1941. }
  1942. }
  1943. }
  1944. #endif
  1945. #if defined(HAS_ARGB1555TOYROW_MSA) && defined(HAS_ARGB1555TOUVROW_MSA)
  1946. if (TestCpuFlag(kCpuHasMSA)) {
  1947. ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
  1948. ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
  1949. if (IS_ALIGNED(width, 16)) {
  1950. ARGB1555ToYRow = ARGB1555ToYRow_MSA;
  1951. ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
  1952. }
  1953. }
  1954. #endif
  1955. // Other platforms do intermediate conversion from ARGB1555 to ARGB.
  1956. #else
  1957. #if defined(HAS_ARGB1555TOARGBROW_SSE2)
  1958. if (TestCpuFlag(kCpuHasSSE2)) {
  1959. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
  1960. if (IS_ALIGNED(width, 8)) {
  1961. ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
  1962. }
  1963. }
  1964. #endif
  1965. #if defined(HAS_ARGB1555TOARGBROW_AVX2)
  1966. if (TestCpuFlag(kCpuHasAVX2)) {
  1967. ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
  1968. if (IS_ALIGNED(width, 16)) {
  1969. ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
  1970. }
  1971. }
  1972. #endif
  1973. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  1974. if (TestCpuFlag(kCpuHasSSSE3)) {
  1975. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1976. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1977. if (IS_ALIGNED(width, 16)) {
  1978. ARGBToUVRow = ARGBToUVRow_SSSE3;
  1979. ARGBToYRow = ARGBToYRow_SSSE3;
  1980. }
  1981. }
  1982. #endif
  1983. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  1984. if (TestCpuFlag(kCpuHasAVX2)) {
  1985. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  1986. ARGBToYRow = ARGBToYRow_Any_AVX2;
  1987. if (IS_ALIGNED(width, 32)) {
  1988. ARGBToUVRow = ARGBToUVRow_AVX2;
  1989. ARGBToYRow = ARGBToYRow_AVX2;
  1990. }
  1991. }
  1992. #endif
  1993. #endif
  1994. {
  1995. #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
  1996. defined(HAS_ARGB1555TOYROW_MMI))
  1997. // Allocate 2 rows of ARGB.
  1998. const int kRowSize = (width * 4 + 31) & ~31;
  1999. align_buffer_64(row, kRowSize * 2);
  2000. #endif
  2001. for (y = 0; y < height - 1; y += 2) {
  2002. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
  2003. defined(HAS_ARGB1555TOYROW_MMI))
  2004. ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
  2005. ARGB1555ToYRow(src_argb1555, dst_y, width);
  2006. ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
  2007. width);
  2008. #else
  2009. ARGB1555ToARGBRow(src_argb1555, row, width);
  2010. ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
  2011. width);
  2012. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  2013. ARGBToYRow(row, dst_y, width);
  2014. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  2015. #endif
  2016. src_argb1555 += src_stride_argb1555 * 2;
  2017. dst_y += dst_stride_y * 2;
  2018. dst_u += dst_stride_u;
  2019. dst_v += dst_stride_v;
  2020. }
  2021. if (height & 1) {
  2022. #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
  2023. defined(HAS_ARGB1555TOYROW_MMI))
  2024. ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
  2025. ARGB1555ToYRow(src_argb1555, dst_y, width);
  2026. #else
  2027. ARGB1555ToARGBRow(src_argb1555, row, width);
  2028. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  2029. ARGBToYRow(row, dst_y, width);
  2030. #endif
  2031. }
  2032. #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
  2033. defined(HAS_ARGB1555TOYROW_MMI))
  2034. free_aligned_buffer_64(row);
  2035. #endif
  2036. }
  2037. return 0;
  2038. }
  2039. // Convert ARGB4444 to I420.
  2040. LIBYUV_API
  2041. int ARGB4444ToI420(const uint8_t* src_argb4444,
  2042. int src_stride_argb4444,
  2043. uint8_t* dst_y,
  2044. int dst_stride_y,
  2045. uint8_t* dst_u,
  2046. int dst_stride_u,
  2047. uint8_t* dst_v,
  2048. int dst_stride_v,
  2049. int width,
  2050. int height) {
  2051. int y;
  2052. #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
  2053. void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
  2054. uint8_t* dst_u, uint8_t* dst_v, int width) =
  2055. ARGB4444ToUVRow_C;
  2056. void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
  2057. int width) = ARGB4444ToYRow_C;
  2058. #else
  2059. void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
  2060. int width) = ARGB4444ToARGBRow_C;
  2061. void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
  2062. uint8_t* dst_u, uint8_t* dst_v, int width) =
  2063. ARGBToUVRow_C;
  2064. void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
  2065. ARGBToYRow_C;
  2066. #endif
  2067. if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
  2068. height == 0) {
  2069. return -1;
  2070. }
  2071. // Negative height means invert the image.
  2072. if (height < 0) {
  2073. height = -height;
  2074. src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
  2075. src_stride_argb4444 = -src_stride_argb4444;
  2076. }
  2077. // Neon version does direct ARGB4444 to YUV.
  2078. #if defined(HAS_ARGB4444TOYROW_NEON)
  2079. if (TestCpuFlag(kCpuHasNEON)) {
  2080. ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
  2081. ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
  2082. if (IS_ALIGNED(width, 8)) {
  2083. ARGB4444ToYRow = ARGB4444ToYRow_NEON;
  2084. if (IS_ALIGNED(width, 16)) {
  2085. ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
  2086. }
  2087. }
  2088. }
  2089. #elif defined(HAS_ARGB4444TOYROW_MMI) && defined(HAS_ARGB4444TOUVROW_MMI)
  2090. if (TestCpuFlag(kCpuHasMMI)) {
  2091. ARGB4444ToUVRow = ARGB4444ToUVRow_Any_MMI;
  2092. ARGB4444ToYRow = ARGB4444ToYRow_Any_MMI;
  2093. if (IS_ALIGNED(width, 8)) {
  2094. ARGB4444ToYRow = ARGB4444ToYRow_MMI;
  2095. if (IS_ALIGNED(width, 16)) {
  2096. ARGB4444ToUVRow = ARGB4444ToUVRow_MMI;
  2097. }
  2098. }
  2099. }
  2100. // Other platforms do intermediate conversion from ARGB4444 to ARGB.
  2101. #else
  2102. #if defined(HAS_ARGB4444TOARGBROW_SSE2)
  2103. if (TestCpuFlag(kCpuHasSSE2)) {
  2104. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
  2105. if (IS_ALIGNED(width, 8)) {
  2106. ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
  2107. }
  2108. }
  2109. #endif
  2110. #if defined(HAS_ARGB4444TOARGBROW_AVX2)
  2111. if (TestCpuFlag(kCpuHasAVX2)) {
  2112. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
  2113. if (IS_ALIGNED(width, 16)) {
  2114. ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
  2115. }
  2116. }
  2117. #endif
  2118. #if defined(HAS_ARGB4444TOARGBROW_MSA)
  2119. if (TestCpuFlag(kCpuHasMSA)) {
  2120. ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
  2121. if (IS_ALIGNED(width, 16)) {
  2122. ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
  2123. }
  2124. }
  2125. #endif
  2126. #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
  2127. if (TestCpuFlag(kCpuHasSSSE3)) {
  2128. ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  2129. ARGBToYRow = ARGBToYRow_Any_SSSE3;
  2130. if (IS_ALIGNED(width, 16)) {
  2131. ARGBToUVRow = ARGBToUVRow_SSSE3;
  2132. ARGBToYRow = ARGBToYRow_SSSE3;
  2133. }
  2134. }
  2135. #endif
  2136. #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
  2137. if (TestCpuFlag(kCpuHasAVX2)) {
  2138. ARGBToUVRow = ARGBToUVRow_Any_AVX2;
  2139. ARGBToYRow = ARGBToYRow_Any_AVX2;
  2140. if (IS_ALIGNED(width, 32)) {
  2141. ARGBToUVRow = ARGBToUVRow_AVX2;
  2142. ARGBToYRow = ARGBToYRow_AVX2;
  2143. }
  2144. }
  2145. #endif
  2146. #if defined(HAS_ARGBTOYROW_MMI) && defined(HAS_ARGBTOUVROW_MMI)
  2147. if (TestCpuFlag(kCpuHasMMI)) {
  2148. ARGBToUVRow = ARGBToUVRow_Any_MMI;
  2149. ARGBToYRow = ARGBToYRow_Any_MMI;
  2150. if (IS_ALIGNED(width, 8)) {
  2151. ARGBToYRow = ARGBToYRow_MMI;
  2152. if (IS_ALIGNED(width, 16)) {
  2153. ARGBToUVRow = ARGBToUVRow_MMI;
  2154. }
  2155. }
  2156. }
  2157. #endif
  2158. #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
  2159. if (TestCpuFlag(kCpuHasMSA)) {
  2160. ARGBToUVRow = ARGBToUVRow_Any_MSA;
  2161. ARGBToYRow = ARGBToYRow_Any_MSA;
  2162. if (IS_ALIGNED(width, 16)) {
  2163. ARGBToYRow = ARGBToYRow_MSA;
  2164. if (IS_ALIGNED(width, 32)) {
  2165. ARGBToUVRow = ARGBToUVRow_MSA;
  2166. }
  2167. }
  2168. }
  2169. #endif
  2170. #endif
  2171. {
  2172. #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
  2173. // Allocate 2 rows of ARGB.
  2174. const int kRowSize = (width * 4 + 31) & ~31;
  2175. align_buffer_64(row, kRowSize * 2);
  2176. #endif
  2177. for (y = 0; y < height - 1; y += 2) {
  2178. #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
  2179. ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
  2180. ARGB4444ToYRow(src_argb4444, dst_y, width);
  2181. ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
  2182. width);
  2183. #else
  2184. ARGB4444ToARGBRow(src_argb4444, row, width);
  2185. ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
  2186. width);
  2187. ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  2188. ARGBToYRow(row, dst_y, width);
  2189. ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  2190. #endif
  2191. src_argb4444 += src_stride_argb4444 * 2;
  2192. dst_y += dst_stride_y * 2;
  2193. dst_u += dst_stride_u;
  2194. dst_v += dst_stride_v;
  2195. }
  2196. if (height & 1) {
  2197. #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
  2198. ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
  2199. ARGB4444ToYRow(src_argb4444, dst_y, width);
  2200. #else
  2201. ARGB4444ToARGBRow(src_argb4444, row, width);
  2202. ARGBToUVRow(row, 0, dst_u, dst_v, width);
  2203. ARGBToYRow(row, dst_y, width);
  2204. #endif
  2205. }
  2206. #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
  2207. free_aligned_buffer_64(row);
  2208. #endif
  2209. }
  2210. return 0;
  2211. }
  2212. // Convert RGB24 to J400.
  2213. LIBYUV_API
  2214. int RGB24ToJ400(const uint8_t* src_rgb24,
  2215. int src_stride_rgb24,
  2216. uint8_t* dst_yj,
  2217. int dst_stride_yj,
  2218. int width,
  2219. int height) {
  2220. int y;
  2221. void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) =
  2222. RGB24ToYJRow_C;
  2223. if (!src_rgb24 || !dst_yj || width <= 0 || height == 0) {
  2224. return -1;
  2225. }
  2226. if (height < 0) {
  2227. height = -height;
  2228. src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
  2229. src_stride_rgb24 = -src_stride_rgb24;
  2230. }
  2231. // Coalesce rows.
  2232. if (src_stride_rgb24 == width * 3 && dst_stride_yj == width) {
  2233. width *= height;
  2234. height = 1;
  2235. src_stride_rgb24 = dst_stride_yj = 0;
  2236. }
  2237. #if defined(HAS_RGB24TOYJROW_SSSE3)
  2238. if (TestCpuFlag(kCpuHasSSSE3)) {
  2239. RGB24ToYJRow = RGB24ToYJRow_Any_SSSE3;
  2240. if (IS_ALIGNED(width, 16)) {
  2241. RGB24ToYJRow = RGB24ToYJRow_SSSE3;
  2242. }
  2243. }
  2244. #endif
  2245. #if defined(HAS_RGB24TOYJROW_AVX2)
  2246. if (TestCpuFlag(kCpuHasAVX2)) {
  2247. RGB24ToYJRow = RGB24ToYJRow_Any_AVX2;
  2248. if (IS_ALIGNED(width, 32)) {
  2249. RGB24ToYJRow = RGB24ToYJRow_AVX2;
  2250. }
  2251. }
  2252. #endif
  2253. #if defined(HAS_RGB24TOYJROW_NEON)
  2254. if (TestCpuFlag(kCpuHasNEON)) {
  2255. RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
  2256. if (IS_ALIGNED(width, 8)) {
  2257. RGB24ToYJRow = RGB24ToYJRow_NEON;
  2258. }
  2259. }
  2260. #endif
  2261. #if defined(HAS_RGB24TOYJROW_MMI)
  2262. if (TestCpuFlag(kCpuHasMMI)) {
  2263. RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
  2264. if (IS_ALIGNED(width, 8)) {
  2265. RGB24ToYJRow = RGB24ToYJRow_MMI;
  2266. }
  2267. }
  2268. #endif
  2269. #if defined(HAS_RGB24TOYJROW_MSA)
  2270. if (TestCpuFlag(kCpuHasMSA)) {
  2271. RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
  2272. if (IS_ALIGNED(width, 16)) {
  2273. RGB24ToYJRow = RGB24ToYJRow_MSA;
  2274. }
  2275. }
  2276. #endif
  2277. for (y = 0; y < height; ++y) {
  2278. RGB24ToYJRow(src_rgb24, dst_yj, width);
  2279. src_rgb24 += src_stride_rgb24;
  2280. dst_yj += dst_stride_yj;
  2281. }
  2282. return 0;
  2283. }
  2284. // Convert RAW to J400.
  2285. LIBYUV_API
  2286. int RAWToJ400(const uint8_t* src_raw,
  2287. int src_stride_raw,
  2288. uint8_t* dst_yj,
  2289. int dst_stride_yj,
  2290. int width,
  2291. int height) {
  2292. int y;
  2293. void (*RAWToYJRow)(const uint8_t* src_raw, uint8_t* dst_yj, int width) =
  2294. RAWToYJRow_C;
  2295. if (!src_raw || !dst_yj || width <= 0 || height == 0) {
  2296. return -1;
  2297. }
  2298. if (height < 0) {
  2299. height = -height;
  2300. src_raw = src_raw + (height - 1) * src_stride_raw;
  2301. src_stride_raw = -src_stride_raw;
  2302. }
  2303. // Coalesce rows.
  2304. if (src_stride_raw == width * 3 && dst_stride_yj == width) {
  2305. width *= height;
  2306. height = 1;
  2307. src_stride_raw = dst_stride_yj = 0;
  2308. }
  2309. #if defined(HAS_RAWTOYJROW_SSSE3)
  2310. if (TestCpuFlag(kCpuHasSSSE3)) {
  2311. RAWToYJRow = RAWToYJRow_Any_SSSE3;
  2312. if (IS_ALIGNED(width, 16)) {
  2313. RAWToYJRow = RAWToYJRow_SSSE3;
  2314. }
  2315. }
  2316. #endif
  2317. #if defined(HAS_RAWTOYJROW_AVX2)
  2318. if (TestCpuFlag(kCpuHasAVX2)) {
  2319. RAWToYJRow = RAWToYJRow_Any_AVX2;
  2320. if (IS_ALIGNED(width, 32)) {
  2321. RAWToYJRow = RAWToYJRow_AVX2;
  2322. }
  2323. }
  2324. #endif
  2325. #if defined(HAS_RAWTOYJROW_NEON)
  2326. if (TestCpuFlag(kCpuHasNEON)) {
  2327. RAWToYJRow = RAWToYJRow_Any_NEON;
  2328. if (IS_ALIGNED(width, 8)) {
  2329. RAWToYJRow = RAWToYJRow_NEON;
  2330. }
  2331. }
  2332. #endif
  2333. #if defined(HAS_RAWTOYJROW_MMI)
  2334. if (TestCpuFlag(kCpuHasMMI)) {
  2335. RAWToYJRow = RAWToYJRow_Any_MMI;
  2336. if (IS_ALIGNED(width, 8)) {
  2337. RAWToYJRow = RAWToYJRow_MMI;
  2338. }
  2339. }
  2340. #endif
  2341. #if defined(HAS_RAWTOYJROW_MSA)
  2342. if (TestCpuFlag(kCpuHasMSA)) {
  2343. RAWToYJRow = RAWToYJRow_Any_MSA;
  2344. if (IS_ALIGNED(width, 16)) {
  2345. RAWToYJRow = RAWToYJRow_MSA;
  2346. }
  2347. }
  2348. #endif
  2349. for (y = 0; y < height; ++y) {
  2350. RAWToYJRow(src_raw, dst_yj, width);
  2351. src_raw += src_stride_raw;
  2352. dst_yj += dst_stride_yj;
  2353. }
  2354. return 0;
  2355. }
  2356. static void SplitPixels(const uint8_t* src_u,
  2357. int src_pixel_stride_uv,
  2358. uint8_t* dst_u,
  2359. int width) {
  2360. int i;
  2361. for (i = 0; i < width; ++i) {
  2362. *dst_u = *src_u;
  2363. ++dst_u;
  2364. src_u += src_pixel_stride_uv;
  2365. }
  2366. }
  2367. // Convert Android420 to I420.
  2368. LIBYUV_API
  2369. int Android420ToI420(const uint8_t* src_y,
  2370. int src_stride_y,
  2371. const uint8_t* src_u,
  2372. int src_stride_u,
  2373. const uint8_t* src_v,
  2374. int src_stride_v,
  2375. int src_pixel_stride_uv,
  2376. uint8_t* dst_y,
  2377. int dst_stride_y,
  2378. uint8_t* dst_u,
  2379. int dst_stride_u,
  2380. uint8_t* dst_v,
  2381. int dst_stride_v,
  2382. int width,
  2383. int height) {
  2384. int y;
  2385. const ptrdiff_t vu_off = src_v - src_u;
  2386. int halfwidth = (width + 1) >> 1;
  2387. int halfheight = (height + 1) >> 1;
  2388. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  2389. return -1;
  2390. }
  2391. // Negative height means invert the image.
  2392. if (height < 0) {
  2393. height = -height;
  2394. halfheight = (height + 1) >> 1;
  2395. src_y = src_y + (height - 1) * src_stride_y;
  2396. src_u = src_u + (halfheight - 1) * src_stride_u;
  2397. src_v = src_v + (halfheight - 1) * src_stride_v;
  2398. src_stride_y = -src_stride_y;
  2399. src_stride_u = -src_stride_u;
  2400. src_stride_v = -src_stride_v;
  2401. }
  2402. if (dst_y) {
  2403. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  2404. }
  2405. // Copy UV planes as is - I420
  2406. if (src_pixel_stride_uv == 1) {
  2407. CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
  2408. CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
  2409. return 0;
  2410. // Split UV planes - NV21
  2411. }
  2412. if (src_pixel_stride_uv == 2 && vu_off == -1 &&
  2413. src_stride_u == src_stride_v) {
  2414. SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
  2415. halfwidth, halfheight);
  2416. return 0;
  2417. // Split UV planes - NV12
  2418. }
  2419. if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
  2420. SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
  2421. halfwidth, halfheight);
  2422. return 0;
  2423. }
  2424. for (y = 0; y < halfheight; ++y) {
  2425. SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
  2426. SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
  2427. src_u += src_stride_u;
  2428. src_v += src_stride_v;
  2429. dst_u += dst_stride_u;
  2430. dst_v += dst_stride_v;
  2431. }
  2432. return 0;
  2433. }
  2434. #ifdef __cplusplus
  2435. } // extern "C"
  2436. } // namespace libyuv
  2437. #endif