convert_to_i420.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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 <stdlib.h>
  11. #include "libyuv/convert.h"
  12. #include "libyuv/video_common.h"
  13. #ifdef __cplusplus
  14. namespace libyuv {
  15. extern "C" {
  16. #endif
  17. // Convert camera sample to I420 with cropping, rotation and vertical flip.
  18. // src_width is used for source stride computation
  19. // src_height is used to compute location of planes, and indicate inversion
  20. // sample_size is measured in bytes and is the size of the frame.
  21. // With MJPEG it is the compressed size of the frame.
  22. LIBYUV_API
  23. int ConvertToI420(const uint8* sample,
  24. size_t sample_size,
  25. uint8* y, int y_stride,
  26. uint8* u, int u_stride,
  27. uint8* v, int v_stride,
  28. int crop_x, int crop_y,
  29. int src_width, int src_height,
  30. int crop_width, int crop_height,
  31. enum RotationMode rotation,
  32. uint32 fourcc) {
  33. uint32 format = CanonicalFourCC(fourcc);
  34. int aligned_src_width = (src_width + 1) & ~1;
  35. const uint8* src;
  36. const uint8* src_uv;
  37. const int abs_src_height = (src_height < 0) ? -src_height : src_height;
  38. // TODO(nisse): Why allow crop_height < 0?
  39. const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  40. int r = 0;
  41. LIBYUV_BOOL need_buf = (rotation && format != FOURCC_I420 &&
  42. format != FOURCC_NV12 && format != FOURCC_NV21 &&
  43. format != FOURCC_YV12) || y == sample;
  44. uint8* tmp_y = y;
  45. uint8* tmp_u = u;
  46. uint8* tmp_v = v;
  47. int tmp_y_stride = y_stride;
  48. int tmp_u_stride = u_stride;
  49. int tmp_v_stride = v_stride;
  50. uint8* rotate_buffer = NULL;
  51. const int inv_crop_height =
  52. (src_height < 0) ? -abs_crop_height : abs_crop_height;
  53. if (!y || !u || !v || !sample ||
  54. src_width <= 0 || crop_width <= 0 ||
  55. src_height == 0 || crop_height == 0) {
  56. return -1;
  57. }
  58. // One pass rotation is available for some formats. For the rest, convert
  59. // to I420 (with optional vertical flipping) into a temporary I420 buffer,
  60. // and then rotate the I420 to the final destination buffer.
  61. // For in-place conversion, if destination y is same as source sample,
  62. // also enable temporary buffer.
  63. if (need_buf) {
  64. int y_size = crop_width * abs_crop_height;
  65. int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
  66. rotate_buffer = (uint8*)malloc(y_size + uv_size * 2);
  67. if (!rotate_buffer) {
  68. return 1; // Out of memory runtime error.
  69. }
  70. y = rotate_buffer;
  71. u = y + y_size;
  72. v = u + uv_size;
  73. y_stride = crop_width;
  74. u_stride = v_stride = ((crop_width + 1) / 2);
  75. }
  76. switch (format) {
  77. // Single plane formats
  78. case FOURCC_YUY2:
  79. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  80. r = YUY2ToI420(src, aligned_src_width * 2,
  81. y, y_stride,
  82. u, u_stride,
  83. v, v_stride,
  84. crop_width, inv_crop_height);
  85. break;
  86. case FOURCC_UYVY:
  87. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  88. r = UYVYToI420(src, aligned_src_width * 2,
  89. y, y_stride,
  90. u, u_stride,
  91. v, v_stride,
  92. crop_width, inv_crop_height);
  93. break;
  94. case FOURCC_RGBP:
  95. src = sample + (src_width * crop_y + crop_x) * 2;
  96. r = RGB565ToI420(src, src_width * 2,
  97. y, y_stride,
  98. u, u_stride,
  99. v, v_stride,
  100. crop_width, inv_crop_height);
  101. break;
  102. case FOURCC_RGBO:
  103. src = sample + (src_width * crop_y + crop_x) * 2;
  104. r = ARGB1555ToI420(src, src_width * 2,
  105. y, y_stride,
  106. u, u_stride,
  107. v, v_stride,
  108. crop_width, inv_crop_height);
  109. break;
  110. case FOURCC_R444:
  111. src = sample + (src_width * crop_y + crop_x) * 2;
  112. r = ARGB4444ToI420(src, src_width * 2,
  113. y, y_stride,
  114. u, u_stride,
  115. v, v_stride,
  116. crop_width, inv_crop_height);
  117. break;
  118. case FOURCC_24BG:
  119. src = sample + (src_width * crop_y + crop_x) * 3;
  120. r = RGB24ToI420(src, src_width * 3,
  121. y, y_stride,
  122. u, u_stride,
  123. v, v_stride,
  124. crop_width, inv_crop_height);
  125. break;
  126. case FOURCC_RAW:
  127. src = sample + (src_width * crop_y + crop_x) * 3;
  128. r = RAWToI420(src, src_width * 3,
  129. y, y_stride,
  130. u, u_stride,
  131. v, v_stride,
  132. crop_width, inv_crop_height);
  133. break;
  134. case FOURCC_ARGB:
  135. src = sample + (src_width * crop_y + crop_x) * 4;
  136. r = ARGBToI420(src, src_width * 4,
  137. y, y_stride,
  138. u, u_stride,
  139. v, v_stride,
  140. crop_width, inv_crop_height);
  141. break;
  142. case FOURCC_BGRA:
  143. src = sample + (src_width * crop_y + crop_x) * 4;
  144. r = BGRAToI420(src, src_width * 4,
  145. y, y_stride,
  146. u, u_stride,
  147. v, v_stride,
  148. crop_width, inv_crop_height);
  149. break;
  150. case FOURCC_ABGR:
  151. src = sample + (src_width * crop_y + crop_x) * 4;
  152. r = ABGRToI420(src, src_width * 4,
  153. y, y_stride,
  154. u, u_stride,
  155. v, v_stride,
  156. crop_width, inv_crop_height);
  157. break;
  158. case FOURCC_RGBA:
  159. src = sample + (src_width * crop_y + crop_x) * 4;
  160. r = RGBAToI420(src, src_width * 4,
  161. y, y_stride,
  162. u, u_stride,
  163. v, v_stride,
  164. crop_width, inv_crop_height);
  165. break;
  166. case FOURCC_I400:
  167. src = sample + src_width * crop_y + crop_x;
  168. r = I400ToI420(src, src_width,
  169. y, y_stride,
  170. u, u_stride,
  171. v, v_stride,
  172. crop_width, inv_crop_height);
  173. break;
  174. // Biplanar formats
  175. case FOURCC_NV12:
  176. src = sample + (src_width * crop_y + crop_x);
  177. src_uv = sample + (src_width * src_height) +
  178. ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
  179. r = NV12ToI420Rotate(src, src_width,
  180. src_uv, aligned_src_width,
  181. y, y_stride,
  182. u, u_stride,
  183. v, v_stride,
  184. crop_width, inv_crop_height, rotation);
  185. break;
  186. case FOURCC_NV21:
  187. src = sample + (src_width * crop_y + crop_x);
  188. src_uv = sample + (src_width * src_height) +
  189. ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
  190. // Call NV12 but with u and v parameters swapped.
  191. r = NV12ToI420Rotate(src, src_width,
  192. src_uv, aligned_src_width,
  193. y, y_stride,
  194. v, v_stride,
  195. u, u_stride,
  196. crop_width, inv_crop_height, rotation);
  197. break;
  198. case FOURCC_M420:
  199. src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
  200. r = M420ToI420(src, src_width,
  201. y, y_stride,
  202. u, u_stride,
  203. v, v_stride,
  204. crop_width, inv_crop_height);
  205. break;
  206. // Triplanar formats
  207. case FOURCC_I420:
  208. case FOURCC_YV12: {
  209. const uint8* src_y = sample + (src_width * crop_y + crop_x);
  210. const uint8* src_u;
  211. const uint8* src_v;
  212. int halfwidth = (src_width + 1) / 2;
  213. int halfheight = (abs_src_height + 1) / 2;
  214. if (format == FOURCC_YV12) {
  215. src_v = sample + src_width * abs_src_height +
  216. (halfwidth * crop_y + crop_x) / 2;
  217. src_u = sample + src_width * abs_src_height +
  218. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  219. } else {
  220. src_u = sample + src_width * abs_src_height +
  221. (halfwidth * crop_y + crop_x) / 2;
  222. src_v = sample + src_width * abs_src_height +
  223. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  224. }
  225. r = I420Rotate(src_y, src_width,
  226. src_u, halfwidth,
  227. src_v, halfwidth,
  228. y, y_stride,
  229. u, u_stride,
  230. v, v_stride,
  231. crop_width, inv_crop_height, rotation);
  232. break;
  233. }
  234. case FOURCC_I422:
  235. case FOURCC_YV16: {
  236. const uint8* src_y = sample + src_width * crop_y + crop_x;
  237. const uint8* src_u;
  238. const uint8* src_v;
  239. int halfwidth = (src_width + 1) / 2;
  240. if (format == FOURCC_YV16) {
  241. src_v = sample + src_width * abs_src_height +
  242. halfwidth * crop_y + crop_x / 2;
  243. src_u = sample + src_width * abs_src_height +
  244. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  245. } else {
  246. src_u = sample + src_width * abs_src_height +
  247. halfwidth * crop_y + crop_x / 2;
  248. src_v = sample + src_width * abs_src_height +
  249. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  250. }
  251. r = I422ToI420(src_y, src_width,
  252. src_u, halfwidth,
  253. src_v, halfwidth,
  254. y, y_stride,
  255. u, u_stride,
  256. v, v_stride,
  257. crop_width, inv_crop_height);
  258. break;
  259. }
  260. case FOURCC_I444:
  261. case FOURCC_YV24: {
  262. const uint8* src_y = sample + src_width * crop_y + crop_x;
  263. const uint8* src_u;
  264. const uint8* src_v;
  265. if (format == FOURCC_YV24) {
  266. src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
  267. src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  268. } else {
  269. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  270. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  271. }
  272. r = I444ToI420(src_y, src_width,
  273. src_u, src_width,
  274. src_v, src_width,
  275. y, y_stride,
  276. u, u_stride,
  277. v, v_stride,
  278. crop_width, inv_crop_height);
  279. break;
  280. }
  281. case FOURCC_I411: {
  282. int quarterwidth = (src_width + 3) / 4;
  283. const uint8* src_y = sample + src_width * crop_y + crop_x;
  284. const uint8* src_u = sample + src_width * abs_src_height +
  285. quarterwidth * crop_y + crop_x / 4;
  286. const uint8* src_v = sample + src_width * abs_src_height +
  287. quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
  288. r = I411ToI420(src_y, src_width,
  289. src_u, quarterwidth,
  290. src_v, quarterwidth,
  291. y, y_stride,
  292. u, u_stride,
  293. v, v_stride,
  294. crop_width, inv_crop_height);
  295. break;
  296. }
  297. #ifdef HAVE_JPEG
  298. case FOURCC_MJPG:
  299. r = MJPGToI420(sample, sample_size,
  300. y, y_stride,
  301. u, u_stride,
  302. v, v_stride,
  303. src_width, abs_src_height, crop_width, inv_crop_height);
  304. break;
  305. #endif
  306. default:
  307. r = -1; // unknown fourcc - return failure code.
  308. }
  309. if (need_buf) {
  310. if (!r) {
  311. r = I420Rotate(y, y_stride,
  312. u, u_stride,
  313. v, v_stride,
  314. tmp_y, tmp_y_stride,
  315. tmp_u, tmp_u_stride,
  316. tmp_v, tmp_v_stride,
  317. crop_width, abs_crop_height, rotation);
  318. }
  319. free(rotate_buffer);
  320. }
  321. return r;
  322. }
  323. #ifdef __cplusplus
  324. } // extern "C"
  325. } // namespace libyuv
  326. #endif