convert_to_argb.cc 11 KB

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