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