convert_from.cc 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. /*
  2. * Copyright 2012 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_from.h"
  11. #include "libyuv/basic_types.h"
  12. #include "libyuv/convert.h" // For I420Copy
  13. #include "libyuv/cpu_id.h"
  14. #include "libyuv/planar_functions.h"
  15. #include "libyuv/rotate.h"
  16. #include "libyuv/row.h"
  17. #include "libyuv/scale.h" // For ScalePlane()
  18. #include "libyuv/video_common.h"
  19. #ifdef __cplusplus
  20. namespace libyuv {
  21. extern "C" {
  22. #endif
  23. #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
  24. static __inline int Abs(int v) {
  25. return v >= 0 ? v : -v;
  26. }
  27. // I420 To any I4xx YUV format with mirroring.
  28. static int I420ToI4xx(const uint8_t* src_y,
  29. int src_stride_y,
  30. const uint8_t* src_u,
  31. int src_stride_u,
  32. const uint8_t* src_v,
  33. int src_stride_v,
  34. uint8_t* dst_y,
  35. int dst_stride_y,
  36. uint8_t* dst_u,
  37. int dst_stride_u,
  38. uint8_t* dst_v,
  39. int dst_stride_v,
  40. int src_y_width,
  41. int src_y_height,
  42. int dst_uv_width,
  43. int dst_uv_height) {
  44. const int dst_y_width = Abs(src_y_width);
  45. const int dst_y_height = Abs(src_y_height);
  46. const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
  47. const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
  48. if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
  49. dst_uv_height <= 0) {
  50. return -1;
  51. }
  52. if (dst_y) {
  53. ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
  54. dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
  55. }
  56. ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
  57. dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
  58. ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
  59. dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
  60. return 0;
  61. }
  62. // Convert 8 bit YUV to 10 bit.
  63. LIBYUV_API
  64. int I420ToI010(const uint8_t* src_y,
  65. int src_stride_y,
  66. const uint8_t* src_u,
  67. int src_stride_u,
  68. const uint8_t* src_v,
  69. int src_stride_v,
  70. uint16_t* dst_y,
  71. int dst_stride_y,
  72. uint16_t* dst_u,
  73. int dst_stride_u,
  74. uint16_t* dst_v,
  75. int dst_stride_v,
  76. int width,
  77. int height) {
  78. int halfwidth = (width + 1) >> 1;
  79. int halfheight = (height + 1) >> 1;
  80. if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
  81. return -1;
  82. }
  83. // Negative height means invert the image.
  84. if (height < 0) {
  85. height = -height;
  86. halfheight = (height + 1) >> 1;
  87. src_y = src_y + (height - 1) * src_stride_y;
  88. src_u = src_u + (halfheight - 1) * src_stride_u;
  89. src_v = src_v + (halfheight - 1) * src_stride_v;
  90. src_stride_y = -src_stride_y;
  91. src_stride_u = -src_stride_u;
  92. src_stride_v = -src_stride_v;
  93. }
  94. // Convert Y plane.
  95. Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
  96. height);
  97. // Convert UV planes.
  98. Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
  99. halfheight);
  100. Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
  101. halfheight);
  102. return 0;
  103. }
  104. // 420 chroma is 1/2 width, 1/2 height
  105. // 422 chroma is 1/2 width, 1x height
  106. LIBYUV_API
  107. int I420ToI422(const uint8_t* src_y,
  108. int src_stride_y,
  109. const uint8_t* src_u,
  110. int src_stride_u,
  111. const uint8_t* src_v,
  112. int src_stride_v,
  113. uint8_t* dst_y,
  114. int dst_stride_y,
  115. uint8_t* dst_u,
  116. int dst_stride_u,
  117. uint8_t* dst_v,
  118. int dst_stride_v,
  119. int width,
  120. int height) {
  121. const int dst_uv_width = (Abs(width) + 1) >> 1;
  122. const int dst_uv_height = Abs(height);
  123. return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
  124. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  125. dst_v, dst_stride_v, width, height, dst_uv_width,
  126. dst_uv_height);
  127. }
  128. // 420 chroma is 1/2 width, 1/2 height
  129. // 444 chroma is 1x width, 1x height
  130. LIBYUV_API
  131. int I420ToI444(const uint8_t* src_y,
  132. int src_stride_y,
  133. const uint8_t* src_u,
  134. int src_stride_u,
  135. const uint8_t* src_v,
  136. int src_stride_v,
  137. uint8_t* dst_y,
  138. int dst_stride_y,
  139. uint8_t* dst_u,
  140. int dst_stride_u,
  141. uint8_t* dst_v,
  142. int dst_stride_v,
  143. int width,
  144. int height) {
  145. const int dst_uv_width = Abs(width);
  146. const int dst_uv_height = Abs(height);
  147. return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
  148. src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
  149. dst_v, dst_stride_v, width, height, dst_uv_width,
  150. dst_uv_height);
  151. }
  152. // Copy to I400. Source can be I420,422,444,400,NV12,NV21
  153. LIBYUV_API
  154. int I400Copy(const uint8_t* src_y,
  155. int src_stride_y,
  156. uint8_t* dst_y,
  157. int dst_stride_y,
  158. int width,
  159. int height) {
  160. if (!src_y || !dst_y || width <= 0 || height == 0) {
  161. return -1;
  162. }
  163. // Negative height means invert the image.
  164. if (height < 0) {
  165. height = -height;
  166. src_y = src_y + (height - 1) * src_stride_y;
  167. src_stride_y = -src_stride_y;
  168. }
  169. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  170. return 0;
  171. }
  172. LIBYUV_API
  173. int I422ToYUY2(const uint8_t* src_y,
  174. int src_stride_y,
  175. const uint8_t* src_u,
  176. int src_stride_u,
  177. const uint8_t* src_v,
  178. int src_stride_v,
  179. uint8_t* dst_yuy2,
  180. int dst_stride_yuy2,
  181. int width,
  182. int height) {
  183. int y;
  184. void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
  185. const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
  186. I422ToYUY2Row_C;
  187. if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
  188. return -1;
  189. }
  190. // Negative height means invert the image.
  191. if (height < 0) {
  192. height = -height;
  193. dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
  194. dst_stride_yuy2 = -dst_stride_yuy2;
  195. }
  196. // Coalesce rows.
  197. if (src_stride_y == width && src_stride_u * 2 == width &&
  198. src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
  199. width *= height;
  200. height = 1;
  201. src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
  202. }
  203. #if defined(HAS_I422TOYUY2ROW_SSE2)
  204. if (TestCpuFlag(kCpuHasSSE2)) {
  205. I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
  206. if (IS_ALIGNED(width, 16)) {
  207. I422ToYUY2Row = I422ToYUY2Row_SSE2;
  208. }
  209. }
  210. #endif
  211. #if defined(HAS_I422TOYUY2ROW_AVX2)
  212. if (TestCpuFlag(kCpuHasAVX2)) {
  213. I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
  214. if (IS_ALIGNED(width, 32)) {
  215. I422ToYUY2Row = I422ToYUY2Row_AVX2;
  216. }
  217. }
  218. #endif
  219. #if defined(HAS_I422TOYUY2ROW_NEON)
  220. if (TestCpuFlag(kCpuHasNEON)) {
  221. I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
  222. if (IS_ALIGNED(width, 16)) {
  223. I422ToYUY2Row = I422ToYUY2Row_NEON;
  224. }
  225. }
  226. #endif
  227. for (y = 0; y < height; ++y) {
  228. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  229. src_y += src_stride_y;
  230. src_u += src_stride_u;
  231. src_v += src_stride_v;
  232. dst_yuy2 += dst_stride_yuy2;
  233. }
  234. return 0;
  235. }
  236. LIBYUV_API
  237. int I420ToYUY2(const uint8_t* src_y,
  238. int src_stride_y,
  239. const uint8_t* src_u,
  240. int src_stride_u,
  241. const uint8_t* src_v,
  242. int src_stride_v,
  243. uint8_t* dst_yuy2,
  244. int dst_stride_yuy2,
  245. int width,
  246. int height) {
  247. int y;
  248. void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
  249. const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
  250. I422ToYUY2Row_C;
  251. if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
  252. return -1;
  253. }
  254. // Negative height means invert the image.
  255. if (height < 0) {
  256. height = -height;
  257. dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
  258. dst_stride_yuy2 = -dst_stride_yuy2;
  259. }
  260. #if defined(HAS_I422TOYUY2ROW_SSE2)
  261. if (TestCpuFlag(kCpuHasSSE2)) {
  262. I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
  263. if (IS_ALIGNED(width, 16)) {
  264. I422ToYUY2Row = I422ToYUY2Row_SSE2;
  265. }
  266. }
  267. #endif
  268. #if defined(HAS_I422TOYUY2ROW_AVX2)
  269. if (TestCpuFlag(kCpuHasAVX2)) {
  270. I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
  271. if (IS_ALIGNED(width, 32)) {
  272. I422ToYUY2Row = I422ToYUY2Row_AVX2;
  273. }
  274. }
  275. #endif
  276. #if defined(HAS_I422TOYUY2ROW_NEON)
  277. if (TestCpuFlag(kCpuHasNEON)) {
  278. I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
  279. if (IS_ALIGNED(width, 16)) {
  280. I422ToYUY2Row = I422ToYUY2Row_NEON;
  281. }
  282. }
  283. #endif
  284. #if defined(HAS_I422TOYUY2ROW_MSA)
  285. if (TestCpuFlag(kCpuHasMSA)) {
  286. I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
  287. if (IS_ALIGNED(width, 32)) {
  288. I422ToYUY2Row = I422ToYUY2Row_MSA;
  289. }
  290. }
  291. #endif
  292. for (y = 0; y < height - 1; y += 2) {
  293. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  294. I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
  295. dst_yuy2 + dst_stride_yuy2, width);
  296. src_y += src_stride_y * 2;
  297. src_u += src_stride_u;
  298. src_v += src_stride_v;
  299. dst_yuy2 += dst_stride_yuy2 * 2;
  300. }
  301. if (height & 1) {
  302. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  303. }
  304. return 0;
  305. }
  306. LIBYUV_API
  307. int I422ToUYVY(const uint8_t* src_y,
  308. int src_stride_y,
  309. const uint8_t* src_u,
  310. int src_stride_u,
  311. const uint8_t* src_v,
  312. int src_stride_v,
  313. uint8_t* dst_uyvy,
  314. int dst_stride_uyvy,
  315. int width,
  316. int height) {
  317. int y;
  318. void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
  319. const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
  320. I422ToUYVYRow_C;
  321. if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
  322. return -1;
  323. }
  324. // Negative height means invert the image.
  325. if (height < 0) {
  326. height = -height;
  327. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  328. dst_stride_uyvy = -dst_stride_uyvy;
  329. }
  330. // Coalesce rows.
  331. if (src_stride_y == width && src_stride_u * 2 == width &&
  332. src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
  333. width *= height;
  334. height = 1;
  335. src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
  336. }
  337. #if defined(HAS_I422TOUYVYROW_SSE2)
  338. if (TestCpuFlag(kCpuHasSSE2)) {
  339. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  340. if (IS_ALIGNED(width, 16)) {
  341. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  342. }
  343. }
  344. #endif
  345. #if defined(HAS_I422TOUYVYROW_AVX2)
  346. if (TestCpuFlag(kCpuHasAVX2)) {
  347. I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
  348. if (IS_ALIGNED(width, 32)) {
  349. I422ToUYVYRow = I422ToUYVYRow_AVX2;
  350. }
  351. }
  352. #endif
  353. #if defined(HAS_I422TOUYVYROW_NEON)
  354. if (TestCpuFlag(kCpuHasNEON)) {
  355. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  356. if (IS_ALIGNED(width, 16)) {
  357. I422ToUYVYRow = I422ToUYVYRow_NEON;
  358. }
  359. }
  360. #endif
  361. #if defined(HAS_I422TOUYVYROW_MSA)
  362. if (TestCpuFlag(kCpuHasMSA)) {
  363. I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
  364. if (IS_ALIGNED(width, 32)) {
  365. I422ToUYVYRow = I422ToUYVYRow_MSA;
  366. }
  367. }
  368. #endif
  369. for (y = 0; y < height; ++y) {
  370. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  371. src_y += src_stride_y;
  372. src_u += src_stride_u;
  373. src_v += src_stride_v;
  374. dst_uyvy += dst_stride_uyvy;
  375. }
  376. return 0;
  377. }
  378. LIBYUV_API
  379. int I420ToUYVY(const uint8_t* src_y,
  380. int src_stride_y,
  381. const uint8_t* src_u,
  382. int src_stride_u,
  383. const uint8_t* src_v,
  384. int src_stride_v,
  385. uint8_t* dst_uyvy,
  386. int dst_stride_uyvy,
  387. int width,
  388. int height) {
  389. int y;
  390. void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
  391. const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
  392. I422ToUYVYRow_C;
  393. if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
  394. return -1;
  395. }
  396. // Negative height means invert the image.
  397. if (height < 0) {
  398. height = -height;
  399. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  400. dst_stride_uyvy = -dst_stride_uyvy;
  401. }
  402. #if defined(HAS_I422TOUYVYROW_SSE2)
  403. if (TestCpuFlag(kCpuHasSSE2)) {
  404. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  405. if (IS_ALIGNED(width, 16)) {
  406. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  407. }
  408. }
  409. #endif
  410. #if defined(HAS_I422TOUYVYROW_AVX2)
  411. if (TestCpuFlag(kCpuHasAVX2)) {
  412. I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
  413. if (IS_ALIGNED(width, 32)) {
  414. I422ToUYVYRow = I422ToUYVYRow_AVX2;
  415. }
  416. }
  417. #endif
  418. #if defined(HAS_I422TOUYVYROW_NEON)
  419. if (TestCpuFlag(kCpuHasNEON)) {
  420. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  421. if (IS_ALIGNED(width, 16)) {
  422. I422ToUYVYRow = I422ToUYVYRow_NEON;
  423. }
  424. }
  425. #endif
  426. #if defined(HAS_I422TOUYVYROW_MSA)
  427. if (TestCpuFlag(kCpuHasMSA)) {
  428. I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
  429. if (IS_ALIGNED(width, 32)) {
  430. I422ToUYVYRow = I422ToUYVYRow_MSA;
  431. }
  432. }
  433. #endif
  434. for (y = 0; y < height - 1; y += 2) {
  435. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  436. I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
  437. dst_uyvy + dst_stride_uyvy, width);
  438. src_y += src_stride_y * 2;
  439. src_u += src_stride_u;
  440. src_v += src_stride_v;
  441. dst_uyvy += dst_stride_uyvy * 2;
  442. }
  443. if (height & 1) {
  444. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  445. }
  446. return 0;
  447. }
  448. // TODO(fbarchard): test negative height for invert.
  449. LIBYUV_API
  450. int I420ToNV12(const uint8_t* src_y,
  451. int src_stride_y,
  452. const uint8_t* src_u,
  453. int src_stride_u,
  454. const uint8_t* src_v,
  455. int src_stride_v,
  456. uint8_t* dst_y,
  457. int dst_stride_y,
  458. uint8_t* dst_uv,
  459. int dst_stride_uv,
  460. int width,
  461. int height) {
  462. if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
  463. height == 0) {
  464. return -1;
  465. }
  466. int halfwidth = (width + 1) / 2;
  467. int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
  468. if (dst_y) {
  469. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  470. }
  471. MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
  472. halfwidth, halfheight);
  473. return 0;
  474. }
  475. LIBYUV_API
  476. int I420ToNV21(const uint8_t* src_y,
  477. int src_stride_y,
  478. const uint8_t* src_u,
  479. int src_stride_u,
  480. const uint8_t* src_v,
  481. int src_stride_v,
  482. uint8_t* dst_y,
  483. int dst_stride_y,
  484. uint8_t* dst_vu,
  485. int dst_stride_vu,
  486. int width,
  487. int height) {
  488. return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
  489. src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
  490. width, height);
  491. }
  492. // Convert I422 to RGBA with matrix
  493. static int I420ToRGBAMatrix(const uint8_t* src_y,
  494. int src_stride_y,
  495. const uint8_t* src_u,
  496. int src_stride_u,
  497. const uint8_t* src_v,
  498. int src_stride_v,
  499. uint8_t* dst_rgba,
  500. int dst_stride_rgba,
  501. const struct YuvConstants* yuvconstants,
  502. int width,
  503. int height) {
  504. int y;
  505. void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf,
  506. const uint8_t* v_buf, uint8_t* rgb_buf,
  507. const struct YuvConstants* yuvconstants, int width) =
  508. I422ToRGBARow_C;
  509. if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
  510. return -1;
  511. }
  512. // Negative height means invert the image.
  513. if (height < 0) {
  514. height = -height;
  515. dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
  516. dst_stride_rgba = -dst_stride_rgba;
  517. }
  518. #if defined(HAS_I422TORGBAROW_SSSE3)
  519. if (TestCpuFlag(kCpuHasSSSE3)) {
  520. I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
  521. if (IS_ALIGNED(width, 8)) {
  522. I422ToRGBARow = I422ToRGBARow_SSSE3;
  523. }
  524. }
  525. #endif
  526. #if defined(HAS_I422TORGBAROW_AVX2)
  527. if (TestCpuFlag(kCpuHasAVX2)) {
  528. I422ToRGBARow = I422ToRGBARow_Any_AVX2;
  529. if (IS_ALIGNED(width, 16)) {
  530. I422ToRGBARow = I422ToRGBARow_AVX2;
  531. }
  532. }
  533. #endif
  534. #if defined(HAS_I422TORGBAROW_NEON)
  535. if (TestCpuFlag(kCpuHasNEON)) {
  536. I422ToRGBARow = I422ToRGBARow_Any_NEON;
  537. if (IS_ALIGNED(width, 8)) {
  538. I422ToRGBARow = I422ToRGBARow_NEON;
  539. }
  540. }
  541. #endif
  542. #if defined(HAS_I422TORGBAROW_MSA)
  543. if (TestCpuFlag(kCpuHasMSA)) {
  544. I422ToRGBARow = I422ToRGBARow_Any_MSA;
  545. if (IS_ALIGNED(width, 8)) {
  546. I422ToRGBARow = I422ToRGBARow_MSA;
  547. }
  548. }
  549. #endif
  550. for (y = 0; y < height; ++y) {
  551. I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
  552. dst_rgba += dst_stride_rgba;
  553. src_y += src_stride_y;
  554. if (y & 1) {
  555. src_u += src_stride_u;
  556. src_v += src_stride_v;
  557. }
  558. }
  559. return 0;
  560. }
  561. // Convert I420 to RGBA.
  562. LIBYUV_API
  563. int I420ToRGBA(const uint8_t* src_y,
  564. int src_stride_y,
  565. const uint8_t* src_u,
  566. int src_stride_u,
  567. const uint8_t* src_v,
  568. int src_stride_v,
  569. uint8_t* dst_rgba,
  570. int dst_stride_rgba,
  571. int width,
  572. int height) {
  573. return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
  574. src_stride_v, dst_rgba, dst_stride_rgba,
  575. &kYuvI601Constants, width, height);
  576. }
  577. // Convert I420 to BGRA.
  578. LIBYUV_API
  579. int I420ToBGRA(const uint8_t* src_y,
  580. int src_stride_y,
  581. const uint8_t* src_u,
  582. int src_stride_u,
  583. const uint8_t* src_v,
  584. int src_stride_v,
  585. uint8_t* dst_bgra,
  586. int dst_stride_bgra,
  587. int width,
  588. int height) {
  589. return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
  590. src_stride_v, // Swap U and V
  591. src_u, src_stride_u, dst_bgra, dst_stride_bgra,
  592. &kYvuI601Constants, // Use Yvu matrix
  593. width, height);
  594. }
  595. // Convert I420 to RGB24 with matrix
  596. static int I420ToRGB24Matrix(const uint8_t* src_y,
  597. int src_stride_y,
  598. const uint8_t* src_u,
  599. int src_stride_u,
  600. const uint8_t* src_v,
  601. int src_stride_v,
  602. uint8_t* dst_rgb24,
  603. int dst_stride_rgb24,
  604. const struct YuvConstants* yuvconstants,
  605. int width,
  606. int height) {
  607. int y;
  608. void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  609. const uint8_t* v_buf, uint8_t* rgb_buf,
  610. const struct YuvConstants* yuvconstants, int width) =
  611. I422ToRGB24Row_C;
  612. if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
  613. return -1;
  614. }
  615. // Negative height means invert the image.
  616. if (height < 0) {
  617. height = -height;
  618. dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
  619. dst_stride_rgb24 = -dst_stride_rgb24;
  620. }
  621. #if defined(HAS_I422TORGB24ROW_SSSE3)
  622. if (TestCpuFlag(kCpuHasSSSE3)) {
  623. I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
  624. if (IS_ALIGNED(width, 8)) {
  625. I422ToRGB24Row = I422ToRGB24Row_SSSE3;
  626. }
  627. }
  628. #endif
  629. #if defined(HAS_I422TORGB24ROW_AVX2)
  630. if (TestCpuFlag(kCpuHasAVX2)) {
  631. I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
  632. if (IS_ALIGNED(width, 16)) {
  633. I422ToRGB24Row = I422ToRGB24Row_AVX2;
  634. }
  635. }
  636. #endif
  637. #if defined(HAS_I422TORGB24ROW_NEON)
  638. if (TestCpuFlag(kCpuHasNEON)) {
  639. I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
  640. if (IS_ALIGNED(width, 8)) {
  641. I422ToRGB24Row = I422ToRGB24Row_NEON;
  642. }
  643. }
  644. #endif
  645. #if defined(HAS_I422TORGB24ROW_MSA)
  646. if (TestCpuFlag(kCpuHasMSA)) {
  647. I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
  648. if (IS_ALIGNED(width, 16)) {
  649. I422ToRGB24Row = I422ToRGB24Row_MSA;
  650. }
  651. }
  652. #endif
  653. for (y = 0; y < height; ++y) {
  654. I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
  655. dst_rgb24 += dst_stride_rgb24;
  656. src_y += src_stride_y;
  657. if (y & 1) {
  658. src_u += src_stride_u;
  659. src_v += src_stride_v;
  660. }
  661. }
  662. return 0;
  663. }
  664. // Convert I420 to RGB24.
  665. LIBYUV_API
  666. int I420ToRGB24(const uint8_t* src_y,
  667. int src_stride_y,
  668. const uint8_t* src_u,
  669. int src_stride_u,
  670. const uint8_t* src_v,
  671. int src_stride_v,
  672. uint8_t* dst_rgb24,
  673. int dst_stride_rgb24,
  674. int width,
  675. int height) {
  676. return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
  677. src_stride_v, dst_rgb24, dst_stride_rgb24,
  678. &kYuvI601Constants, width, height);
  679. }
  680. // Convert I420 to RAW.
  681. LIBYUV_API
  682. int I420ToRAW(const uint8_t* src_y,
  683. int src_stride_y,
  684. const uint8_t* src_u,
  685. int src_stride_u,
  686. const uint8_t* src_v,
  687. int src_stride_v,
  688. uint8_t* dst_raw,
  689. int dst_stride_raw,
  690. int width,
  691. int height) {
  692. return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
  693. src_stride_v, // Swap U and V
  694. src_u, src_stride_u, dst_raw, dst_stride_raw,
  695. &kYvuI601Constants, // Use Yvu matrix
  696. width, height);
  697. }
  698. // Convert H420 to RGB24.
  699. LIBYUV_API
  700. int H420ToRGB24(const uint8_t* src_y,
  701. int src_stride_y,
  702. const uint8_t* src_u,
  703. int src_stride_u,
  704. const uint8_t* src_v,
  705. int src_stride_v,
  706. uint8_t* dst_rgb24,
  707. int dst_stride_rgb24,
  708. int width,
  709. int height) {
  710. return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
  711. src_stride_v, dst_rgb24, dst_stride_rgb24,
  712. &kYuvH709Constants, width, height);
  713. }
  714. // Convert H420 to RAW.
  715. LIBYUV_API
  716. int H420ToRAW(const uint8_t* src_y,
  717. int src_stride_y,
  718. const uint8_t* src_u,
  719. int src_stride_u,
  720. const uint8_t* src_v,
  721. int src_stride_v,
  722. uint8_t* dst_raw,
  723. int dst_stride_raw,
  724. int width,
  725. int height) {
  726. return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
  727. src_stride_v, // Swap U and V
  728. src_u, src_stride_u, dst_raw, dst_stride_raw,
  729. &kYvuH709Constants, // Use Yvu matrix
  730. width, height);
  731. }
  732. // Convert I420 to ARGB1555.
  733. LIBYUV_API
  734. int I420ToARGB1555(const uint8_t* src_y,
  735. int src_stride_y,
  736. const uint8_t* src_u,
  737. int src_stride_u,
  738. const uint8_t* src_v,
  739. int src_stride_v,
  740. uint8_t* dst_argb1555,
  741. int dst_stride_argb1555,
  742. int width,
  743. int height) {
  744. int y;
  745. void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  746. const uint8_t* v_buf, uint8_t* rgb_buf,
  747. const struct YuvConstants* yuvconstants,
  748. int width) = I422ToARGB1555Row_C;
  749. if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
  750. height == 0) {
  751. return -1;
  752. }
  753. // Negative height means invert the image.
  754. if (height < 0) {
  755. height = -height;
  756. dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
  757. dst_stride_argb1555 = -dst_stride_argb1555;
  758. }
  759. #if defined(HAS_I422TOARGB1555ROW_SSSE3)
  760. if (TestCpuFlag(kCpuHasSSSE3)) {
  761. I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
  762. if (IS_ALIGNED(width, 8)) {
  763. I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
  764. }
  765. }
  766. #endif
  767. #if defined(HAS_I422TOARGB1555ROW_AVX2)
  768. if (TestCpuFlag(kCpuHasAVX2)) {
  769. I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
  770. if (IS_ALIGNED(width, 16)) {
  771. I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
  772. }
  773. }
  774. #endif
  775. #if defined(HAS_I422TOARGB1555ROW_NEON)
  776. if (TestCpuFlag(kCpuHasNEON)) {
  777. I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
  778. if (IS_ALIGNED(width, 8)) {
  779. I422ToARGB1555Row = I422ToARGB1555Row_NEON;
  780. }
  781. }
  782. #endif
  783. #if defined(HAS_I422TOARGB1555ROW_MSA)
  784. if (TestCpuFlag(kCpuHasMSA)) {
  785. I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
  786. if (IS_ALIGNED(width, 8)) {
  787. I422ToARGB1555Row = I422ToARGB1555Row_MSA;
  788. }
  789. }
  790. #endif
  791. for (y = 0; y < height; ++y) {
  792. I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
  793. width);
  794. dst_argb1555 += dst_stride_argb1555;
  795. src_y += src_stride_y;
  796. if (y & 1) {
  797. src_u += src_stride_u;
  798. src_v += src_stride_v;
  799. }
  800. }
  801. return 0;
  802. }
  803. // Convert I420 to ARGB4444.
  804. LIBYUV_API
  805. int I420ToARGB4444(const uint8_t* src_y,
  806. int src_stride_y,
  807. const uint8_t* src_u,
  808. int src_stride_u,
  809. const uint8_t* src_v,
  810. int src_stride_v,
  811. uint8_t* dst_argb4444,
  812. int dst_stride_argb4444,
  813. int width,
  814. int height) {
  815. int y;
  816. void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  817. const uint8_t* v_buf, uint8_t* rgb_buf,
  818. const struct YuvConstants* yuvconstants,
  819. int width) = I422ToARGB4444Row_C;
  820. if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
  821. height == 0) {
  822. return -1;
  823. }
  824. // Negative height means invert the image.
  825. if (height < 0) {
  826. height = -height;
  827. dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
  828. dst_stride_argb4444 = -dst_stride_argb4444;
  829. }
  830. #if defined(HAS_I422TOARGB4444ROW_SSSE3)
  831. if (TestCpuFlag(kCpuHasSSSE3)) {
  832. I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
  833. if (IS_ALIGNED(width, 8)) {
  834. I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
  835. }
  836. }
  837. #endif
  838. #if defined(HAS_I422TOARGB4444ROW_AVX2)
  839. if (TestCpuFlag(kCpuHasAVX2)) {
  840. I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
  841. if (IS_ALIGNED(width, 16)) {
  842. I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
  843. }
  844. }
  845. #endif
  846. #if defined(HAS_I422TOARGB4444ROW_NEON)
  847. if (TestCpuFlag(kCpuHasNEON)) {
  848. I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
  849. if (IS_ALIGNED(width, 8)) {
  850. I422ToARGB4444Row = I422ToARGB4444Row_NEON;
  851. }
  852. }
  853. #endif
  854. #if defined(HAS_I422TOARGB4444ROW_MSA)
  855. if (TestCpuFlag(kCpuHasMSA)) {
  856. I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
  857. if (IS_ALIGNED(width, 8)) {
  858. I422ToARGB4444Row = I422ToARGB4444Row_MSA;
  859. }
  860. }
  861. #endif
  862. for (y = 0; y < height; ++y) {
  863. I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
  864. width);
  865. dst_argb4444 += dst_stride_argb4444;
  866. src_y += src_stride_y;
  867. if (y & 1) {
  868. src_u += src_stride_u;
  869. src_v += src_stride_v;
  870. }
  871. }
  872. return 0;
  873. }
  874. // Convert I420 to RGB565.
  875. LIBYUV_API
  876. int I420ToRGB565(const uint8_t* src_y,
  877. int src_stride_y,
  878. const uint8_t* src_u,
  879. int src_stride_u,
  880. const uint8_t* src_v,
  881. int src_stride_v,
  882. uint8_t* dst_rgb565,
  883. int dst_stride_rgb565,
  884. int width,
  885. int height) {
  886. int y;
  887. void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  888. const uint8_t* v_buf, uint8_t* rgb_buf,
  889. const struct YuvConstants* yuvconstants, int width) =
  890. I422ToRGB565Row_C;
  891. if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
  892. return -1;
  893. }
  894. // Negative height means invert the image.
  895. if (height < 0) {
  896. height = -height;
  897. dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
  898. dst_stride_rgb565 = -dst_stride_rgb565;
  899. }
  900. #if defined(HAS_I422TORGB565ROW_SSSE3)
  901. if (TestCpuFlag(kCpuHasSSSE3)) {
  902. I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
  903. if (IS_ALIGNED(width, 8)) {
  904. I422ToRGB565Row = I422ToRGB565Row_SSSE3;
  905. }
  906. }
  907. #endif
  908. #if defined(HAS_I422TORGB565ROW_AVX2)
  909. if (TestCpuFlag(kCpuHasAVX2)) {
  910. I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
  911. if (IS_ALIGNED(width, 16)) {
  912. I422ToRGB565Row = I422ToRGB565Row_AVX2;
  913. }
  914. }
  915. #endif
  916. #if defined(HAS_I422TORGB565ROW_NEON)
  917. if (TestCpuFlag(kCpuHasNEON)) {
  918. I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
  919. if (IS_ALIGNED(width, 8)) {
  920. I422ToRGB565Row = I422ToRGB565Row_NEON;
  921. }
  922. }
  923. #endif
  924. #if defined(HAS_I422TORGB565ROW_MSA)
  925. if (TestCpuFlag(kCpuHasMSA)) {
  926. I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
  927. if (IS_ALIGNED(width, 8)) {
  928. I422ToRGB565Row = I422ToRGB565Row_MSA;
  929. }
  930. }
  931. #endif
  932. for (y = 0; y < height; ++y) {
  933. I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
  934. dst_rgb565 += dst_stride_rgb565;
  935. src_y += src_stride_y;
  936. if (y & 1) {
  937. src_u += src_stride_u;
  938. src_v += src_stride_v;
  939. }
  940. }
  941. return 0;
  942. }
  943. // Convert I422 to RGB565.
  944. LIBYUV_API
  945. int I422ToRGB565(const uint8_t* src_y,
  946. int src_stride_y,
  947. const uint8_t* src_u,
  948. int src_stride_u,
  949. const uint8_t* src_v,
  950. int src_stride_v,
  951. uint8_t* dst_rgb565,
  952. int dst_stride_rgb565,
  953. int width,
  954. int height) {
  955. int y;
  956. void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  957. const uint8_t* v_buf, uint8_t* rgb_buf,
  958. const struct YuvConstants* yuvconstants, int width) =
  959. I422ToRGB565Row_C;
  960. if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
  961. return -1;
  962. }
  963. // Negative height means invert the image.
  964. if (height < 0) {
  965. height = -height;
  966. dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
  967. dst_stride_rgb565 = -dst_stride_rgb565;
  968. }
  969. #if defined(HAS_I422TORGB565ROW_SSSE3)
  970. if (TestCpuFlag(kCpuHasSSSE3)) {
  971. I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
  972. if (IS_ALIGNED(width, 8)) {
  973. I422ToRGB565Row = I422ToRGB565Row_SSSE3;
  974. }
  975. }
  976. #endif
  977. #if defined(HAS_I422TORGB565ROW_AVX2)
  978. if (TestCpuFlag(kCpuHasAVX2)) {
  979. I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
  980. if (IS_ALIGNED(width, 16)) {
  981. I422ToRGB565Row = I422ToRGB565Row_AVX2;
  982. }
  983. }
  984. #endif
  985. #if defined(HAS_I422TORGB565ROW_NEON)
  986. if (TestCpuFlag(kCpuHasNEON)) {
  987. I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
  988. if (IS_ALIGNED(width, 8)) {
  989. I422ToRGB565Row = I422ToRGB565Row_NEON;
  990. }
  991. }
  992. #endif
  993. #if defined(HAS_I422TORGB565ROW_MSA)
  994. if (TestCpuFlag(kCpuHasMSA)) {
  995. I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
  996. if (IS_ALIGNED(width, 8)) {
  997. I422ToRGB565Row = I422ToRGB565Row_MSA;
  998. }
  999. }
  1000. #endif
  1001. for (y = 0; y < height; ++y) {
  1002. I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
  1003. dst_rgb565 += dst_stride_rgb565;
  1004. src_y += src_stride_y;
  1005. src_u += src_stride_u;
  1006. src_v += src_stride_v;
  1007. }
  1008. return 0;
  1009. }
  1010. // Ordered 8x8 dither for 888 to 565. Values from 0 to 7.
  1011. static const uint8_t kDither565_4x4[16] = {
  1012. 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
  1013. };
  1014. // Convert I420 to RGB565 with dithering.
  1015. LIBYUV_API
  1016. int I420ToRGB565Dither(const uint8_t* src_y,
  1017. int src_stride_y,
  1018. const uint8_t* src_u,
  1019. int src_stride_u,
  1020. const uint8_t* src_v,
  1021. int src_stride_v,
  1022. uint8_t* dst_rgb565,
  1023. int dst_stride_rgb565,
  1024. const uint8_t* dither4x4,
  1025. int width,
  1026. int height) {
  1027. int y;
  1028. void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
  1029. const uint8_t* v_buf, uint8_t* rgb_buf,
  1030. const struct YuvConstants* yuvconstants, int width) =
  1031. I422ToARGBRow_C;
  1032. void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb,
  1033. const uint32_t dither4, int width) =
  1034. ARGBToRGB565DitherRow_C;
  1035. if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
  1036. return -1;
  1037. }
  1038. // Negative height means invert the image.
  1039. if (height < 0) {
  1040. height = -height;
  1041. dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
  1042. dst_stride_rgb565 = -dst_stride_rgb565;
  1043. }
  1044. if (!dither4x4) {
  1045. dither4x4 = kDither565_4x4;
  1046. }
  1047. #if defined(HAS_I422TOARGBROW_SSSE3)
  1048. if (TestCpuFlag(kCpuHasSSSE3)) {
  1049. I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
  1050. if (IS_ALIGNED(width, 8)) {
  1051. I422ToARGBRow = I422ToARGBRow_SSSE3;
  1052. }
  1053. }
  1054. #endif
  1055. #if defined(HAS_I422TOARGBROW_AVX2)
  1056. if (TestCpuFlag(kCpuHasAVX2)) {
  1057. I422ToARGBRow = I422ToARGBRow_Any_AVX2;
  1058. if (IS_ALIGNED(width, 16)) {
  1059. I422ToARGBRow = I422ToARGBRow_AVX2;
  1060. }
  1061. }
  1062. #endif
  1063. #if defined(HAS_I422TOARGBROW_NEON)
  1064. if (TestCpuFlag(kCpuHasNEON)) {
  1065. I422ToARGBRow = I422ToARGBRow_Any_NEON;
  1066. if (IS_ALIGNED(width, 8)) {
  1067. I422ToARGBRow = I422ToARGBRow_NEON;
  1068. }
  1069. }
  1070. #endif
  1071. #if defined(HAS_I422TOARGBROW_MSA)
  1072. if (TestCpuFlag(kCpuHasMSA)) {
  1073. I422ToARGBRow = I422ToARGBRow_Any_MSA;
  1074. if (IS_ALIGNED(width, 8)) {
  1075. I422ToARGBRow = I422ToARGBRow_MSA;
  1076. }
  1077. }
  1078. #endif
  1079. #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
  1080. if (TestCpuFlag(kCpuHasSSE2)) {
  1081. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
  1082. if (IS_ALIGNED(width, 4)) {
  1083. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
  1084. }
  1085. }
  1086. #endif
  1087. #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
  1088. if (TestCpuFlag(kCpuHasAVX2)) {
  1089. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
  1090. if (IS_ALIGNED(width, 8)) {
  1091. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
  1092. }
  1093. }
  1094. #endif
  1095. #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
  1096. if (TestCpuFlag(kCpuHasNEON)) {
  1097. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
  1098. if (IS_ALIGNED(width, 8)) {
  1099. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
  1100. }
  1101. }
  1102. #endif
  1103. #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
  1104. if (TestCpuFlag(kCpuHasMSA)) {
  1105. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
  1106. if (IS_ALIGNED(width, 8)) {
  1107. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
  1108. }
  1109. }
  1110. #endif
  1111. {
  1112. // Allocate a row of argb.
  1113. align_buffer_64(row_argb, width * 4);
  1114. for (y = 0; y < height; ++y) {
  1115. I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
  1116. ARGBToRGB565DitherRow(row_argb, dst_rgb565,
  1117. *(const uint32_t*)(dither4x4 + ((y & 3) << 2)),
  1118. width);
  1119. dst_rgb565 += dst_stride_rgb565;
  1120. src_y += src_stride_y;
  1121. if (y & 1) {
  1122. src_u += src_stride_u;
  1123. src_v += src_stride_v;
  1124. }
  1125. }
  1126. free_aligned_buffer_64(row_argb);
  1127. }
  1128. return 0;
  1129. }
  1130. // Convert I420 to AR30 with matrix
  1131. static int I420ToAR30Matrix(const uint8_t* src_y,
  1132. int src_stride_y,
  1133. const uint8_t* src_u,
  1134. int src_stride_u,
  1135. const uint8_t* src_v,
  1136. int src_stride_v,
  1137. uint8_t* dst_ar30,
  1138. int dst_stride_ar30,
  1139. const struct YuvConstants* yuvconstants,
  1140. int width,
  1141. int height) {
  1142. int y;
  1143. void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf,
  1144. const uint8_t* v_buf, uint8_t* rgb_buf,
  1145. const struct YuvConstants* yuvconstants, int width) =
  1146. I422ToAR30Row_C;
  1147. if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
  1148. return -1;
  1149. }
  1150. // Negative height means invert the image.
  1151. if (height < 0) {
  1152. height = -height;
  1153. dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
  1154. dst_stride_ar30 = -dst_stride_ar30;
  1155. }
  1156. #if defined(HAS_I422TOAR30ROW_SSSE3)
  1157. if (TestCpuFlag(kCpuHasSSSE3)) {
  1158. I422ToAR30Row = I422ToAR30Row_Any_SSSE3;
  1159. if (IS_ALIGNED(width, 8)) {
  1160. I422ToAR30Row = I422ToAR30Row_SSSE3;
  1161. }
  1162. }
  1163. #endif
  1164. #if defined(HAS_I422TOAR30ROW_AVX2)
  1165. if (TestCpuFlag(kCpuHasAVX2)) {
  1166. I422ToAR30Row = I422ToAR30Row_Any_AVX2;
  1167. if (IS_ALIGNED(width, 16)) {
  1168. I422ToAR30Row = I422ToAR30Row_AVX2;
  1169. }
  1170. }
  1171. #endif
  1172. for (y = 0; y < height; ++y) {
  1173. I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
  1174. dst_ar30 += dst_stride_ar30;
  1175. src_y += src_stride_y;
  1176. if (y & 1) {
  1177. src_u += src_stride_u;
  1178. src_v += src_stride_v;
  1179. }
  1180. }
  1181. return 0;
  1182. }
  1183. // Convert I420 to AR30.
  1184. LIBYUV_API
  1185. int I420ToAR30(const uint8_t* src_y,
  1186. int src_stride_y,
  1187. const uint8_t* src_u,
  1188. int src_stride_u,
  1189. const uint8_t* src_v,
  1190. int src_stride_v,
  1191. uint8_t* dst_ar30,
  1192. int dst_stride_ar30,
  1193. int width,
  1194. int height) {
  1195. return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
  1196. src_stride_v, dst_ar30, dst_stride_ar30,
  1197. &kYuvI601Constants, width, height);
  1198. }
  1199. // Convert H420 to AR30.
  1200. LIBYUV_API
  1201. int H420ToAR30(const uint8_t* src_y,
  1202. int src_stride_y,
  1203. const uint8_t* src_u,
  1204. int src_stride_u,
  1205. const uint8_t* src_v,
  1206. int src_stride_v,
  1207. uint8_t* dst_ar30,
  1208. int dst_stride_ar30,
  1209. int width,
  1210. int height) {
  1211. return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
  1212. src_stride_v, dst_ar30, dst_stride_ar30,
  1213. &kYvuH709Constants, width, height);
  1214. }
  1215. // Convert I420 to specified format
  1216. LIBYUV_API
  1217. int ConvertFromI420(const uint8_t* y,
  1218. int y_stride,
  1219. const uint8_t* u,
  1220. int u_stride,
  1221. const uint8_t* v,
  1222. int v_stride,
  1223. uint8_t* dst_sample,
  1224. int dst_sample_stride,
  1225. int width,
  1226. int height,
  1227. uint32_t fourcc) {
  1228. uint32_t format = CanonicalFourCC(fourcc);
  1229. int r = 0;
  1230. if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
  1231. return -1;
  1232. }
  1233. switch (format) {
  1234. // Single plane formats
  1235. case FOURCC_YUY2:
  1236. r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1237. dst_sample_stride ? dst_sample_stride : width * 2, width,
  1238. height);
  1239. break;
  1240. case FOURCC_UYVY:
  1241. r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1242. dst_sample_stride ? dst_sample_stride : width * 2, width,
  1243. height);
  1244. break;
  1245. case FOURCC_RGBP:
  1246. r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1247. dst_sample_stride ? dst_sample_stride : width * 2, width,
  1248. height);
  1249. break;
  1250. case FOURCC_RGBO:
  1251. r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1252. dst_sample_stride ? dst_sample_stride : width * 2,
  1253. width, height);
  1254. break;
  1255. case FOURCC_R444:
  1256. r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1257. dst_sample_stride ? dst_sample_stride : width * 2,
  1258. width, height);
  1259. break;
  1260. case FOURCC_24BG:
  1261. r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1262. dst_sample_stride ? dst_sample_stride : width * 3, width,
  1263. height);
  1264. break;
  1265. case FOURCC_RAW:
  1266. r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1267. dst_sample_stride ? dst_sample_stride : width * 3, width,
  1268. height);
  1269. break;
  1270. case FOURCC_ARGB:
  1271. r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1272. dst_sample_stride ? dst_sample_stride : width * 4, width,
  1273. height);
  1274. break;
  1275. case FOURCC_BGRA:
  1276. r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1277. dst_sample_stride ? dst_sample_stride : width * 4, width,
  1278. height);
  1279. break;
  1280. case FOURCC_ABGR:
  1281. r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1282. dst_sample_stride ? dst_sample_stride : width * 4, width,
  1283. height);
  1284. break;
  1285. case FOURCC_RGBA:
  1286. r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1287. dst_sample_stride ? dst_sample_stride : width * 4, width,
  1288. height);
  1289. break;
  1290. case FOURCC_AR30:
  1291. r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1292. dst_sample_stride ? dst_sample_stride : width * 4, width,
  1293. height);
  1294. break;
  1295. case FOURCC_I400:
  1296. r = I400Copy(y, y_stride, dst_sample,
  1297. dst_sample_stride ? dst_sample_stride : width, width,
  1298. height);
  1299. break;
  1300. case FOURCC_NV12: {
  1301. uint8_t* dst_uv = dst_sample + width * height;
  1302. r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1303. dst_sample_stride ? dst_sample_stride : width, dst_uv,
  1304. dst_sample_stride ? dst_sample_stride : width, width,
  1305. height);
  1306. break;
  1307. }
  1308. case FOURCC_NV21: {
  1309. uint8_t* dst_vu = dst_sample + width * height;
  1310. r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1311. dst_sample_stride ? dst_sample_stride : width, dst_vu,
  1312. dst_sample_stride ? dst_sample_stride : width, width,
  1313. height);
  1314. break;
  1315. }
  1316. // TODO(fbarchard): Add M420.
  1317. // Triplanar formats
  1318. case FOURCC_I420:
  1319. case FOURCC_YV12: {
  1320. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  1321. int halfstride = (dst_sample_stride + 1) / 2;
  1322. int halfheight = (height + 1) / 2;
  1323. uint8_t* dst_u;
  1324. uint8_t* dst_v;
  1325. if (format == FOURCC_YV12) {
  1326. dst_v = dst_sample + dst_sample_stride * height;
  1327. dst_u = dst_v + halfstride * halfheight;
  1328. } else {
  1329. dst_u = dst_sample + dst_sample_stride * height;
  1330. dst_v = dst_u + halfstride * halfheight;
  1331. }
  1332. r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1333. dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
  1334. width, height);
  1335. break;
  1336. }
  1337. case FOURCC_I422:
  1338. case FOURCC_YV16: {
  1339. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  1340. int halfstride = (dst_sample_stride + 1) / 2;
  1341. uint8_t* dst_u;
  1342. uint8_t* dst_v;
  1343. if (format == FOURCC_YV16) {
  1344. dst_v = dst_sample + dst_sample_stride * height;
  1345. dst_u = dst_v + halfstride * height;
  1346. } else {
  1347. dst_u = dst_sample + dst_sample_stride * height;
  1348. dst_v = dst_u + halfstride * height;
  1349. }
  1350. r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1351. dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
  1352. width, height);
  1353. break;
  1354. }
  1355. case FOURCC_I444:
  1356. case FOURCC_YV24: {
  1357. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  1358. uint8_t* dst_u;
  1359. uint8_t* dst_v;
  1360. if (format == FOURCC_YV24) {
  1361. dst_v = dst_sample + dst_sample_stride * height;
  1362. dst_u = dst_v + dst_sample_stride * height;
  1363. } else {
  1364. dst_u = dst_sample + dst_sample_stride * height;
  1365. dst_v = dst_u + dst_sample_stride * height;
  1366. }
  1367. r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  1368. dst_sample_stride, dst_u, dst_sample_stride, dst_v,
  1369. dst_sample_stride, width, height);
  1370. break;
  1371. }
  1372. // Formats not supported - MJPG, biplanar, some rgb formats.
  1373. default:
  1374. return -1; // unknown fourcc - return failure code.
  1375. }
  1376. return r;
  1377. }
  1378. #ifdef __cplusplus
  1379. } // extern "C"
  1380. } // namespace libyuv
  1381. #endif