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