convert_from.cc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  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/scale.h" // For ScalePlane()
  17. #include "libyuv/video_common.h"
  18. #include "libyuv/row.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* src_y, int src_stride_y,
  29. const uint8* src_u, int src_stride_u,
  30. const uint8* src_v, int src_stride_v,
  31. uint8* dst_y, int dst_stride_y,
  32. uint8* dst_u, int dst_stride_u,
  33. uint8* dst_v, int dst_stride_v,
  34. int src_y_width, int src_y_height,
  35. int dst_uv_width, int dst_uv_height) {
  36. const int dst_y_width = Abs(src_y_width);
  37. const int dst_y_height = Abs(src_y_height);
  38. const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
  39. const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
  40. if (src_y_width == 0 || src_y_height == 0 ||
  41. dst_uv_width <= 0 || dst_uv_height <= 0) {
  42. return -1;
  43. }
  44. ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
  45. dst_y, dst_stride_y, dst_y_width, dst_y_height,
  46. kFilterBilinear);
  47. ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
  48. dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
  49. kFilterBilinear);
  50. ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
  51. dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
  52. kFilterBilinear);
  53. return 0;
  54. }
  55. // 420 chroma is 1/2 width, 1/2 height
  56. // 422 chroma is 1/2 width, 1x height
  57. LIBYUV_API
  58. int I420ToI422(const uint8* src_y, int src_stride_y,
  59. const uint8* src_u, int src_stride_u,
  60. const uint8* src_v, int src_stride_v,
  61. uint8* dst_y, int dst_stride_y,
  62. uint8* dst_u, int dst_stride_u,
  63. uint8* dst_v, int dst_stride_v,
  64. int width, int height) {
  65. const int dst_uv_width = (Abs(width) + 1) >> 1;
  66. const int dst_uv_height = Abs(height);
  67. return I420ToI4xx(src_y, src_stride_y,
  68. src_u, src_stride_u,
  69. src_v, src_stride_v,
  70. dst_y, dst_stride_y,
  71. dst_u, dst_stride_u,
  72. dst_v, dst_stride_v,
  73. width, height,
  74. dst_uv_width, dst_uv_height);
  75. }
  76. // 420 chroma is 1/2 width, 1/2 height
  77. // 444 chroma is 1x width, 1x height
  78. LIBYUV_API
  79. int I420ToI444(const uint8* src_y, int src_stride_y,
  80. const uint8* src_u, int src_stride_u,
  81. const uint8* src_v, int src_stride_v,
  82. uint8* dst_y, int dst_stride_y,
  83. uint8* dst_u, int dst_stride_u,
  84. uint8* dst_v, int dst_stride_v,
  85. int width, int height) {
  86. const int dst_uv_width = Abs(width);
  87. const int dst_uv_height = Abs(height);
  88. return I420ToI4xx(src_y, src_stride_y,
  89. src_u, src_stride_u,
  90. src_v, src_stride_v,
  91. dst_y, dst_stride_y,
  92. dst_u, dst_stride_u,
  93. dst_v, dst_stride_v,
  94. width, height,
  95. dst_uv_width, dst_uv_height);
  96. }
  97. // 420 chroma is 1/2 width, 1/2 height
  98. // 411 chroma is 1/4 width, 1x height
  99. LIBYUV_API
  100. int I420ToI411(const uint8* src_y, int src_stride_y,
  101. const uint8* src_u, int src_stride_u,
  102. const uint8* src_v, int src_stride_v,
  103. uint8* dst_y, int dst_stride_y,
  104. uint8* dst_u, int dst_stride_u,
  105. uint8* dst_v, int dst_stride_v,
  106. int width, int height) {
  107. const int dst_uv_width = (Abs(width) + 3) >> 2;
  108. const int dst_uv_height = Abs(height);
  109. return I420ToI4xx(src_y, src_stride_y,
  110. src_u, src_stride_u,
  111. src_v, src_stride_v,
  112. dst_y, dst_stride_y,
  113. dst_u, dst_stride_u,
  114. dst_v, dst_stride_v,
  115. width, height,
  116. dst_uv_width, dst_uv_height);
  117. }
  118. // Copy to I400. Source can be I420,422,444,400,NV12,NV21
  119. LIBYUV_API
  120. int I400Copy(const uint8* src_y, int src_stride_y,
  121. uint8* dst_y, int dst_stride_y,
  122. int width, int height) {
  123. if (!src_y || !dst_y ||
  124. width <= 0 || height == 0) {
  125. return -1;
  126. }
  127. // Negative height means invert the image.
  128. if (height < 0) {
  129. height = -height;
  130. src_y = src_y + (height - 1) * src_stride_y;
  131. src_stride_y = -src_stride_y;
  132. }
  133. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  134. return 0;
  135. }
  136. LIBYUV_API
  137. int I422ToYUY2(const uint8* src_y, int src_stride_y,
  138. const uint8* src_u, int src_stride_u,
  139. const uint8* src_v, int src_stride_v,
  140. uint8* dst_yuy2, int dst_stride_yuy2,
  141. int width, int height) {
  142. int y;
  143. void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
  144. const uint8* src_v, uint8* dst_yuy2, int width) =
  145. I422ToYUY2Row_C;
  146. if (!src_y || !src_u || !src_v || !dst_yuy2 ||
  147. width <= 0 || height == 0) {
  148. return -1;
  149. }
  150. // Negative height means invert the image.
  151. if (height < 0) {
  152. height = -height;
  153. dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
  154. dst_stride_yuy2 = -dst_stride_yuy2;
  155. }
  156. // Coalesce rows.
  157. if (src_stride_y == width &&
  158. src_stride_u * 2 == width &&
  159. src_stride_v * 2 == width &&
  160. dst_stride_yuy2 == width * 2) {
  161. width *= height;
  162. height = 1;
  163. src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
  164. }
  165. #if defined(HAS_I422TOYUY2ROW_SSE2)
  166. if (TestCpuFlag(kCpuHasSSE2)) {
  167. I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
  168. if (IS_ALIGNED(width, 16)) {
  169. I422ToYUY2Row = I422ToYUY2Row_SSE2;
  170. }
  171. }
  172. #endif
  173. #if defined(HAS_I422TOYUY2ROW_NEON)
  174. if (TestCpuFlag(kCpuHasNEON)) {
  175. I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
  176. if (IS_ALIGNED(width, 16)) {
  177. I422ToYUY2Row = I422ToYUY2Row_NEON;
  178. }
  179. }
  180. #endif
  181. for (y = 0; y < height; ++y) {
  182. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  183. src_y += src_stride_y;
  184. src_u += src_stride_u;
  185. src_v += src_stride_v;
  186. dst_yuy2 += dst_stride_yuy2;
  187. }
  188. return 0;
  189. }
  190. LIBYUV_API
  191. int I420ToYUY2(const uint8* src_y, int src_stride_y,
  192. const uint8* src_u, int src_stride_u,
  193. const uint8* src_v, int src_stride_v,
  194. uint8* dst_yuy2, int dst_stride_yuy2,
  195. int width, int height) {
  196. int y;
  197. void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
  198. const uint8* src_v, uint8* dst_yuy2, int width) =
  199. I422ToYUY2Row_C;
  200. if (!src_y || !src_u || !src_v || !dst_yuy2 ||
  201. width <= 0 || height == 0) {
  202. return -1;
  203. }
  204. // Negative height means invert the image.
  205. if (height < 0) {
  206. height = -height;
  207. dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
  208. dst_stride_yuy2 = -dst_stride_yuy2;
  209. }
  210. #if defined(HAS_I422TOYUY2ROW_SSE2)
  211. if (TestCpuFlag(kCpuHasSSE2)) {
  212. I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
  213. if (IS_ALIGNED(width, 16)) {
  214. I422ToYUY2Row = I422ToYUY2Row_SSE2;
  215. }
  216. }
  217. #endif
  218. #if defined(HAS_I422TOYUY2ROW_NEON)
  219. if (TestCpuFlag(kCpuHasNEON)) {
  220. I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
  221. if (IS_ALIGNED(width, 16)) {
  222. I422ToYUY2Row = I422ToYUY2Row_NEON;
  223. }
  224. }
  225. #endif
  226. for (y = 0; y < height - 1; y += 2) {
  227. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  228. I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
  229. dst_yuy2 + dst_stride_yuy2, width);
  230. src_y += src_stride_y * 2;
  231. src_u += src_stride_u;
  232. src_v += src_stride_v;
  233. dst_yuy2 += dst_stride_yuy2 * 2;
  234. }
  235. if (height & 1) {
  236. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  237. }
  238. return 0;
  239. }
  240. LIBYUV_API
  241. int I422ToUYVY(const uint8* src_y, int src_stride_y,
  242. const uint8* src_u, int src_stride_u,
  243. const uint8* src_v, int src_stride_v,
  244. uint8* dst_uyvy, int dst_stride_uyvy,
  245. int width, int height) {
  246. int y;
  247. void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
  248. const uint8* src_v, uint8* dst_uyvy, int width) =
  249. I422ToUYVYRow_C;
  250. if (!src_y || !src_u || !src_v || !dst_uyvy ||
  251. width <= 0 || height == 0) {
  252. return -1;
  253. }
  254. // Negative height means invert the image.
  255. if (height < 0) {
  256. height = -height;
  257. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  258. dst_stride_uyvy = -dst_stride_uyvy;
  259. }
  260. // Coalesce rows.
  261. if (src_stride_y == width &&
  262. src_stride_u * 2 == width &&
  263. src_stride_v * 2 == width &&
  264. dst_stride_uyvy == width * 2) {
  265. width *= height;
  266. height = 1;
  267. src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
  268. }
  269. #if defined(HAS_I422TOUYVYROW_SSE2)
  270. if (TestCpuFlag(kCpuHasSSE2)) {
  271. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  272. if (IS_ALIGNED(width, 16)) {
  273. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  274. }
  275. }
  276. #endif
  277. #if defined(HAS_I422TOUYVYROW_NEON)
  278. if (TestCpuFlag(kCpuHasNEON)) {
  279. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  280. if (IS_ALIGNED(width, 16)) {
  281. I422ToUYVYRow = I422ToUYVYRow_NEON;
  282. }
  283. }
  284. #endif
  285. for (y = 0; y < height; ++y) {
  286. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  287. src_y += src_stride_y;
  288. src_u += src_stride_u;
  289. src_v += src_stride_v;
  290. dst_uyvy += dst_stride_uyvy;
  291. }
  292. return 0;
  293. }
  294. LIBYUV_API
  295. int I420ToUYVY(const uint8* src_y, int src_stride_y,
  296. const uint8* src_u, int src_stride_u,
  297. const uint8* src_v, int src_stride_v,
  298. uint8* dst_uyvy, int dst_stride_uyvy,
  299. int width, int height) {
  300. int y;
  301. void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
  302. const uint8* src_v, uint8* dst_uyvy, int width) =
  303. I422ToUYVYRow_C;
  304. if (!src_y || !src_u || !src_v || !dst_uyvy ||
  305. width <= 0 || height == 0) {
  306. return -1;
  307. }
  308. // Negative height means invert the image.
  309. if (height < 0) {
  310. height = -height;
  311. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  312. dst_stride_uyvy = -dst_stride_uyvy;
  313. }
  314. #if defined(HAS_I422TOUYVYROW_SSE2)
  315. if (TestCpuFlag(kCpuHasSSE2)) {
  316. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  317. if (IS_ALIGNED(width, 16)) {
  318. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  319. }
  320. }
  321. #endif
  322. #if defined(HAS_I422TOUYVYROW_NEON)
  323. if (TestCpuFlag(kCpuHasNEON)) {
  324. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  325. if (IS_ALIGNED(width, 16)) {
  326. I422ToUYVYRow = I422ToUYVYRow_NEON;
  327. }
  328. }
  329. #endif
  330. for (y = 0; y < height - 1; y += 2) {
  331. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  332. I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
  333. dst_uyvy + dst_stride_uyvy, width);
  334. src_y += src_stride_y * 2;
  335. src_u += src_stride_u;
  336. src_v += src_stride_v;
  337. dst_uyvy += dst_stride_uyvy * 2;
  338. }
  339. if (height & 1) {
  340. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  341. }
  342. return 0;
  343. }
  344. LIBYUV_API
  345. int I420ToNV12(const uint8* src_y, int src_stride_y,
  346. const uint8* src_u, int src_stride_u,
  347. const uint8* src_v, int src_stride_v,
  348. uint8* dst_y, int dst_stride_y,
  349. uint8* dst_uv, int dst_stride_uv,
  350. int width, int height) {
  351. int y;
  352. void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
  353. int width) = MergeUVRow_C;
  354. // Coalesce rows.
  355. int halfwidth = (width + 1) >> 1;
  356. int halfheight = (height + 1) >> 1;
  357. if (!src_y || !src_u || !src_v || !dst_y || !dst_uv ||
  358. width <= 0 || height == 0) {
  359. return -1;
  360. }
  361. // Negative height means invert the image.
  362. if (height < 0) {
  363. height = -height;
  364. halfheight = (height + 1) >> 1;
  365. dst_y = dst_y + (height - 1) * dst_stride_y;
  366. dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv;
  367. dst_stride_y = -dst_stride_y;
  368. dst_stride_uv = -dst_stride_uv;
  369. }
  370. if (src_stride_y == width &&
  371. dst_stride_y == width) {
  372. width *= height;
  373. height = 1;
  374. src_stride_y = dst_stride_y = 0;
  375. }
  376. // Coalesce rows.
  377. if (src_stride_u == halfwidth &&
  378. src_stride_v == halfwidth &&
  379. dst_stride_uv == halfwidth * 2) {
  380. halfwidth *= halfheight;
  381. halfheight = 1;
  382. src_stride_u = src_stride_v = dst_stride_uv = 0;
  383. }
  384. #if defined(HAS_MERGEUVROW_SSE2)
  385. if (TestCpuFlag(kCpuHasSSE2)) {
  386. MergeUVRow_ = MergeUVRow_Any_SSE2;
  387. if (IS_ALIGNED(halfwidth, 16)) {
  388. MergeUVRow_ = MergeUVRow_SSE2;
  389. }
  390. }
  391. #endif
  392. #if defined(HAS_MERGEUVROW_AVX2)
  393. if (TestCpuFlag(kCpuHasAVX2)) {
  394. MergeUVRow_ = MergeUVRow_Any_AVX2;
  395. if (IS_ALIGNED(halfwidth, 32)) {
  396. MergeUVRow_ = MergeUVRow_AVX2;
  397. }
  398. }
  399. #endif
  400. #if defined(HAS_MERGEUVROW_NEON)
  401. if (TestCpuFlag(kCpuHasNEON)) {
  402. MergeUVRow_ = MergeUVRow_Any_NEON;
  403. if (IS_ALIGNED(halfwidth, 16)) {
  404. MergeUVRow_ = MergeUVRow_NEON;
  405. }
  406. }
  407. #endif
  408. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  409. for (y = 0; y < halfheight; ++y) {
  410. // Merge a row of U and V into a row of UV.
  411. MergeUVRow_(src_u, src_v, dst_uv, halfwidth);
  412. src_u += src_stride_u;
  413. src_v += src_stride_v;
  414. dst_uv += dst_stride_uv;
  415. }
  416. return 0;
  417. }
  418. LIBYUV_API
  419. int I420ToNV21(const uint8* src_y, int src_stride_y,
  420. const uint8* src_u, int src_stride_u,
  421. const uint8* src_v, int src_stride_v,
  422. uint8* dst_y, int dst_stride_y,
  423. uint8* dst_vu, int dst_stride_vu,
  424. int width, int height) {
  425. return I420ToNV12(src_y, src_stride_y,
  426. src_v, src_stride_v,
  427. src_u, src_stride_u,
  428. dst_y, dst_stride_y,
  429. dst_vu, dst_stride_vu,
  430. width, height);
  431. }
  432. // Convert I422 to RGBA with matrix
  433. static int I420ToRGBAMatrix(const uint8* src_y, int src_stride_y,
  434. const uint8* src_u, int src_stride_u,
  435. const uint8* src_v, int src_stride_v,
  436. uint8* dst_rgba, int dst_stride_rgba,
  437. const struct YuvConstants* yuvconstants,
  438. int width, int height) {
  439. int y;
  440. void (*I422ToRGBARow)(const uint8* y_buf,
  441. const uint8* u_buf,
  442. const uint8* v_buf,
  443. uint8* rgb_buf,
  444. const struct YuvConstants* yuvconstants,
  445. int width) = I422ToRGBARow_C;
  446. if (!src_y || !src_u || !src_v || !dst_rgba ||
  447. width <= 0 || height == 0) {
  448. return -1;
  449. }
  450. // Negative height means invert the image.
  451. if (height < 0) {
  452. height = -height;
  453. dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
  454. dst_stride_rgba = -dst_stride_rgba;
  455. }
  456. #if defined(HAS_I422TORGBAROW_SSSE3)
  457. if (TestCpuFlag(kCpuHasSSSE3)) {
  458. I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
  459. if (IS_ALIGNED(width, 8)) {
  460. I422ToRGBARow = I422ToRGBARow_SSSE3;
  461. }
  462. }
  463. #endif
  464. #if defined(HAS_I422TORGBAROW_AVX2)
  465. if (TestCpuFlag(kCpuHasAVX2)) {
  466. I422ToRGBARow = I422ToRGBARow_Any_AVX2;
  467. if (IS_ALIGNED(width, 16)) {
  468. I422ToRGBARow = I422ToRGBARow_AVX2;
  469. }
  470. }
  471. #endif
  472. #if defined(HAS_I422TORGBAROW_NEON)
  473. if (TestCpuFlag(kCpuHasNEON)) {
  474. I422ToRGBARow = I422ToRGBARow_Any_NEON;
  475. if (IS_ALIGNED(width, 8)) {
  476. I422ToRGBARow = I422ToRGBARow_NEON;
  477. }
  478. }
  479. #endif
  480. #if defined(HAS_I422TORGBAROW_DSPR2)
  481. if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
  482. IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
  483. IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
  484. IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
  485. IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) {
  486. I422ToRGBARow = I422ToRGBARow_DSPR2;
  487. }
  488. #endif
  489. for (y = 0; y < height; ++y) {
  490. I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
  491. dst_rgba += dst_stride_rgba;
  492. src_y += src_stride_y;
  493. if (y & 1) {
  494. src_u += src_stride_u;
  495. src_v += src_stride_v;
  496. }
  497. }
  498. return 0;
  499. }
  500. // Convert I420 to RGBA.
  501. LIBYUV_API
  502. int I420ToRGBA(const uint8* src_y, int src_stride_y,
  503. const uint8* src_u, int src_stride_u,
  504. const uint8* src_v, int src_stride_v,
  505. uint8* dst_rgba, int dst_stride_rgba,
  506. int width, int height) {
  507. return I420ToRGBAMatrix(src_y, src_stride_y,
  508. src_u, src_stride_u,
  509. src_v, src_stride_v,
  510. dst_rgba, dst_stride_rgba,
  511. &kYuvI601Constants,
  512. width, height);
  513. }
  514. // Convert I420 to BGRA.
  515. LIBYUV_API
  516. int I420ToBGRA(const uint8* src_y, int src_stride_y,
  517. const uint8* src_u, int src_stride_u,
  518. const uint8* src_v, int src_stride_v,
  519. uint8* dst_bgra, int dst_stride_bgra,
  520. int width, int height) {
  521. return I420ToRGBAMatrix(src_y, src_stride_y,
  522. src_v, src_stride_v, // Swap U and V
  523. src_u, src_stride_u,
  524. dst_bgra, dst_stride_bgra,
  525. &kYvuI601Constants, // Use Yvu matrix
  526. width, height);
  527. }
  528. // Convert I420 to RGB24 with matrix
  529. static int I420ToRGB24Matrix(const uint8* src_y, int src_stride_y,
  530. const uint8* src_u, int src_stride_u,
  531. const uint8* src_v, int src_stride_v,
  532. uint8* dst_rgb24, int dst_stride_rgb24,
  533. const struct YuvConstants* yuvconstants,
  534. int width, int height) {
  535. int y;
  536. void (*I422ToRGB24Row)(const uint8* y_buf,
  537. const uint8* u_buf,
  538. const uint8* v_buf,
  539. uint8* rgb_buf,
  540. const struct YuvConstants* yuvconstants,
  541. int width) = I422ToRGB24Row_C;
  542. if (!src_y || !src_u || !src_v || !dst_rgb24 ||
  543. width <= 0 || height == 0) {
  544. return -1;
  545. }
  546. // Negative height means invert the image.
  547. if (height < 0) {
  548. height = -height;
  549. dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
  550. dst_stride_rgb24 = -dst_stride_rgb24;
  551. }
  552. #if defined(HAS_I422TORGB24ROW_SSSE3)
  553. if (TestCpuFlag(kCpuHasSSSE3)) {
  554. I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
  555. if (IS_ALIGNED(width, 8)) {
  556. I422ToRGB24Row = I422ToRGB24Row_SSSE3;
  557. }
  558. }
  559. #endif
  560. #if defined(HAS_I422TORGB24ROW_AVX2)
  561. if (TestCpuFlag(kCpuHasAVX2)) {
  562. I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
  563. if (IS_ALIGNED(width, 16)) {
  564. I422ToRGB24Row = I422ToRGB24Row_AVX2;
  565. }
  566. }
  567. #endif
  568. #if defined(HAS_I422TORGB24ROW_NEON)
  569. if (TestCpuFlag(kCpuHasNEON)) {
  570. I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
  571. if (IS_ALIGNED(width, 8)) {
  572. I422ToRGB24Row = I422ToRGB24Row_NEON;
  573. }
  574. }
  575. #endif
  576. for (y = 0; y < height; ++y) {
  577. I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
  578. dst_rgb24 += dst_stride_rgb24;
  579. src_y += src_stride_y;
  580. if (y & 1) {
  581. src_u += src_stride_u;
  582. src_v += src_stride_v;
  583. }
  584. }
  585. return 0;
  586. }
  587. // Convert I420 to RGB24.
  588. LIBYUV_API
  589. int I420ToRGB24(const uint8* src_y, int src_stride_y,
  590. const uint8* src_u, int src_stride_u,
  591. const uint8* src_v, int src_stride_v,
  592. uint8* dst_rgb24, int dst_stride_rgb24,
  593. int width, int height) {
  594. return I420ToRGB24Matrix(src_y, src_stride_y,
  595. src_u, src_stride_u,
  596. src_v, src_stride_v,
  597. dst_rgb24, dst_stride_rgb24,
  598. &kYuvI601Constants,
  599. width, height);
  600. }
  601. // Convert I420 to RAW.
  602. LIBYUV_API
  603. int I420ToRAW(const uint8* src_y, int src_stride_y,
  604. const uint8* src_u, int src_stride_u,
  605. const uint8* src_v, int src_stride_v,
  606. uint8* dst_raw, int dst_stride_raw,
  607. int width, int height) {
  608. return I420ToRGB24Matrix(src_y, src_stride_y,
  609. src_v, src_stride_v, // Swap U and V
  610. src_u, src_stride_u,
  611. dst_raw, dst_stride_raw,
  612. &kYvuI601Constants, // Use Yvu matrix
  613. width, height);
  614. }
  615. // Convert I420 to ARGB1555.
  616. LIBYUV_API
  617. int I420ToARGB1555(const uint8* src_y, int src_stride_y,
  618. const uint8* src_u, int src_stride_u,
  619. const uint8* src_v, int src_stride_v,
  620. uint8* dst_argb1555, int dst_stride_argb1555,
  621. int width, int height) {
  622. int y;
  623. void (*I422ToARGB1555Row)(const uint8* y_buf,
  624. const uint8* u_buf,
  625. const uint8* v_buf,
  626. uint8* rgb_buf,
  627. const struct YuvConstants* yuvconstants,
  628. int width) = I422ToARGB1555Row_C;
  629. if (!src_y || !src_u || !src_v || !dst_argb1555 ||
  630. width <= 0 || height == 0) {
  631. return -1;
  632. }
  633. // Negative height means invert the image.
  634. if (height < 0) {
  635. height = -height;
  636. dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
  637. dst_stride_argb1555 = -dst_stride_argb1555;
  638. }
  639. #if defined(HAS_I422TOARGB1555ROW_SSSE3)
  640. if (TestCpuFlag(kCpuHasSSSE3)) {
  641. I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
  642. if (IS_ALIGNED(width, 8)) {
  643. I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
  644. }
  645. }
  646. #endif
  647. #if defined(HAS_I422TOARGB1555ROW_AVX2)
  648. if (TestCpuFlag(kCpuHasAVX2)) {
  649. I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
  650. if (IS_ALIGNED(width, 16)) {
  651. I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
  652. }
  653. }
  654. #endif
  655. #if defined(HAS_I422TOARGB1555ROW_NEON)
  656. if (TestCpuFlag(kCpuHasNEON)) {
  657. I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
  658. if (IS_ALIGNED(width, 8)) {
  659. I422ToARGB1555Row = I422ToARGB1555Row_NEON;
  660. }
  661. }
  662. #endif
  663. for (y = 0; y < height; ++y) {
  664. I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
  665. width);
  666. dst_argb1555 += dst_stride_argb1555;
  667. src_y += src_stride_y;
  668. if (y & 1) {
  669. src_u += src_stride_u;
  670. src_v += src_stride_v;
  671. }
  672. }
  673. return 0;
  674. }
  675. // Convert I420 to ARGB4444.
  676. LIBYUV_API
  677. int I420ToARGB4444(const uint8* src_y, int src_stride_y,
  678. const uint8* src_u, int src_stride_u,
  679. const uint8* src_v, int src_stride_v,
  680. uint8* dst_argb4444, int dst_stride_argb4444,
  681. int width, int height) {
  682. int y;
  683. void (*I422ToARGB4444Row)(const uint8* y_buf,
  684. const uint8* u_buf,
  685. const uint8* v_buf,
  686. uint8* rgb_buf,
  687. const struct YuvConstants* yuvconstants,
  688. int width) = I422ToARGB4444Row_C;
  689. if (!src_y || !src_u || !src_v || !dst_argb4444 ||
  690. width <= 0 || height == 0) {
  691. return -1;
  692. }
  693. // Negative height means invert the image.
  694. if (height < 0) {
  695. height = -height;
  696. dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
  697. dst_stride_argb4444 = -dst_stride_argb4444;
  698. }
  699. #if defined(HAS_I422TOARGB4444ROW_SSSE3)
  700. if (TestCpuFlag(kCpuHasSSSE3)) {
  701. I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
  702. if (IS_ALIGNED(width, 8)) {
  703. I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
  704. }
  705. }
  706. #endif
  707. #if defined(HAS_I422TOARGB4444ROW_AVX2)
  708. if (TestCpuFlag(kCpuHasAVX2)) {
  709. I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
  710. if (IS_ALIGNED(width, 16)) {
  711. I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
  712. }
  713. }
  714. #endif
  715. #if defined(HAS_I422TOARGB4444ROW_NEON)
  716. if (TestCpuFlag(kCpuHasNEON)) {
  717. I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
  718. if (IS_ALIGNED(width, 8)) {
  719. I422ToARGB4444Row = I422ToARGB4444Row_NEON;
  720. }
  721. }
  722. #endif
  723. for (y = 0; y < height; ++y) {
  724. I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
  725. width);
  726. dst_argb4444 += dst_stride_argb4444;
  727. src_y += src_stride_y;
  728. if (y & 1) {
  729. src_u += src_stride_u;
  730. src_v += src_stride_v;
  731. }
  732. }
  733. return 0;
  734. }
  735. // Convert I420 to RGB565.
  736. LIBYUV_API
  737. int I420ToRGB565(const uint8* src_y, int src_stride_y,
  738. const uint8* src_u, int src_stride_u,
  739. const uint8* src_v, int src_stride_v,
  740. uint8* dst_rgb565, int dst_stride_rgb565,
  741. int width, int height) {
  742. int y;
  743. void (*I422ToRGB565Row)(const uint8* y_buf,
  744. const uint8* u_buf,
  745. const uint8* v_buf,
  746. uint8* rgb_buf,
  747. const struct YuvConstants* yuvconstants,
  748. int width) = I422ToRGB565Row_C;
  749. if (!src_y || !src_u || !src_v || !dst_rgb565 ||
  750. width <= 0 || height == 0) {
  751. return -1;
  752. }
  753. // Negative height means invert the image.
  754. if (height < 0) {
  755. height = -height;
  756. dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
  757. dst_stride_rgb565 = -dst_stride_rgb565;
  758. }
  759. #if defined(HAS_I422TORGB565ROW_SSSE3)
  760. if (TestCpuFlag(kCpuHasSSSE3)) {
  761. I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
  762. if (IS_ALIGNED(width, 8)) {
  763. I422ToRGB565Row = I422ToRGB565Row_SSSE3;
  764. }
  765. }
  766. #endif
  767. #if defined(HAS_I422TORGB565ROW_AVX2)
  768. if (TestCpuFlag(kCpuHasAVX2)) {
  769. I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
  770. if (IS_ALIGNED(width, 16)) {
  771. I422ToRGB565Row = I422ToRGB565Row_AVX2;
  772. }
  773. }
  774. #endif
  775. #if defined(HAS_I422TORGB565ROW_NEON)
  776. if (TestCpuFlag(kCpuHasNEON)) {
  777. I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
  778. if (IS_ALIGNED(width, 8)) {
  779. I422ToRGB565Row = I422ToRGB565Row_NEON;
  780. }
  781. }
  782. #endif
  783. for (y = 0; y < height; ++y) {
  784. I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
  785. dst_rgb565 += dst_stride_rgb565;
  786. src_y += src_stride_y;
  787. if (y & 1) {
  788. src_u += src_stride_u;
  789. src_v += src_stride_v;
  790. }
  791. }
  792. return 0;
  793. }
  794. // Ordered 8x8 dither for 888 to 565. Values from 0 to 7.
  795. static const uint8 kDither565_4x4[16] = {
  796. 0, 4, 1, 5,
  797. 6, 2, 7, 3,
  798. 1, 5, 0, 4,
  799. 7, 3, 6, 2,
  800. };
  801. // Convert I420 to RGB565 with dithering.
  802. LIBYUV_API
  803. int I420ToRGB565Dither(const uint8* src_y, int src_stride_y,
  804. const uint8* src_u, int src_stride_u,
  805. const uint8* src_v, int src_stride_v,
  806. uint8* dst_rgb565, int dst_stride_rgb565,
  807. const uint8* dither4x4, int width, int height) {
  808. int y;
  809. void (*I422ToARGBRow)(const uint8* y_buf,
  810. const uint8* u_buf,
  811. const uint8* v_buf,
  812. uint8* rgb_buf,
  813. const struct YuvConstants* yuvconstants,
  814. int width) = I422ToARGBRow_C;
  815. void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
  816. const uint32 dither4, int width) = ARGBToRGB565DitherRow_C;
  817. if (!src_y || !src_u || !src_v || !dst_rgb565 ||
  818. width <= 0 || height == 0) {
  819. return -1;
  820. }
  821. // Negative height means invert the image.
  822. if (height < 0) {
  823. height = -height;
  824. dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
  825. dst_stride_rgb565 = -dst_stride_rgb565;
  826. }
  827. if (!dither4x4) {
  828. dither4x4 = kDither565_4x4;
  829. }
  830. #if defined(HAS_I422TOARGBROW_SSSE3)
  831. if (TestCpuFlag(kCpuHasSSSE3)) {
  832. I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
  833. if (IS_ALIGNED(width, 8)) {
  834. I422ToARGBRow = I422ToARGBRow_SSSE3;
  835. }
  836. }
  837. #endif
  838. #if defined(HAS_I422TOARGBROW_AVX2)
  839. if (TestCpuFlag(kCpuHasAVX2)) {
  840. I422ToARGBRow = I422ToARGBRow_Any_AVX2;
  841. if (IS_ALIGNED(width, 16)) {
  842. I422ToARGBRow = I422ToARGBRow_AVX2;
  843. }
  844. }
  845. #endif
  846. #if defined(HAS_I422TOARGBROW_NEON)
  847. if (TestCpuFlag(kCpuHasNEON)) {
  848. I422ToARGBRow = I422ToARGBRow_Any_NEON;
  849. if (IS_ALIGNED(width, 8)) {
  850. I422ToARGBRow = I422ToARGBRow_NEON;
  851. }
  852. }
  853. #endif
  854. #if defined(HAS_I422TOARGBROW_DSPR2)
  855. if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
  856. IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
  857. IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
  858. IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
  859. I422ToARGBRow = I422ToARGBRow_DSPR2;
  860. }
  861. #endif
  862. #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
  863. if (TestCpuFlag(kCpuHasSSE2)) {
  864. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
  865. if (IS_ALIGNED(width, 4)) {
  866. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
  867. }
  868. }
  869. #endif
  870. #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
  871. if (TestCpuFlag(kCpuHasAVX2)) {
  872. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
  873. if (IS_ALIGNED(width, 8)) {
  874. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
  875. }
  876. }
  877. #endif
  878. #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
  879. if (TestCpuFlag(kCpuHasNEON)) {
  880. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
  881. if (IS_ALIGNED(width, 8)) {
  882. ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
  883. }
  884. }
  885. #endif
  886. {
  887. // Allocate a row of argb.
  888. align_buffer_64(row_argb, width * 4);
  889. for (y = 0; y < height; ++y) {
  890. I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
  891. ARGBToRGB565DitherRow(row_argb, dst_rgb565,
  892. *(uint32*)(dither4x4 + ((y & 3) << 2)), width);
  893. dst_rgb565 += dst_stride_rgb565;
  894. src_y += src_stride_y;
  895. if (y & 1) {
  896. src_u += src_stride_u;
  897. src_v += src_stride_v;
  898. }
  899. }
  900. free_aligned_buffer_64(row_argb);
  901. }
  902. return 0;
  903. }
  904. // Convert I420 to specified format
  905. LIBYUV_API
  906. int ConvertFromI420(const uint8* y, int y_stride,
  907. const uint8* u, int u_stride,
  908. const uint8* v, int v_stride,
  909. uint8* dst_sample, int dst_sample_stride,
  910. int width, int height,
  911. uint32 fourcc) {
  912. uint32 format = CanonicalFourCC(fourcc);
  913. int r = 0;
  914. if (!y || !u|| !v || !dst_sample ||
  915. width <= 0 || height == 0) {
  916. return -1;
  917. }
  918. switch (format) {
  919. // Single plane formats
  920. case FOURCC_YUY2:
  921. r = I420ToYUY2(y, y_stride,
  922. u, u_stride,
  923. v, v_stride,
  924. dst_sample,
  925. dst_sample_stride ? dst_sample_stride : width * 2,
  926. width, height);
  927. break;
  928. case FOURCC_UYVY:
  929. r = I420ToUYVY(y, y_stride,
  930. u, u_stride,
  931. v, v_stride,
  932. dst_sample,
  933. dst_sample_stride ? dst_sample_stride : width * 2,
  934. width, height);
  935. break;
  936. case FOURCC_RGBP:
  937. r = I420ToRGB565(y, y_stride,
  938. u, u_stride,
  939. v, v_stride,
  940. dst_sample,
  941. dst_sample_stride ? dst_sample_stride : width * 2,
  942. width, height);
  943. break;
  944. case FOURCC_RGBO:
  945. r = I420ToARGB1555(y, y_stride,
  946. u, u_stride,
  947. v, v_stride,
  948. dst_sample,
  949. dst_sample_stride ? dst_sample_stride : width * 2,
  950. width, height);
  951. break;
  952. case FOURCC_R444:
  953. r = I420ToARGB4444(y, y_stride,
  954. u, u_stride,
  955. v, v_stride,
  956. dst_sample,
  957. dst_sample_stride ? dst_sample_stride : width * 2,
  958. width, height);
  959. break;
  960. case FOURCC_24BG:
  961. r = I420ToRGB24(y, y_stride,
  962. u, u_stride,
  963. v, v_stride,
  964. dst_sample,
  965. dst_sample_stride ? dst_sample_stride : width * 3,
  966. width, height);
  967. break;
  968. case FOURCC_RAW:
  969. r = I420ToRAW(y, y_stride,
  970. u, u_stride,
  971. v, v_stride,
  972. dst_sample,
  973. dst_sample_stride ? dst_sample_stride : width * 3,
  974. width, height);
  975. break;
  976. case FOURCC_ARGB:
  977. r = I420ToARGB(y, y_stride,
  978. u, u_stride,
  979. v, v_stride,
  980. dst_sample,
  981. dst_sample_stride ? dst_sample_stride : width * 4,
  982. width, height);
  983. break;
  984. case FOURCC_BGRA:
  985. r = I420ToBGRA(y, y_stride,
  986. u, u_stride,
  987. v, v_stride,
  988. dst_sample,
  989. dst_sample_stride ? dst_sample_stride : width * 4,
  990. width, height);
  991. break;
  992. case FOURCC_ABGR:
  993. r = I420ToABGR(y, y_stride,
  994. u, u_stride,
  995. v, v_stride,
  996. dst_sample,
  997. dst_sample_stride ? dst_sample_stride : width * 4,
  998. width, height);
  999. break;
  1000. case FOURCC_RGBA:
  1001. r = I420ToRGBA(y, y_stride,
  1002. u, u_stride,
  1003. v, v_stride,
  1004. dst_sample,
  1005. dst_sample_stride ? dst_sample_stride : width * 4,
  1006. width, height);
  1007. break;
  1008. case FOURCC_I400:
  1009. r = I400Copy(y, y_stride,
  1010. dst_sample,
  1011. dst_sample_stride ? dst_sample_stride : width,
  1012. width, height);
  1013. break;
  1014. case FOURCC_NV12: {
  1015. uint8* dst_uv = dst_sample + width * height;
  1016. r = I420ToNV12(y, y_stride,
  1017. u, u_stride,
  1018. v, v_stride,
  1019. dst_sample,
  1020. dst_sample_stride ? dst_sample_stride : width,
  1021. dst_uv,
  1022. dst_sample_stride ? dst_sample_stride : width,
  1023. width, height);
  1024. break;
  1025. }
  1026. case FOURCC_NV21: {
  1027. uint8* dst_vu = dst_sample + width * height;
  1028. r = I420ToNV21(y, y_stride,
  1029. u, u_stride,
  1030. v, v_stride,
  1031. dst_sample,
  1032. dst_sample_stride ? dst_sample_stride : width,
  1033. dst_vu,
  1034. dst_sample_stride ? dst_sample_stride : width,
  1035. width, height);
  1036. break;
  1037. }
  1038. // TODO(fbarchard): Add M420.
  1039. // Triplanar formats
  1040. // TODO(fbarchard): halfstride instead of halfwidth
  1041. case FOURCC_I420:
  1042. case FOURCC_YV12: {
  1043. int halfwidth = (width + 1) / 2;
  1044. int halfheight = (height + 1) / 2;
  1045. uint8* dst_u;
  1046. uint8* dst_v;
  1047. if (format == FOURCC_YV12) {
  1048. dst_v = dst_sample + width * height;
  1049. dst_u = dst_v + halfwidth * halfheight;
  1050. } else {
  1051. dst_u = dst_sample + width * height;
  1052. dst_v = dst_u + halfwidth * halfheight;
  1053. }
  1054. r = I420Copy(y, y_stride,
  1055. u, u_stride,
  1056. v, v_stride,
  1057. dst_sample, width,
  1058. dst_u, halfwidth,
  1059. dst_v, halfwidth,
  1060. width, height);
  1061. break;
  1062. }
  1063. case FOURCC_I422:
  1064. case FOURCC_YV16: {
  1065. int halfwidth = (width + 1) / 2;
  1066. uint8* dst_u;
  1067. uint8* dst_v;
  1068. if (format == FOURCC_YV16) {
  1069. dst_v = dst_sample + width * height;
  1070. dst_u = dst_v + halfwidth * height;
  1071. } else {
  1072. dst_u = dst_sample + width * height;
  1073. dst_v = dst_u + halfwidth * height;
  1074. }
  1075. r = I420ToI422(y, y_stride,
  1076. u, u_stride,
  1077. v, v_stride,
  1078. dst_sample, width,
  1079. dst_u, halfwidth,
  1080. dst_v, halfwidth,
  1081. width, height);
  1082. break;
  1083. }
  1084. case FOURCC_I444:
  1085. case FOURCC_YV24: {
  1086. uint8* dst_u;
  1087. uint8* dst_v;
  1088. if (format == FOURCC_YV24) {
  1089. dst_v = dst_sample + width * height;
  1090. dst_u = dst_v + width * height;
  1091. } else {
  1092. dst_u = dst_sample + width * height;
  1093. dst_v = dst_u + width * height;
  1094. }
  1095. r = I420ToI444(y, y_stride,
  1096. u, u_stride,
  1097. v, v_stride,
  1098. dst_sample, width,
  1099. dst_u, width,
  1100. dst_v, width,
  1101. width, height);
  1102. break;
  1103. }
  1104. case FOURCC_I411: {
  1105. int quarterwidth = (width + 3) / 4;
  1106. uint8* dst_u = dst_sample + width * height;
  1107. uint8* dst_v = dst_u + quarterwidth * height;
  1108. r = I420ToI411(y, y_stride,
  1109. u, u_stride,
  1110. v, v_stride,
  1111. dst_sample, width,
  1112. dst_u, quarterwidth,
  1113. dst_v, quarterwidth,
  1114. width, height);
  1115. break;
  1116. }
  1117. // Formats not supported - MJPG, biplanar, some rgb formats.
  1118. default:
  1119. return -1; // unknown fourcc - return failure code.
  1120. }
  1121. return r;
  1122. }
  1123. #ifdef __cplusplus
  1124. } // extern "C"
  1125. } // namespace libyuv
  1126. #endif