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 "libyuv/convert_argb.h" 12 13#include "libyuv/cpu_id.h" 14#include "libyuv/format_conversion.h" 15#ifdef HAVE_JPEG 16#include "libyuv/mjpeg_decoder.h" 17#endif 18#include "libyuv/rotate_argb.h" 19#include "libyuv/row.h" 20#include "libyuv/video_common.h" 21 22#ifdef __cplusplus 23namespace libyuv { 24extern "C" { 25#endif 26 27// Convert camera sample to I420 with cropping, rotation and vertical flip. 28// src_width is used for source stride computation 29// src_height is used to compute location of planes, and indicate inversion 30// sample_size is measured in bytes and is the size of the frame. 31// With MJPEG it is the compressed size of the frame. 32LIBYUV_API 33int ConvertToARGB(const uint8* sample, size_t sample_size, 34 uint8* crop_argb, int argb_stride, 35 int crop_x, int crop_y, 36 int src_width, int src_height, 37 int crop_width, int crop_height, 38 enum RotationMode rotation, 39 uint32 fourcc) { 40 uint32 format = CanonicalFourCC(fourcc); 41 int aligned_src_width = (src_width + 1) & ~1; 42 const uint8* src; 43 const uint8* src_uv; 44 int abs_src_height = (src_height < 0) ? -src_height : src_height; 45 int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height; 46 int r = 0; 47 48 // One pass rotation is available for some formats. For the rest, convert 49 // to I420 (with optional vertical flipping) into a temporary I420 buffer, 50 // and then rotate the I420 to the final destination buffer. 51 // For in-place conversion, if destination crop_argb is same as source sample, 52 // also enable temporary buffer. 53 LIBYUV_BOOL need_buf = (rotation && format != FOURCC_ARGB) || 54 crop_argb == sample; 55 uint8* tmp_argb = crop_argb; 56 int tmp_argb_stride = argb_stride; 57 uint8* rotate_buffer = NULL; 58 int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height; 59 60 if (crop_argb == NULL || sample == NULL || 61 src_width <= 0 || crop_width <= 0 || 62 src_height == 0 || crop_height == 0) { 63 return -1; 64 } 65 if (src_height < 0) { 66 inv_crop_height = -inv_crop_height; 67 } 68 69 if (need_buf) { 70 int argb_size = crop_width * abs_crop_height * 4; 71 rotate_buffer = (uint8*)malloc(argb_size); 72 if (!rotate_buffer) { 73 return 1; // Out of memory runtime error. 74 } 75 crop_argb = rotate_buffer; 76 argb_stride = crop_width; 77 } 78 79 switch (format) { 80 // Single plane formats 81 case FOURCC_YUY2: 82 src = sample + (aligned_src_width * crop_y + crop_x) * 2; 83 r = YUY2ToARGB(src, aligned_src_width * 2, 84 crop_argb, argb_stride, 85 crop_width, inv_crop_height); 86 break; 87 case FOURCC_UYVY: 88 src = sample + (aligned_src_width * crop_y + crop_x) * 2; 89 r = UYVYToARGB(src, aligned_src_width * 2, 90 crop_argb, argb_stride, 91 crop_width, inv_crop_height); 92 break; 93 case FOURCC_24BG: 94 src = sample + (src_width * crop_y + crop_x) * 3; 95 r = RGB24ToARGB(src, src_width * 3, 96 crop_argb, argb_stride, 97 crop_width, inv_crop_height); 98 break; 99 case FOURCC_RAW: 100 src = sample + (src_width * crop_y + crop_x) * 3; 101 r = RAWToARGB(src, src_width * 3, 102 crop_argb, argb_stride, 103 crop_width, inv_crop_height); 104 break; 105 case FOURCC_ARGB: 106 src = sample + (src_width * crop_y + crop_x) * 4; 107 r = ARGBToARGB(src, src_width * 4, 108 crop_argb, argb_stride, 109 crop_width, inv_crop_height); 110 break; 111 case FOURCC_BGRA: 112 src = sample + (src_width * crop_y + crop_x) * 4; 113 r = BGRAToARGB(src, src_width * 4, 114 crop_argb, argb_stride, 115 crop_width, inv_crop_height); 116 break; 117 case FOURCC_ABGR: 118 src = sample + (src_width * crop_y + crop_x) * 4; 119 r = ABGRToARGB(src, src_width * 4, 120 crop_argb, argb_stride, 121 crop_width, inv_crop_height); 122 break; 123 case FOURCC_RGBA: 124 src = sample + (src_width * crop_y + crop_x) * 4; 125 r = RGBAToARGB(src, src_width * 4, 126 crop_argb, argb_stride, 127 crop_width, inv_crop_height); 128 break; 129 case FOURCC_RGBP: 130 src = sample + (src_width * crop_y + crop_x) * 2; 131 r = RGB565ToARGB(src, src_width * 2, 132 crop_argb, argb_stride, 133 crop_width, inv_crop_height); 134 break; 135 case FOURCC_RGBO: 136 src = sample + (src_width * crop_y + crop_x) * 2; 137 r = ARGB1555ToARGB(src, src_width * 2, 138 crop_argb, argb_stride, 139 crop_width, inv_crop_height); 140 break; 141 case FOURCC_R444: 142 src = sample + (src_width * crop_y + crop_x) * 2; 143 r = ARGB4444ToARGB(src, src_width * 2, 144 crop_argb, argb_stride, 145 crop_width, inv_crop_height); 146 break; 147 // TODO(fbarchard): Support cropping Bayer by odd numbers 148 // by adjusting fourcc. 149 case FOURCC_BGGR: 150 src = sample + (src_width * crop_y + crop_x); 151 r = BayerBGGRToARGB(src, src_width, 152 crop_argb, argb_stride, 153 crop_width, inv_crop_height); 154 break; 155 156 case FOURCC_GBRG: 157 src = sample + (src_width * crop_y + crop_x); 158 r = BayerGBRGToARGB(src, src_width, 159 crop_argb, argb_stride, 160 crop_width, inv_crop_height); 161 break; 162 163 case FOURCC_GRBG: 164 src = sample + (src_width * crop_y + crop_x); 165 r = BayerGRBGToARGB(src, src_width, 166 crop_argb, argb_stride, 167 crop_width, inv_crop_height); 168 break; 169 170 case FOURCC_RGGB: 171 src = sample + (src_width * crop_y + crop_x); 172 r = BayerRGGBToARGB(src, src_width, 173 crop_argb, argb_stride, 174 crop_width, inv_crop_height); 175 break; 176 177 case FOURCC_I400: 178 src = sample + src_width * crop_y + crop_x; 179 r = I400ToARGB(src, src_width, 180 crop_argb, argb_stride, 181 crop_width, inv_crop_height); 182 break; 183 184 // Biplanar formats 185 case FOURCC_NV12: 186 src = sample + (src_width * crop_y + crop_x); 187 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 188 r = NV12ToARGB(src, src_width, 189 src_uv, aligned_src_width, 190 crop_argb, argb_stride, 191 crop_width, inv_crop_height); 192 break; 193 case FOURCC_NV21: 194 src = sample + (src_width * crop_y + crop_x); 195 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 196 // Call NV12 but with u and v parameters swapped. 197 r = NV21ToARGB(src, src_width, 198 src_uv, aligned_src_width, 199 crop_argb, argb_stride, 200 crop_width, inv_crop_height); 201 break; 202 case FOURCC_M420: 203 src = sample + (src_width * crop_y) * 12 / 8 + crop_x; 204 r = M420ToARGB(src, src_width, 205 crop_argb, argb_stride, 206 crop_width, inv_crop_height); 207 break; 208// case FOURCC_Q420: 209// src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x; 210// src_uv = sample + (src_width + aligned_src_width * 2) * crop_y + 211// src_width + crop_x * 2; 212// r = Q420ToARGB(src, src_width * 3, 213// src_uv, src_width * 3, 214// crop_argb, argb_stride, 215// crop_width, inv_crop_height); 216// break; 217 // Triplanar formats 218 case FOURCC_I420: 219 case FOURCC_YU12: 220 case FOURCC_YV12: { 221 const uint8* src_y = sample + (src_width * crop_y + crop_x); 222 const uint8* src_u; 223 const uint8* src_v; 224 int halfwidth = (src_width + 1) / 2; 225 int halfheight = (abs_src_height + 1) / 2; 226 if (format == FOURCC_YV12) { 227 src_v = sample + src_width * abs_src_height + 228 (halfwidth * crop_y + crop_x) / 2; 229 src_u = sample + src_width * abs_src_height + 230 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 231 } else { 232 src_u = sample + src_width * abs_src_height + 233 (halfwidth * crop_y + crop_x) / 2; 234 src_v = sample + src_width * abs_src_height + 235 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 236 } 237 r = I420ToARGB(src_y, src_width, 238 src_u, halfwidth, 239 src_v, halfwidth, 240 crop_argb, argb_stride, 241 crop_width, inv_crop_height); 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 = I422ToARGB(src_y, src_width, 262 src_u, halfwidth, 263 src_v, halfwidth, 264 crop_argb, argb_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 = I444ToARGB(src_y, src_width, 281 src_u, src_width, 282 src_v, src_width, 283 crop_argb, argb_stride, 284 crop_width, inv_crop_height); 285 break; 286 } 287 case FOURCC_I411: { 288 int quarterwidth = (src_width + 3) / 4; 289 const uint8* src_y = sample + src_width * crop_y + crop_x; 290 const uint8* src_u = sample + src_width * abs_src_height + 291 quarterwidth * crop_y + crop_x / 4; 292 const uint8* src_v = sample + src_width * abs_src_height + 293 quarterwidth * (abs_src_height + crop_y) + crop_x / 4; 294 r = I411ToARGB(src_y, src_width, 295 src_u, quarterwidth, 296 src_v, quarterwidth, 297 crop_argb, argb_stride, 298 crop_width, inv_crop_height); 299 break; 300 } 301#ifdef HAVE_JPEG 302 case FOURCC_MJPG: 303 r = MJPGToARGB(sample, sample_size, 304 crop_argb, argb_stride, 305 src_width, abs_src_height, crop_width, inv_crop_height); 306 break; 307#endif 308 default: 309 r = -1; // unknown fourcc - return failure code. 310 } 311 312 if (need_buf) { 313 if (!r) { 314 r = ARGBRotate(crop_argb, argb_stride, 315 tmp_argb, tmp_argb_stride, 316 crop_width, abs_crop_height, rotation); 317 } 318 free(rotate_buffer); 319 } 320 321 return r; 322} 323 324#ifdef __cplusplus 325} // extern "C" 326} // namespace libyuv 327#endif 328