convert_from.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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_MMI)
  285. if (TestCpuFlag(kCpuHasMMI)) {
  286. I422ToYUY2Row = I422ToYUY2Row_Any_MMI;
  287. if (IS_ALIGNED(width, 8)) {
  288. I422ToYUY2Row = I422ToYUY2Row_MMI;
  289. }
  290. }
  291. #endif
  292. #if defined(HAS_I422TOYUY2ROW_MSA)
  293. if (TestCpuFlag(kCpuHasMSA)) {
  294. I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
  295. if (IS_ALIGNED(width, 32)) {
  296. I422ToYUY2Row = I422ToYUY2Row_MSA;
  297. }
  298. }
  299. #endif
  300. for (y = 0; y < height - 1; y += 2) {
  301. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  302. I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
  303. dst_yuy2 + dst_stride_yuy2, width);
  304. src_y += src_stride_y * 2;
  305. src_u += src_stride_u;
  306. src_v += src_stride_v;
  307. dst_yuy2 += dst_stride_yuy2 * 2;
  308. }
  309. if (height & 1) {
  310. I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
  311. }
  312. return 0;
  313. }
  314. LIBYUV_API
  315. int I422ToUYVY(const uint8_t* src_y,
  316. int src_stride_y,
  317. const uint8_t* src_u,
  318. int src_stride_u,
  319. const uint8_t* src_v,
  320. int src_stride_v,
  321. uint8_t* dst_uyvy,
  322. int dst_stride_uyvy,
  323. int width,
  324. int height) {
  325. int y;
  326. void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
  327. const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
  328. I422ToUYVYRow_C;
  329. if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
  330. return -1;
  331. }
  332. // Negative height means invert the image.
  333. if (height < 0) {
  334. height = -height;
  335. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  336. dst_stride_uyvy = -dst_stride_uyvy;
  337. }
  338. // Coalesce rows.
  339. if (src_stride_y == width && src_stride_u * 2 == width &&
  340. src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
  341. width *= height;
  342. height = 1;
  343. src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
  344. }
  345. #if defined(HAS_I422TOUYVYROW_SSE2)
  346. if (TestCpuFlag(kCpuHasSSE2)) {
  347. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  348. if (IS_ALIGNED(width, 16)) {
  349. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  350. }
  351. }
  352. #endif
  353. #if defined(HAS_I422TOUYVYROW_AVX2)
  354. if (TestCpuFlag(kCpuHasAVX2)) {
  355. I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
  356. if (IS_ALIGNED(width, 32)) {
  357. I422ToUYVYRow = I422ToUYVYRow_AVX2;
  358. }
  359. }
  360. #endif
  361. #if defined(HAS_I422TOUYVYROW_NEON)
  362. if (TestCpuFlag(kCpuHasNEON)) {
  363. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  364. if (IS_ALIGNED(width, 16)) {
  365. I422ToUYVYRow = I422ToUYVYRow_NEON;
  366. }
  367. }
  368. #endif
  369. #if defined(HAS_I422TOUYVYROW_MMI)
  370. if (TestCpuFlag(kCpuHasMMI)) {
  371. I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
  372. if (IS_ALIGNED(width, 8)) {
  373. I422ToUYVYRow = I422ToUYVYRow_MMI;
  374. }
  375. }
  376. #endif
  377. #if defined(HAS_I422TOUYVYROW_MSA)
  378. if (TestCpuFlag(kCpuHasMSA)) {
  379. I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
  380. if (IS_ALIGNED(width, 32)) {
  381. I422ToUYVYRow = I422ToUYVYRow_MSA;
  382. }
  383. }
  384. #endif
  385. for (y = 0; y < height; ++y) {
  386. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  387. src_y += src_stride_y;
  388. src_u += src_stride_u;
  389. src_v += src_stride_v;
  390. dst_uyvy += dst_stride_uyvy;
  391. }
  392. return 0;
  393. }
  394. LIBYUV_API
  395. int I420ToUYVY(const uint8_t* src_y,
  396. int src_stride_y,
  397. const uint8_t* src_u,
  398. int src_stride_u,
  399. const uint8_t* src_v,
  400. int src_stride_v,
  401. uint8_t* dst_uyvy,
  402. int dst_stride_uyvy,
  403. int width,
  404. int height) {
  405. int y;
  406. void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
  407. const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
  408. I422ToUYVYRow_C;
  409. if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
  410. return -1;
  411. }
  412. // Negative height means invert the image.
  413. if (height < 0) {
  414. height = -height;
  415. dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
  416. dst_stride_uyvy = -dst_stride_uyvy;
  417. }
  418. #if defined(HAS_I422TOUYVYROW_SSE2)
  419. if (TestCpuFlag(kCpuHasSSE2)) {
  420. I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
  421. if (IS_ALIGNED(width, 16)) {
  422. I422ToUYVYRow = I422ToUYVYRow_SSE2;
  423. }
  424. }
  425. #endif
  426. #if defined(HAS_I422TOUYVYROW_AVX2)
  427. if (TestCpuFlag(kCpuHasAVX2)) {
  428. I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
  429. if (IS_ALIGNED(width, 32)) {
  430. I422ToUYVYRow = I422ToUYVYRow_AVX2;
  431. }
  432. }
  433. #endif
  434. #if defined(HAS_I422TOUYVYROW_NEON)
  435. if (TestCpuFlag(kCpuHasNEON)) {
  436. I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
  437. if (IS_ALIGNED(width, 16)) {
  438. I422ToUYVYRow = I422ToUYVYRow_NEON;
  439. }
  440. }
  441. #endif
  442. #if defined(HAS_I422TOUYVYROW_MMI)
  443. if (TestCpuFlag(kCpuHasMMI)) {
  444. I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
  445. if (IS_ALIGNED(width, 8)) {
  446. I422ToUYVYRow = I422ToUYVYRow_MMI;
  447. }
  448. }
  449. #endif
  450. #if defined(HAS_I422TOUYVYROW_MSA)
  451. if (TestCpuFlag(kCpuHasMSA)) {
  452. I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
  453. if (IS_ALIGNED(width, 32)) {
  454. I422ToUYVYRow = I422ToUYVYRow_MSA;
  455. }
  456. }
  457. #endif
  458. for (y = 0; y < height - 1; y += 2) {
  459. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  460. I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
  461. dst_uyvy + dst_stride_uyvy, width);
  462. src_y += src_stride_y * 2;
  463. src_u += src_stride_u;
  464. src_v += src_stride_v;
  465. dst_uyvy += dst_stride_uyvy * 2;
  466. }
  467. if (height & 1) {
  468. I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
  469. }
  470. return 0;
  471. }
  472. LIBYUV_API
  473. int I420ToNV12(const uint8_t* src_y,
  474. int src_stride_y,
  475. const uint8_t* src_u,
  476. int src_stride_u,
  477. const uint8_t* src_v,
  478. int src_stride_v,
  479. uint8_t* dst_y,
  480. int dst_stride_y,
  481. uint8_t* dst_uv,
  482. int dst_stride_uv,
  483. int width,
  484. int height) {
  485. int halfwidth = (width + 1) / 2;
  486. int halfheight = (height + 1) / 2;
  487. if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
  488. height == 0) {
  489. return -1;
  490. }
  491. // Negative height means invert the image.
  492. if (height < 0) {
  493. height = -height;
  494. halfheight = (height + 1) >> 1;
  495. src_y = src_y + (height - 1) * src_stride_y;
  496. src_u = src_u + (halfheight - 1) * src_stride_u;
  497. src_v = src_v + (halfheight - 1) * src_stride_v;
  498. src_stride_y = -src_stride_y;
  499. src_stride_u = -src_stride_u;
  500. src_stride_v = -src_stride_v;
  501. }
  502. if (dst_y) {
  503. CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
  504. }
  505. MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
  506. halfwidth, halfheight);
  507. return 0;
  508. }
  509. LIBYUV_API
  510. int I420ToNV21(const uint8_t* src_y,
  511. int src_stride_y,
  512. const uint8_t* src_u,
  513. int src_stride_u,
  514. const uint8_t* src_v,
  515. int src_stride_v,
  516. uint8_t* dst_y,
  517. int dst_stride_y,
  518. uint8_t* dst_vu,
  519. int dst_stride_vu,
  520. int width,
  521. int height) {
  522. return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
  523. src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
  524. width, height);
  525. }
  526. // Convert I420 to specified format
  527. LIBYUV_API
  528. int ConvertFromI420(const uint8_t* y,
  529. int y_stride,
  530. const uint8_t* u,
  531. int u_stride,
  532. const uint8_t* v,
  533. int v_stride,
  534. uint8_t* dst_sample,
  535. int dst_sample_stride,
  536. int width,
  537. int height,
  538. uint32_t fourcc) {
  539. uint32_t format = CanonicalFourCC(fourcc);
  540. int r = 0;
  541. if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
  542. return -1;
  543. }
  544. switch (format) {
  545. // Single plane formats
  546. case FOURCC_YUY2:
  547. r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  548. dst_sample_stride ? dst_sample_stride : width * 2, width,
  549. height);
  550. break;
  551. case FOURCC_UYVY:
  552. r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  553. dst_sample_stride ? dst_sample_stride : width * 2, width,
  554. height);
  555. break;
  556. case FOURCC_RGBP:
  557. r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  558. dst_sample_stride ? dst_sample_stride : width * 2, width,
  559. height);
  560. break;
  561. case FOURCC_RGBO:
  562. r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  563. dst_sample_stride ? dst_sample_stride : width * 2,
  564. width, height);
  565. break;
  566. case FOURCC_R444:
  567. r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  568. dst_sample_stride ? dst_sample_stride : width * 2,
  569. width, height);
  570. break;
  571. case FOURCC_24BG:
  572. r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  573. dst_sample_stride ? dst_sample_stride : width * 3, width,
  574. height);
  575. break;
  576. case FOURCC_RAW:
  577. r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  578. dst_sample_stride ? dst_sample_stride : width * 3, width,
  579. height);
  580. break;
  581. case FOURCC_ARGB:
  582. r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  583. dst_sample_stride ? dst_sample_stride : width * 4, width,
  584. height);
  585. break;
  586. case FOURCC_BGRA:
  587. r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  588. dst_sample_stride ? dst_sample_stride : width * 4, width,
  589. height);
  590. break;
  591. case FOURCC_ABGR:
  592. r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  593. dst_sample_stride ? dst_sample_stride : width * 4, width,
  594. height);
  595. break;
  596. case FOURCC_RGBA:
  597. r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  598. dst_sample_stride ? dst_sample_stride : width * 4, width,
  599. height);
  600. break;
  601. case FOURCC_AR30:
  602. r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  603. dst_sample_stride ? dst_sample_stride : width * 4, width,
  604. height);
  605. break;
  606. case FOURCC_I400:
  607. r = I400Copy(y, y_stride, dst_sample,
  608. dst_sample_stride ? dst_sample_stride : width, width,
  609. height);
  610. break;
  611. case FOURCC_NV12: {
  612. uint8_t* dst_uv = dst_sample + width * height;
  613. r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  614. dst_sample_stride ? dst_sample_stride : width, dst_uv,
  615. dst_sample_stride ? dst_sample_stride : width, width,
  616. height);
  617. break;
  618. }
  619. case FOURCC_NV21: {
  620. uint8_t* dst_vu = dst_sample + width * height;
  621. r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  622. dst_sample_stride ? dst_sample_stride : width, dst_vu,
  623. dst_sample_stride ? dst_sample_stride : width, width,
  624. height);
  625. break;
  626. }
  627. // Triplanar formats
  628. case FOURCC_I420:
  629. case FOURCC_YV12: {
  630. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  631. int halfstride = (dst_sample_stride + 1) / 2;
  632. int halfheight = (height + 1) / 2;
  633. uint8_t* dst_u;
  634. uint8_t* dst_v;
  635. if (format == FOURCC_YV12) {
  636. dst_v = dst_sample + dst_sample_stride * height;
  637. dst_u = dst_v + halfstride * halfheight;
  638. } else {
  639. dst_u = dst_sample + dst_sample_stride * height;
  640. dst_v = dst_u + halfstride * halfheight;
  641. }
  642. r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  643. dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
  644. width, height);
  645. break;
  646. }
  647. case FOURCC_I422:
  648. case FOURCC_YV16: {
  649. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  650. int halfstride = (dst_sample_stride + 1) / 2;
  651. uint8_t* dst_u;
  652. uint8_t* dst_v;
  653. if (format == FOURCC_YV16) {
  654. dst_v = dst_sample + dst_sample_stride * height;
  655. dst_u = dst_v + halfstride * height;
  656. } else {
  657. dst_u = dst_sample + dst_sample_stride * height;
  658. dst_v = dst_u + halfstride * height;
  659. }
  660. r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  661. dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
  662. width, height);
  663. break;
  664. }
  665. case FOURCC_I444:
  666. case FOURCC_YV24: {
  667. dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
  668. uint8_t* dst_u;
  669. uint8_t* dst_v;
  670. if (format == FOURCC_YV24) {
  671. dst_v = dst_sample + dst_sample_stride * height;
  672. dst_u = dst_v + dst_sample_stride * height;
  673. } else {
  674. dst_u = dst_sample + dst_sample_stride * height;
  675. dst_v = dst_u + dst_sample_stride * height;
  676. }
  677. r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
  678. dst_sample_stride, dst_u, dst_sample_stride, dst_v,
  679. dst_sample_stride, width, height);
  680. break;
  681. }
  682. // Formats not supported - MJPG, biplanar, some rgb formats.
  683. default:
  684. return -1; // unknown fourcc - return failure code.
  685. }
  686. return r;
  687. }
  688. #ifdef __cplusplus
  689. } // extern "C"
  690. } // namespace libyuv
  691. #endif