convert_to_argb.cc 10 KB

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