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