1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libyuv/source/convert_to_i420.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,383 @@ 1.4 +/* 1.5 + * Copyright 2011 The LibYuv Project Authors. All rights reserved. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license 1.8 + * that can be found in the LICENSE file in the root of the source 1.9 + * tree. An additional intellectual property rights grant can be found 1.10 + * in the file PATENTS. All contributing project authors may 1.11 + * be found in the AUTHORS file in the root of the source tree. 1.12 + */ 1.13 + 1.14 +#include <stdlib.h> 1.15 + 1.16 +#include "libyuv/convert.h" 1.17 + 1.18 +#include "libyuv/format_conversion.h" 1.19 +#include "libyuv/video_common.h" 1.20 + 1.21 +#ifdef __cplusplus 1.22 +namespace libyuv { 1.23 +extern "C" { 1.24 +#endif 1.25 + 1.26 +// Convert camera sample to I420 with cropping, rotation and vertical flip. 1.27 +// src_width is used for source stride computation 1.28 +// src_height is used to compute location of planes, and indicate inversion 1.29 +// sample_size is measured in bytes and is the size of the frame. 1.30 +// With MJPEG it is the compressed size of the frame. 1.31 +LIBYUV_API 1.32 +int ConvertToI420(const uint8* sample, 1.33 + size_t sample_size, 1.34 + uint8* y, int y_stride, 1.35 + uint8* u, int u_stride, 1.36 + uint8* v, int v_stride, 1.37 + int crop_x, int crop_y, 1.38 + int src_width, int src_height, 1.39 + int crop_width, int crop_height, 1.40 + enum RotationMode rotation, 1.41 + uint32 fourcc) { 1.42 + uint32 format = CanonicalFourCC(fourcc); 1.43 + int aligned_src_width = (src_width + 1) & ~1; 1.44 + const uint8* src; 1.45 + const uint8* src_uv; 1.46 + int abs_src_height = (src_height < 0) ? -src_height : src_height; 1.47 + int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height; 1.48 + int r = 0; 1.49 + LIBYUV_BOOL need_buf = (rotation && format != FOURCC_I420 && 1.50 + format != FOURCC_NV12 && format != FOURCC_NV21 && 1.51 + format != FOURCC_YU12 && format != FOURCC_YV12) || y == sample; 1.52 + uint8* tmp_y = y; 1.53 + uint8* tmp_u = u; 1.54 + uint8* tmp_v = v; 1.55 + int tmp_y_stride = y_stride; 1.56 + int tmp_u_stride = u_stride; 1.57 + int tmp_v_stride = v_stride; 1.58 + uint8* rotate_buffer = NULL; 1.59 + int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height; 1.60 + 1.61 + if (!y || !u || !v || !sample || 1.62 + src_width <= 0 || crop_width <= 0 || 1.63 + src_height == 0 || crop_height == 0) { 1.64 + return -1; 1.65 + } 1.66 + if (src_height < 0) { 1.67 + inv_crop_height = -inv_crop_height; 1.68 + } 1.69 + 1.70 + // One pass rotation is available for some formats. For the rest, convert 1.71 + // to I420 (with optional vertical flipping) into a temporary I420 buffer, 1.72 + // and then rotate the I420 to the final destination buffer. 1.73 + // For in-place conversion, if destination y is same as source sample, 1.74 + // also enable temporary buffer. 1.75 + if (need_buf) { 1.76 + int y_size = crop_width * abs_crop_height; 1.77 + int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2); 1.78 + rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); 1.79 + if (!rotate_buffer) { 1.80 + return 1; // Out of memory runtime error. 1.81 + } 1.82 + y = rotate_buffer; 1.83 + u = y + y_size; 1.84 + v = u + uv_size; 1.85 + y_stride = crop_width; 1.86 + u_stride = v_stride = ((crop_width + 1) / 2); 1.87 + } 1.88 + 1.89 + switch (format) { 1.90 + // Single plane formats 1.91 + case FOURCC_YUY2: 1.92 + src = sample + (aligned_src_width * crop_y + crop_x) * 2; 1.93 + r = YUY2ToI420(src, aligned_src_width * 2, 1.94 + y, y_stride, 1.95 + u, u_stride, 1.96 + v, v_stride, 1.97 + crop_width, inv_crop_height); 1.98 + break; 1.99 + case FOURCC_UYVY: 1.100 + src = sample + (aligned_src_width * crop_y + crop_x) * 2; 1.101 + r = UYVYToI420(src, aligned_src_width * 2, 1.102 + y, y_stride, 1.103 + u, u_stride, 1.104 + v, v_stride, 1.105 + crop_width, inv_crop_height); 1.106 + break; 1.107 + case FOURCC_RGBP: 1.108 + src = sample + (src_width * crop_y + crop_x) * 2; 1.109 + r = RGB565ToI420(src, src_width * 2, 1.110 + y, y_stride, 1.111 + u, u_stride, 1.112 + v, v_stride, 1.113 + crop_width, inv_crop_height); 1.114 + break; 1.115 + case FOURCC_RGBO: 1.116 + src = sample + (src_width * crop_y + crop_x) * 2; 1.117 + r = ARGB1555ToI420(src, src_width * 2, 1.118 + y, y_stride, 1.119 + u, u_stride, 1.120 + v, v_stride, 1.121 + crop_width, inv_crop_height); 1.122 + break; 1.123 + case FOURCC_R444: 1.124 + src = sample + (src_width * crop_y + crop_x) * 2; 1.125 + r = ARGB4444ToI420(src, src_width * 2, 1.126 + y, y_stride, 1.127 + u, u_stride, 1.128 + v, v_stride, 1.129 + crop_width, inv_crop_height); 1.130 + break; 1.131 + case FOURCC_24BG: 1.132 + src = sample + (src_width * crop_y + crop_x) * 3; 1.133 + r = RGB24ToI420(src, src_width * 3, 1.134 + y, y_stride, 1.135 + u, u_stride, 1.136 + v, v_stride, 1.137 + crop_width, inv_crop_height); 1.138 + break; 1.139 + case FOURCC_RAW: 1.140 + src = sample + (src_width * crop_y + crop_x) * 3; 1.141 + r = RAWToI420(src, src_width * 3, 1.142 + y, y_stride, 1.143 + u, u_stride, 1.144 + v, v_stride, 1.145 + crop_width, inv_crop_height); 1.146 + break; 1.147 + case FOURCC_ARGB: 1.148 + src = sample + (src_width * crop_y + crop_x) * 4; 1.149 + r = ARGBToI420(src, src_width * 4, 1.150 + y, y_stride, 1.151 + u, u_stride, 1.152 + v, v_stride, 1.153 + crop_width, inv_crop_height); 1.154 + break; 1.155 + case FOURCC_BGRA: 1.156 + src = sample + (src_width * crop_y + crop_x) * 4; 1.157 + r = BGRAToI420(src, src_width * 4, 1.158 + y, y_stride, 1.159 + u, u_stride, 1.160 + v, v_stride, 1.161 + crop_width, inv_crop_height); 1.162 + break; 1.163 + case FOURCC_ABGR: 1.164 + src = sample + (src_width * crop_y + crop_x) * 4; 1.165 + r = ABGRToI420(src, src_width * 4, 1.166 + y, y_stride, 1.167 + u, u_stride, 1.168 + v, v_stride, 1.169 + crop_width, inv_crop_height); 1.170 + break; 1.171 + case FOURCC_RGBA: 1.172 + src = sample + (src_width * crop_y + crop_x) * 4; 1.173 + r = RGBAToI420(src, src_width * 4, 1.174 + y, y_stride, 1.175 + u, u_stride, 1.176 + v, v_stride, 1.177 + crop_width, inv_crop_height); 1.178 + break; 1.179 + // TODO(fbarchard): Support cropping Bayer by odd numbers 1.180 + // by adjusting fourcc. 1.181 + case FOURCC_BGGR: 1.182 + src = sample + (src_width * crop_y + crop_x); 1.183 + r = BayerBGGRToI420(src, src_width, 1.184 + y, y_stride, 1.185 + u, u_stride, 1.186 + v, v_stride, 1.187 + crop_width, inv_crop_height); 1.188 + break; 1.189 + case FOURCC_GBRG: 1.190 + src = sample + (src_width * crop_y + crop_x); 1.191 + r = BayerGBRGToI420(src, src_width, 1.192 + y, y_stride, 1.193 + u, u_stride, 1.194 + v, v_stride, 1.195 + crop_width, inv_crop_height); 1.196 + break; 1.197 + case FOURCC_GRBG: 1.198 + src = sample + (src_width * crop_y + crop_x); 1.199 + r = BayerGRBGToI420(src, src_width, 1.200 + y, y_stride, 1.201 + u, u_stride, 1.202 + v, v_stride, 1.203 + crop_width, inv_crop_height); 1.204 + break; 1.205 + case FOURCC_RGGB: 1.206 + src = sample + (src_width * crop_y + crop_x); 1.207 + r = BayerRGGBToI420(src, src_width, 1.208 + y, y_stride, 1.209 + u, u_stride, 1.210 + v, v_stride, 1.211 + crop_width, inv_crop_height); 1.212 + break; 1.213 + case FOURCC_I400: 1.214 + src = sample + src_width * crop_y + crop_x; 1.215 + r = I400ToI420(src, src_width, 1.216 + y, y_stride, 1.217 + u, u_stride, 1.218 + v, v_stride, 1.219 + crop_width, inv_crop_height); 1.220 + break; 1.221 + // Biplanar formats 1.222 + case FOURCC_NV12: 1.223 + src = sample + (src_width * crop_y + crop_x); 1.224 + src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 1.225 + r = NV12ToI420Rotate(src, src_width, 1.226 + src_uv, aligned_src_width, 1.227 + y, y_stride, 1.228 + u, u_stride, 1.229 + v, v_stride, 1.230 + crop_width, inv_crop_height, rotation); 1.231 + break; 1.232 + case FOURCC_NV21: 1.233 + src = sample + (src_width * crop_y + crop_x); 1.234 + src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 1.235 + // Call NV12 but with u and v parameters swapped. 1.236 + r = NV12ToI420Rotate(src, src_width, 1.237 + src_uv, aligned_src_width, 1.238 + y, y_stride, 1.239 + v, v_stride, 1.240 + u, u_stride, 1.241 + crop_width, inv_crop_height, rotation); 1.242 + break; 1.243 + case FOURCC_M420: 1.244 + src = sample + (src_width * crop_y) * 12 / 8 + crop_x; 1.245 + r = M420ToI420(src, src_width, 1.246 + y, y_stride, 1.247 + u, u_stride, 1.248 + v, v_stride, 1.249 + crop_width, inv_crop_height); 1.250 + break; 1.251 + case FOURCC_Q420: 1.252 + src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x; 1.253 + src_uv = sample + (src_width + aligned_src_width * 2) * crop_y + 1.254 + src_width + crop_x * 2; 1.255 + r = Q420ToI420(src, src_width * 3, 1.256 + src_uv, src_width * 3, 1.257 + y, y_stride, 1.258 + u, u_stride, 1.259 + v, v_stride, 1.260 + crop_width, inv_crop_height); 1.261 + break; 1.262 + // Triplanar formats 1.263 + case FOURCC_I420: 1.264 + case FOURCC_YU12: 1.265 + case FOURCC_YV12: { 1.266 + const uint8* src_y = sample + (src_width * crop_y + crop_x); 1.267 + const uint8* src_u; 1.268 + const uint8* src_v; 1.269 + int halfwidth = (src_width + 1) / 2; 1.270 + int halfheight = (abs_src_height + 1) / 2; 1.271 + if (format == FOURCC_YV12) { 1.272 + src_v = sample + src_width * abs_src_height + 1.273 + (halfwidth * crop_y + crop_x) / 2; 1.274 + src_u = sample + src_width * abs_src_height + 1.275 + halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 1.276 + } else { 1.277 + src_u = sample + src_width * abs_src_height + 1.278 + (halfwidth * crop_y + crop_x) / 2; 1.279 + src_v = sample + src_width * abs_src_height + 1.280 + halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 1.281 + } 1.282 + r = I420Rotate(src_y, src_width, 1.283 + src_u, halfwidth, 1.284 + src_v, halfwidth, 1.285 + y, y_stride, 1.286 + u, u_stride, 1.287 + v, v_stride, 1.288 + crop_width, inv_crop_height, rotation); 1.289 + break; 1.290 + } 1.291 + case FOURCC_I422: 1.292 + case FOURCC_YV16: { 1.293 + const uint8* src_y = sample + src_width * crop_y + crop_x; 1.294 + const uint8* src_u; 1.295 + const uint8* src_v; 1.296 + int halfwidth = (src_width + 1) / 2; 1.297 + if (format == FOURCC_YV16) { 1.298 + src_v = sample + src_width * abs_src_height + 1.299 + halfwidth * crop_y + crop_x / 2; 1.300 + src_u = sample + src_width * abs_src_height + 1.301 + halfwidth * (abs_src_height + crop_y) + crop_x / 2; 1.302 + } else { 1.303 + src_u = sample + src_width * abs_src_height + 1.304 + halfwidth * crop_y + crop_x / 2; 1.305 + src_v = sample + src_width * abs_src_height + 1.306 + halfwidth * (abs_src_height + crop_y) + crop_x / 2; 1.307 + } 1.308 + r = I422ToI420(src_y, src_width, 1.309 + src_u, halfwidth, 1.310 + src_v, halfwidth, 1.311 + y, y_stride, 1.312 + u, u_stride, 1.313 + v, v_stride, 1.314 + crop_width, inv_crop_height); 1.315 + break; 1.316 + } 1.317 + case FOURCC_I444: 1.318 + case FOURCC_YV24: { 1.319 + const uint8* src_y = sample + src_width * crop_y + crop_x; 1.320 + const uint8* src_u; 1.321 + const uint8* src_v; 1.322 + if (format == FOURCC_YV24) { 1.323 + src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; 1.324 + src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 1.325 + } else { 1.326 + src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; 1.327 + src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 1.328 + } 1.329 + r = I444ToI420(src_y, src_width, 1.330 + src_u, src_width, 1.331 + src_v, src_width, 1.332 + y, y_stride, 1.333 + u, u_stride, 1.334 + v, v_stride, 1.335 + crop_width, inv_crop_height); 1.336 + break; 1.337 + } 1.338 + case FOURCC_I411: { 1.339 + int quarterwidth = (src_width + 3) / 4; 1.340 + const uint8* src_y = sample + src_width * crop_y + crop_x; 1.341 + const uint8* src_u = sample + src_width * abs_src_height + 1.342 + quarterwidth * crop_y + crop_x / 4; 1.343 + const uint8* src_v = sample + src_width * abs_src_height + 1.344 + quarterwidth * (abs_src_height + crop_y) + crop_x / 4; 1.345 + r = I411ToI420(src_y, src_width, 1.346 + src_u, quarterwidth, 1.347 + src_v, quarterwidth, 1.348 + y, y_stride, 1.349 + u, u_stride, 1.350 + v, v_stride, 1.351 + crop_width, inv_crop_height); 1.352 + break; 1.353 + } 1.354 +#ifdef HAVE_JPEG 1.355 + case FOURCC_MJPG: 1.356 + r = MJPGToI420(sample, sample_size, 1.357 + y, y_stride, 1.358 + u, u_stride, 1.359 + v, v_stride, 1.360 + src_width, abs_src_height, crop_width, inv_crop_height); 1.361 + break; 1.362 +#endif 1.363 + default: 1.364 + r = -1; // unknown fourcc - return failure code. 1.365 + } 1.366 + 1.367 + if (need_buf) { 1.368 + if (!r) { 1.369 + r = I420Rotate(y, y_stride, 1.370 + u, u_stride, 1.371 + v, v_stride, 1.372 + tmp_y, tmp_y_stride, 1.373 + tmp_u, tmp_u_stride, 1.374 + tmp_v, tmp_v_stride, 1.375 + crop_width, abs_crop_height, rotation); 1.376 + } 1.377 + free(rotate_buffer); 1.378 + } 1.379 + 1.380 + return r; 1.381 +} 1.382 + 1.383 +#ifdef __cplusplus 1.384 +} // extern "C" 1.385 +} // namespace libyuv 1.386 +#endif