convert_from.cc 36 KB

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