convert_to_i420.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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,
  26. int y_stride,
  27. uint8* u,
  28. int u_stride,
  29. uint8* v,
  30. int v_stride,
  31. int crop_x,
  32. int crop_y,
  33. int src_width,
  34. int src_height,
  35. int crop_width,
  36. int crop_height,
  37. enum RotationMode rotation,
  38. uint32 fourcc) {
  39. uint32 format = CanonicalFourCC(fourcc);
  40. int aligned_src_width = (src_width + 1) & ~1;
  41. const uint8* src;
  42. const uint8* src_uv;
  43. const int abs_src_height = (src_height < 0) ? -src_height : src_height;
  44. // TODO(nisse): Why allow crop_height < 0?
  45. const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
  46. int r = 0;
  47. LIBYUV_BOOL need_buf =
  48. (rotation && format != FOURCC_I420 && format != FOURCC_NV12 &&
  49. format != FOURCC_NV21 && format != FOURCC_YV12) ||
  50. y == sample;
  51. uint8* tmp_y = y;
  52. uint8* tmp_u = u;
  53. uint8* tmp_v = v;
  54. int tmp_y_stride = y_stride;
  55. int tmp_u_stride = u_stride;
  56. int tmp_v_stride = v_stride;
  57. uint8* rotate_buffer = NULL;
  58. const int inv_crop_height =
  59. (src_height < 0) ? -abs_crop_height : abs_crop_height;
  60. if (!y || !u || !v || !sample || src_width <= 0 || crop_width <= 0 ||
  61. src_height == 0 || crop_height == 0) {
  62. return -1;
  63. }
  64. // One pass rotation is available for some formats. For the rest, convert
  65. // to I420 (with optional vertical flipping) into a temporary I420 buffer,
  66. // and then rotate the I420 to the final destination buffer.
  67. // For in-place conversion, if destination y is same as source sample,
  68. // also enable temporary buffer.
  69. if (need_buf) {
  70. int y_size = crop_width * abs_crop_height;
  71. int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
  72. rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); /* NOLINT */
  73. if (!rotate_buffer) {
  74. return 1; // Out of memory runtime error.
  75. }
  76. y = rotate_buffer;
  77. u = y + y_size;
  78. v = u + uv_size;
  79. y_stride = crop_width;
  80. u_stride = v_stride = ((crop_width + 1) / 2);
  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 = YUY2ToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
  87. v_stride, crop_width, inv_crop_height);
  88. break;
  89. case FOURCC_UYVY:
  90. src = sample + (aligned_src_width * crop_y + crop_x) * 2;
  91. r = UYVYToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v,
  92. v_stride, 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, y, y_stride, u, u_stride, v,
  97. v_stride, crop_width, inv_crop_height);
  98. break;
  99. case FOURCC_RGBO:
  100. src = sample + (src_width * crop_y + crop_x) * 2;
  101. r = ARGB1555ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
  102. v_stride, crop_width, inv_crop_height);
  103. break;
  104. case FOURCC_R444:
  105. src = sample + (src_width * crop_y + crop_x) * 2;
  106. r = ARGB4444ToI420(src, src_width * 2, y, y_stride, u, u_stride, v,
  107. v_stride, crop_width, inv_crop_height);
  108. break;
  109. case FOURCC_24BG:
  110. src = sample + (src_width * crop_y + crop_x) * 3;
  111. r = RGB24ToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
  112. crop_width, inv_crop_height);
  113. break;
  114. case FOURCC_RAW:
  115. src = sample + (src_width * crop_y + crop_x) * 3;
  116. r = RAWToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride,
  117. crop_width, inv_crop_height);
  118. break;
  119. case FOURCC_ARGB:
  120. src = sample + (src_width * crop_y + crop_x) * 4;
  121. r = ARGBToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
  122. crop_width, inv_crop_height);
  123. break;
  124. case FOURCC_BGRA:
  125. src = sample + (src_width * crop_y + crop_x) * 4;
  126. r = BGRAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
  127. crop_width, inv_crop_height);
  128. break;
  129. case FOURCC_ABGR:
  130. src = sample + (src_width * crop_y + crop_x) * 4;
  131. r = ABGRToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
  132. crop_width, inv_crop_height);
  133. break;
  134. case FOURCC_RGBA:
  135. src = sample + (src_width * crop_y + crop_x) * 4;
  136. r = RGBAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride,
  137. crop_width, inv_crop_height);
  138. break;
  139. case FOURCC_I400:
  140. src = sample + src_width * crop_y + crop_x;
  141. r = I400ToI420(src, src_width, y, y_stride, u, u_stride, v, v_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 + (src_width * src_height) +
  148. ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
  149. r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
  150. y_stride, u, u_stride, v, v_stride, crop_width,
  151. inv_crop_height, rotation);
  152. break;
  153. case FOURCC_NV21:
  154. src = sample + (src_width * crop_y + crop_x);
  155. src_uv = sample + (src_width * src_height) +
  156. ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2);
  157. // Call NV12 but with u and v parameters swapped.
  158. r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y,
  159. y_stride, v, v_stride, u, u_stride, crop_width,
  160. inv_crop_height, rotation);
  161. break;
  162. case FOURCC_M420:
  163. src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
  164. r = M420ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride,
  165. crop_width, inv_crop_height);
  166. break;
  167. // Triplanar formats
  168. case FOURCC_I420:
  169. case FOURCC_YV12: {
  170. const uint8* src_y = sample + (src_width * crop_y + crop_x);
  171. const uint8* src_u;
  172. const uint8* src_v;
  173. int halfwidth = (src_width + 1) / 2;
  174. int halfheight = (abs_src_height + 1) / 2;
  175. if (format == FOURCC_YV12) {
  176. src_v = sample + src_width * abs_src_height +
  177. (halfwidth * crop_y + crop_x) / 2;
  178. src_u = sample + src_width * abs_src_height +
  179. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  180. } else {
  181. src_u = sample + src_width * abs_src_height +
  182. (halfwidth * crop_y + crop_x) / 2;
  183. src_v = sample + src_width * abs_src_height +
  184. halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
  185. }
  186. r = I420Rotate(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
  187. y_stride, u, u_stride, v, v_stride, crop_width,
  188. inv_crop_height, rotation);
  189. break;
  190. }
  191. case FOURCC_I422:
  192. case FOURCC_YV16: {
  193. const uint8* src_y = sample + src_width * crop_y + crop_x;
  194. const uint8* src_u;
  195. const uint8* src_v;
  196. int halfwidth = (src_width + 1) / 2;
  197. if (format == FOURCC_YV16) {
  198. src_v = sample + src_width * abs_src_height + halfwidth * crop_y +
  199. crop_x / 2;
  200. src_u = sample + src_width * abs_src_height +
  201. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  202. } else {
  203. src_u = sample + src_width * abs_src_height + halfwidth * crop_y +
  204. crop_x / 2;
  205. src_v = sample + src_width * abs_src_height +
  206. halfwidth * (abs_src_height + crop_y) + crop_x / 2;
  207. }
  208. r = I422ToI420(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y,
  209. y_stride, u, u_stride, v, v_stride, crop_width,
  210. inv_crop_height);
  211. break;
  212. }
  213. case FOURCC_I444:
  214. case FOURCC_YV24: {
  215. const uint8* src_y = sample + src_width * crop_y + crop_x;
  216. const uint8* src_u;
  217. const uint8* src_v;
  218. if (format == FOURCC_YV24) {
  219. src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
  220. src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  221. } else {
  222. src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
  223. src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
  224. }
  225. r = I444ToI420(src_y, src_width, src_u, src_width, src_v, src_width, y,
  226. y_stride, u, u_stride, v, v_stride, crop_width,
  227. inv_crop_height);
  228. break;
  229. }
  230. #ifdef HAVE_JPEG
  231. case FOURCC_MJPG:
  232. r = MJPGToI420(sample, sample_size, y, y_stride, u, u_stride, v, v_stride,
  233. src_width, abs_src_height, crop_width, inv_crop_height);
  234. break;
  235. #endif
  236. default:
  237. r = -1; // unknown fourcc - return failure code.
  238. }
  239. if (need_buf) {
  240. if (!r) {
  241. r = I420Rotate(y, y_stride, u, u_stride, v, v_stride, tmp_y, tmp_y_stride,
  242. tmp_u, tmp_u_stride, tmp_v, tmp_v_stride, crop_width,
  243. abs_crop_height, rotation);
  244. }
  245. free(rotate_buffer);
  246. }
  247. return r;
  248. }
  249. #ifdef __cplusplus
  250. } // extern "C"
  251. } // namespace libyuv
  252. #endif