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