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