convert_to_argb.cc 11 KB

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