convert_to_argb.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. * Copyright 2011 The LibYuv Project Authors. All rights reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include "libyuv/convert_argb.h"
  11. #include "libyuv/cpu_id.h"
  12. #ifdef HAVE_JPEG
  13. #include "libyuv/mjpeg_decoder.h"
  14. #endif
  15. #include "libyuv/rotate_argb.h"
  16. #include "libyuv/row.h"
  17. #include "libyuv/video_common.h"
  18. #ifdef __cplusplus
  19. namespace libyuv {
  20. extern "C" {
  21. #endif
  22. // Convert camera sample to ARGB with cropping, rotation and vertical flip.
  23. // src_width is used for source stride computation
  24. // src_height is used to compute location of planes, and indicate inversion
  25. // sample_size is measured in bytes and is the size of the frame.
  26. // With MJPEG it is the compressed size of the frame.
  27. // TODO(fbarchard): Add the following:
  28. // H010ToARGB
  29. // I010ToARGB
  30. LIBYUV_API
  31. int ConvertToARGB(const uint8_t* sample,
  32. size_t sample_size,
  33. uint8_t* dst_argb,
  34. int dst_stride_argb,
  35. int crop_x,
  36. int crop_y,
  37. int src_width,
  38. int src_height,
  39. int crop_width,
  40. int crop_height,
  41. enum RotationMode rotation,
  42. uint32_t fourcc) {
  43. uint32_t format = CanonicalFourCC(fourcc);
  44. int aligned_src_width = (src_width + 1) & ~1;
  45. const uint8_t* src;
  46. const uint8_t* src_uv;
  47. int abs_src_height = (src_height < 0) ? -src_height : src_height;
  48. int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  49. int r = 0;
  50. // One pass rotation is available for some formats. For the rest, convert
  51. // to ARGB (with optional vertical flipping) into a temporary ARGB buffer,
  52. // and then rotate the ARGB to the final destination buffer.
  53. // For in-place conversion, if destination dst_argb is same as source sample,
  54. // also enable temporary buffer.
  55. LIBYUV_BOOL need_buf =
  56. (rotation && format != FOURCC_ARGB) || dst_argb == sample;
  57. uint8_t* dest_argb = dst_argb;
  58. int dest_dst_stride_argb = dst_stride_argb;
  59. uint8_t* rotate_buffer = NULL;
  60. int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  61. if (dst_argb == NULL || sample == NULL || src_width <= 0 || crop_width <= 0 ||
  62. src_height == 0 || crop_height == 0) {
  63. return -1;
  64. }
  65. if (src_height < 0) {
  66. inv_crop_height = -inv_crop_height;
  67. }
  68. if (need_buf) {
  69. int argb_size = crop_width * 4 * abs_crop_height;
  70. rotate_buffer = (uint8_t*)malloc(argb_size); /* NOLINT */
  71. if (!rotate_buffer) {
  72. return 1; // Out of memory runtime error.
  73. }
  74. dst_argb = rotate_buffer;
  75. dst_stride_argb = crop_width * 4;
  76. }
  77. switch (format) {
  78. // Single plane formats
  79. case FOURCC_YUY2:
  80. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  81. r = YUY2ToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb,
  82. crop_width, inv_crop_height);
  83. break;
  84. case FOURCC_UYVY:
  85. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  86. r = UYVYToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb,
  87. crop_width, inv_crop_height);
  88. break;
  89. case FOURCC_24BG:
  90. src = sample + (src_width * crop_y + crop_x) * 3;
  91. r = RGB24ToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width,
  92. inv_crop_height);
  93. break;
  94. case FOURCC_RAW:
  95. src = sample + (src_width * crop_y + crop_x) * 3;
  96. r = RAWToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width,
  97. inv_crop_height);
  98. break;
  99. case FOURCC_ARGB:
  100. if (!need_buf && !rotation) {
  101. src = sample + (src_width * crop_y + crop_x) * 4;
  102. r = ARGBToARGB(src, src_width * 4, dst_argb, dst_stride_argb,
  103. crop_width, inv_crop_height);
  104. }
  105. break;
  106. case FOURCC_BGRA:
  107. src = sample + (src_width * crop_y + crop_x) * 4;
  108. r = BGRAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  109. inv_crop_height);
  110. break;
  111. case FOURCC_ABGR:
  112. src = sample + (src_width * crop_y + crop_x) * 4;
  113. r = ABGRToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  114. inv_crop_height);
  115. break;
  116. case FOURCC_RGBA:
  117. src = sample + (src_width * crop_y + crop_x) * 4;
  118. r = RGBAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  119. inv_crop_height);
  120. break;
  121. case FOURCC_AR30:
  122. src = sample + (src_width * crop_y + crop_x) * 4;
  123. r = AR30ToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  124. inv_crop_height);
  125. break;
  126. case FOURCC_AB30:
  127. src = sample + (src_width * crop_y + crop_x) * 4;
  128. r = AB30ToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  129. inv_crop_height);
  130. break;
  131. case FOURCC_RGBP:
  132. src = sample + (src_width * crop_y + crop_x) * 2;
  133. r = RGB565ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  134. crop_width, inv_crop_height);
  135. break;
  136. case FOURCC_RGBO:
  137. src = sample + (src_width * crop_y + crop_x) * 2;
  138. r = ARGB1555ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  139. crop_width, inv_crop_height);
  140. break;
  141. case FOURCC_R444:
  142. src = sample + (src_width * crop_y + crop_x) * 2;
  143. r = ARGB4444ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  144. crop_width, inv_crop_height);
  145. break;
  146. case FOURCC_I400:
  147. src = sample + src_width * crop_y + crop_x;
  148. r = I400ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width,
  149. inv_crop_height);
  150. break;
  151. case FOURCC_J400:
  152. src = sample + src_width * crop_y + crop_x;
  153. r = J400ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width,
  154. inv_crop_height);
  155. break;
  156. // Biplanar formats
  157. case FOURCC_NV12:
  158. src = sample + (src_width * crop_y + crop_x);
  159. src_uv =
  160. sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
  161. r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
  162. dst_stride_argb, crop_width, inv_crop_height);
  163. break;
  164. case FOURCC_NV21:
  165. src = sample + (src_width * crop_y + crop_x);
  166. src_uv =
  167. sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
  168. // Call NV12 but with u and v parameters swapped.
  169. r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
  170. dst_stride_argb, crop_width, inv_crop_height);
  171. break;
  172. // Triplanar formats
  173. case FOURCC_I420:
  174. case FOURCC_YV12: {
  175. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  176. const uint8_t* src_u;
  177. const uint8_t* src_v;
  178. int halfwidth = (src_width + 1) / 2;
  179. int halfheight = (abs_src_height + 1) / 2;
  180. if (format == FOURCC_YV12) {
  181. src_v = sample + src_width * abs_src_height +
  182. (halfwidth * crop_y + crop_x) / 2;
  183. src_u = sample + src_width * abs_src_height +
  184. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  185. } else {
  186. src_u = sample + src_width * abs_src_height +
  187. (halfwidth * crop_y + crop_x) / 2;
  188. src_v = sample + src_width * abs_src_height +
  189. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  190. }
  191. r = I420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  192. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  193. break;
  194. }
  195. case FOURCC_J420: {
  196. int halfwidth = (src_width + 1) / 2;
  197. int halfheight = (abs_src_height + 1) / 2;
  198. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  199. const uint8_t* src_u = sample + src_width * abs_src_height +
  200. (halfwidth * crop_y + crop_x) / 2;
  201. const uint8_t* src_v = sample + src_width * abs_src_height +
  202. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  203. r = J420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  204. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  205. break;
  206. }
  207. case FOURCC_H420: {
  208. int halfwidth = (src_width + 1) / 2;
  209. int halfheight = (abs_src_height + 1) / 2;
  210. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  211. const uint8_t* src_u = sample + src_width * abs_src_height +
  212. (halfwidth * crop_y + crop_x) / 2;
  213. const uint8_t* src_v = sample + src_width * abs_src_height +
  214. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  215. r = H420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  216. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  217. break;
  218. }
  219. case FOURCC_U420: {
  220. int halfwidth = (src_width + 1) / 2;
  221. int halfheight = (abs_src_height + 1) / 2;
  222. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  223. const uint8_t* src_u = sample + src_width * abs_src_height +
  224. (halfwidth * crop_y + crop_x) / 2;
  225. const uint8_t* src_v = sample + src_width * abs_src_height +
  226. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  227. r = U420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  228. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  229. break;
  230. }
  231. case FOURCC_I422:
  232. case FOURCC_YV16: {
  233. int halfwidth = (src_width + 1) / 2;
  234. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  235. const uint8_t* src_u;
  236. const uint8_t* src_v;
  237. if (format == FOURCC_YV16) {
  238. src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
  239. crop_x / 2;
  240. src_u = sample + src_width * abs_src_height +
  241. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  242. } else {
  243. src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
  244. crop_x / 2;
  245. src_v = sample + src_width * abs_src_height +
  246. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  247. }
  248. r = I422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  249. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  250. break;
  251. }
  252. case FOURCC_J422: {
  253. int halfwidth = (src_width + 1) / 2;
  254. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  255. const uint8_t* src_u =
  256. sample + src_width * abs_src_height + halfwidth * crop_y + crop_x / 2;
  257. const uint8_t* src_v = sample + src_width * abs_src_height +
  258. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  259. r = J422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  260. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  261. break;
  262. }
  263. case FOURCC_H422: {
  264. int halfwidth = (src_width + 1) / 2;
  265. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  266. const uint8_t* src_u =
  267. sample + src_width * abs_src_height + halfwidth * crop_y + crop_x / 2;
  268. const uint8_t* src_v = sample + src_width * abs_src_height +
  269. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  270. r = H422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  271. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  272. break;
  273. }
  274. case FOURCC_U422: {
  275. int halfwidth = (src_width + 1) / 2;
  276. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  277. const uint8_t* src_u =
  278. sample + src_width * abs_src_height + halfwidth * crop_y + crop_x / 2;
  279. const uint8_t* src_v = sample + src_width * abs_src_height +
  280. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  281. r = H422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  282. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  283. break;
  284. }
  285. case FOURCC_I444:
  286. case FOURCC_YV24: {
  287. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  288. const uint8_t* src_u;
  289. const uint8_t* src_v;
  290. if (format == FOURCC_YV24) {
  291. src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
  292. src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  293. } else {
  294. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  295. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  296. }
  297. r = I444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
  298. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  299. break;
  300. }
  301. case FOURCC_J444: {
  302. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  303. const uint8_t* src_u;
  304. const uint8_t* src_v;
  305. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  306. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  307. r = J444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
  308. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  309. break;
  310. }
  311. case FOURCC_H444: {
  312. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  313. const uint8_t* src_u;
  314. const uint8_t* src_v;
  315. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  316. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  317. r = H444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
  318. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  319. break;
  320. }
  321. case FOURCC_U444: {
  322. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  323. const uint8_t* src_u;
  324. const uint8_t* src_v;
  325. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  326. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  327. r = U444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
  328. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  329. break;
  330. }
  331. #ifdef HAVE_JPEG
  332. case FOURCC_MJPG:
  333. r = MJPGToARGB(sample, sample_size, dst_argb, dst_stride_argb, src_width,
  334. abs_src_height, crop_width, inv_crop_height);
  335. break;
  336. #endif
  337. default:
  338. r = -1; // unknown fourcc - return failure code.
  339. }
  340. if (need_buf) {
  341. if (!r) {
  342. r = ARGBRotate(dst_argb, dst_stride_argb, dest_argb, dest_dst_stride_argb,
  343. crop_width, abs_crop_height, rotation);
  344. }
  345. free(rotate_buffer);
  346. } else if (rotation) {
  347. src = sample + (src_width * crop_y + crop_x) * 4;
  348. r = ARGBRotate(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  349. inv_crop_height, rotation);
  350. }
  351. return r;
  352. }
  353. #ifdef __cplusplus
  354. } // extern "C"
  355. } // namespace libyuv
  356. #endif