convert_to_argb.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. // J400ToARGB
  31. // J422ToARGB
  32. // J444ToARGB
  33. LIBYUV_API
  34. int ConvertToARGB(const uint8_t* sample,
  35. size_t sample_size,
  36. uint8_t* dst_argb,
  37. int dst_stride_argb,
  38. int crop_x,
  39. int crop_y,
  40. int src_width,
  41. int src_height,
  42. int crop_width,
  43. int crop_height,
  44. enum RotationMode rotation,
  45. uint32_t fourcc) {
  46. uint32_t format = CanonicalFourCC(fourcc);
  47. int aligned_src_width = (src_width + 1) & ~1;
  48. const uint8_t* src;
  49. const uint8_t* src_uv;
  50. int abs_src_height = (src_height < 0) ? -src_height : src_height;
  51. int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  52. int r = 0;
  53. // One pass rotation is available for some formats. For the rest, convert
  54. // to ARGB (with optional vertical flipping) into a temporary ARGB buffer,
  55. // and then rotate the ARGB to the final destination buffer.
  56. // For in-place conversion, if destination dst_argb is same as source sample,
  57. // also enable temporary buffer.
  58. LIBYUV_BOOL need_buf =
  59. (rotation && format != FOURCC_ARGB) || dst_argb == sample;
  60. uint8_t* dest_argb = dst_argb;
  61. int dest_dst_stride_argb = dst_stride_argb;
  62. uint8_t* rotate_buffer = NULL;
  63. int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  64. if (dst_argb == NULL || sample == NULL || src_width <= 0 || crop_width <= 0 ||
  65. src_height == 0 || crop_height == 0) {
  66. return -1;
  67. }
  68. if (src_height < 0) {
  69. inv_crop_height = -inv_crop_height;
  70. }
  71. if (need_buf) {
  72. int argb_size = crop_width * 4 * abs_crop_height;
  73. rotate_buffer = (uint8_t*)malloc(argb_size); /* NOLINT */
  74. if (!rotate_buffer) {
  75. return 1; // Out of memory runtime error.
  76. }
  77. dst_argb = rotate_buffer;
  78. dst_stride_argb = crop_width * 4;
  79. }
  80. switch (format) {
  81. // Single plane formats
  82. case FOURCC_YUY2:
  83. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  84. r = YUY2ToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb,
  85. crop_width, inv_crop_height);
  86. break;
  87. case FOURCC_UYVY:
  88. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  89. r = UYVYToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb,
  90. crop_width, inv_crop_height);
  91. break;
  92. case FOURCC_24BG:
  93. src = sample + (src_width * crop_y + crop_x) * 3;
  94. r = RGB24ToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width,
  95. inv_crop_height);
  96. break;
  97. case FOURCC_RAW:
  98. src = sample + (src_width * crop_y + crop_x) * 3;
  99. r = RAWToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width,
  100. inv_crop_height);
  101. break;
  102. case FOURCC_ARGB:
  103. if (!need_buf && !rotation) {
  104. src = sample + (src_width * crop_y + crop_x) * 4;
  105. r = ARGBToARGB(src, src_width * 4, dst_argb, dst_stride_argb,
  106. crop_width, inv_crop_height);
  107. }
  108. break;
  109. case FOURCC_BGRA:
  110. src = sample + (src_width * crop_y + crop_x) * 4;
  111. r = BGRAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  112. inv_crop_height);
  113. break;
  114. case FOURCC_ABGR:
  115. src = sample + (src_width * crop_y + crop_x) * 4;
  116. r = ABGRToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  117. inv_crop_height);
  118. break;
  119. case FOURCC_RGBA:
  120. src = sample + (src_width * crop_y + crop_x) * 4;
  121. r = RGBAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  122. inv_crop_height);
  123. break;
  124. case FOURCC_AR30:
  125. src = sample + (src_width * crop_y + crop_x) * 4;
  126. r = AR30ToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  127. inv_crop_height);
  128. break;
  129. case FOURCC_AB30:
  130. src = sample + (src_width * crop_y + crop_x) * 4;
  131. r = AB30ToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  132. inv_crop_height);
  133. break;
  134. case FOURCC_RGBP:
  135. src = sample + (src_width * crop_y + crop_x) * 2;
  136. r = RGB565ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  137. crop_width, inv_crop_height);
  138. break;
  139. case FOURCC_RGBO:
  140. src = sample + (src_width * crop_y + crop_x) * 2;
  141. r = ARGB1555ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  142. crop_width, inv_crop_height);
  143. break;
  144. case FOURCC_R444:
  145. src = sample + (src_width * crop_y + crop_x) * 2;
  146. r = ARGB4444ToARGB(src, src_width * 2, dst_argb, dst_stride_argb,
  147. crop_width, inv_crop_height);
  148. break;
  149. case FOURCC_I400:
  150. src = sample + src_width * crop_y + crop_x;
  151. r = I400ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width,
  152. inv_crop_height);
  153. break;
  154. // Biplanar formats
  155. case FOURCC_NV12:
  156. src = sample + (src_width * crop_y + crop_x);
  157. src_uv =
  158. sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
  159. r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
  160. dst_stride_argb, crop_width, inv_crop_height);
  161. break;
  162. case FOURCC_NV21:
  163. src = sample + (src_width * crop_y + crop_x);
  164. src_uv =
  165. sample + aligned_src_width * (abs_src_height + crop_y / 2) + crop_x;
  166. // Call NV12 but with u and v parameters swapped.
  167. r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb,
  168. dst_stride_argb, crop_width, inv_crop_height);
  169. break;
  170. case FOURCC_M420:
  171. src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
  172. r = M420ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width,
  173. inv_crop_height);
  174. break;
  175. // Triplanar formats
  176. case FOURCC_I420:
  177. case FOURCC_YV12: {
  178. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  179. const uint8_t* src_u;
  180. const uint8_t* src_v;
  181. int halfwidth = (src_width + 1) / 2;
  182. int halfheight = (abs_src_height + 1) / 2;
  183. if (format == FOURCC_YV12) {
  184. src_v = sample + src_width * abs_src_height +
  185. (halfwidth * crop_y + crop_x) / 2;
  186. src_u = sample + src_width * abs_src_height +
  187. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  188. } else {
  189. src_u = sample + src_width * abs_src_height +
  190. (halfwidth * crop_y + crop_x) / 2;
  191. src_v = sample + src_width * abs_src_height +
  192. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  193. }
  194. r = I420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  195. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  196. break;
  197. }
  198. case FOURCC_H420: {
  199. int halfwidth = (src_width + 1) / 2;
  200. int halfheight = (abs_src_height + 1) / 2;
  201. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  202. const uint8_t* src_u = sample + src_width * abs_src_height +
  203. (halfwidth * crop_y + crop_x) / 2;
  204. const uint8_t* src_v = sample + src_width * abs_src_height +
  205. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  206. r = H420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  207. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  208. break;
  209. }
  210. case FOURCC_J420: {
  211. int halfwidth = (src_width + 1) / 2;
  212. int halfheight = (abs_src_height + 1) / 2;
  213. const uint8_t* src_y = sample + (src_width * crop_y + crop_x);
  214. const uint8_t* src_u = sample + src_width * abs_src_height +
  215. (halfwidth * crop_y + crop_x) / 2;
  216. const uint8_t* src_v = sample + src_width * abs_src_height +
  217. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  218. r = J420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  219. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  220. break;
  221. }
  222. case FOURCC_I422:
  223. case FOURCC_YV16: {
  224. int halfwidth = (src_width + 1) / 2;
  225. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  226. const uint8_t* src_u;
  227. const uint8_t* src_v;
  228. if (format == FOURCC_YV16) {
  229. src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
  230. crop_x / 2;
  231. src_u = sample + src_width * abs_src_height +
  232. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  233. } else {
  234. src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
  235. crop_x / 2;
  236. src_v = sample + src_width * abs_src_height +
  237. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  238. }
  239. r = I422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  240. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  241. break;
  242. }
  243. case FOURCC_H422: {
  244. int halfwidth = (src_width + 1) / 2;
  245. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  246. const uint8_t* src_u =
  247. sample + src_width * abs_src_height + halfwidth * crop_y + crop_x / 2;
  248. const uint8_t* src_v = sample + src_width * abs_src_height +
  249. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  250. r = H422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth,
  251. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  252. break;
  253. }
  254. case FOURCC_I444:
  255. case FOURCC_YV24: {
  256. const uint8_t* src_y = sample + src_width * crop_y + crop_x;
  257. const uint8_t* src_u;
  258. const uint8_t* src_v;
  259. if (format == FOURCC_YV24) {
  260. src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
  261. src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  262. } else {
  263. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  264. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  265. }
  266. r = I444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width,
  267. dst_argb, dst_stride_argb, crop_width, inv_crop_height);
  268. break;
  269. }
  270. #ifdef HAVE_JPEG
  271. case FOURCC_MJPG:
  272. r = MJPGToARGB(sample, sample_size, dst_argb, dst_stride_argb, src_width,
  273. abs_src_height, crop_width, inv_crop_height);
  274. break;
  275. #endif
  276. default:
  277. r = -1; // unknown fourcc - return failure code.
  278. }
  279. if (need_buf) {
  280. if (!r) {
  281. r = ARGBRotate(dst_argb, dst_stride_argb, dest_argb, dest_dst_stride_argb,
  282. crop_width, abs_crop_height, rotation);
  283. }
  284. free(rotate_buffer);
  285. } else if (rotation) {
  286. src = sample + (src_width * crop_y + crop_x) * 4;
  287. r = ARGBRotate(src, src_width * 4, dst_argb, dst_stride_argb, crop_width,
  288. inv_crop_height, rotation);
  289. }
  290. return r;
  291. }
  292. #ifdef __cplusplus
  293. } // extern "C"
  294. } // namespace libyuv
  295. #endif