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 ARGB 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* dest_argb = crop_argb; 55 int dest_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 * 4 * abs_crop_height; 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 * 4; 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_YV12: { 180 const uint8* src_y = sample + (src_width * crop_y + crop_x); 181 const uint8* src_u; 182 const uint8* src_v; 183 int halfwidth = (src_width + 1) / 2; 184 int halfheight = (abs_src_height + 1) / 2; 185 if (format == FOURCC_YV12) { 186 src_v = sample + src_width * abs_src_height + 187 (halfwidth * crop_y + crop_x) / 2; 188 src_u = sample + src_width * abs_src_height + 189 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 190 } else { 191 src_u = sample + src_width * abs_src_height + 192 (halfwidth * crop_y + crop_x) / 2; 193 src_v = sample + src_width * abs_src_height + 194 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 195 } 196 r = I420ToARGB(src_y, src_width, 197 src_u, halfwidth, 198 src_v, halfwidth, 199 crop_argb, argb_stride, 200 crop_width, inv_crop_height); 201 break; 202 } 203 204 case FOURCC_J420: { 205 const uint8* src_y = sample + (src_width * crop_y + crop_x); 206 const uint8* src_u; 207 const uint8* src_v; 208 int halfwidth = (src_width + 1) / 2; 209 int halfheight = (abs_src_height + 1) / 2; 210 src_u = sample + src_width * abs_src_height + 211 (halfwidth * crop_y + crop_x) / 2; 212 src_v = sample + src_width * abs_src_height + 213 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 214 r = J420ToARGB(src_y, src_width, 215 src_u, halfwidth, 216 src_v, halfwidth, 217 crop_argb, argb_stride, 218 crop_width, inv_crop_height); 219 break; 220 } 221 222 case FOURCC_I422: 223 case FOURCC_YV16: { 224 const uint8* src_y = sample + src_width * crop_y + crop_x; 225 const uint8* src_u; 226 const uint8* src_v; 227 int halfwidth = (src_width + 1) / 2; 228 if (format == FOURCC_YV16) { 229 src_v = sample + src_width * abs_src_height + 230 halfwidth * crop_y + crop_x / 2; 231 src_u = sample + src_width * abs_src_height + 232 halfwidth * (abs_src_height + crop_y) + crop_x / 2; 233 } else { 234 src_u = sample + src_width * abs_src_height + 235 halfwidth * crop_y + crop_x / 2; 236 src_v = sample + src_width * abs_src_height + 237 halfwidth * (abs_src_height + crop_y) + crop_x / 2; 238 } 239 r = I422ToARGB(src_y, src_width, 240 src_u, halfwidth, 241 src_v, halfwidth, 242 crop_argb, argb_stride, 243 crop_width, inv_crop_height); 244 break; 245 } 246 case FOURCC_I444: 247 case FOURCC_YV24: { 248 const uint8* src_y = sample + src_width * crop_y + crop_x; 249 const uint8* src_u; 250 const uint8* src_v; 251 if (format == FOURCC_YV24) { 252 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; 253 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 254 } else { 255 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; 256 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 257 } 258 r = I444ToARGB(src_y, src_width, 259 src_u, src_width, 260 src_v, src_width, 261 crop_argb, argb_stride, 262 crop_width, inv_crop_height); 263 break; 264 } 265 case FOURCC_I411: { 266 int quarterwidth = (src_width + 3) / 4; 267 const uint8* src_y = sample + src_width * crop_y + crop_x; 268 const uint8* src_u = sample + src_width * abs_src_height + 269 quarterwidth * crop_y + crop_x / 4; 270 const uint8* src_v = sample + src_width * abs_src_height + 271 quarterwidth * (abs_src_height + crop_y) + crop_x / 4; 272 r = I411ToARGB(src_y, src_width, 273 src_u, quarterwidth, 274 src_v, quarterwidth, 275 crop_argb, argb_stride, 276 crop_width, inv_crop_height); 277 break; 278 } 279#ifdef HAVE_JPEG 280 case FOURCC_MJPG: 281 r = MJPGToARGB(sample, sample_size, 282 crop_argb, argb_stride, 283 src_width, abs_src_height, crop_width, inv_crop_height); 284 break; 285#endif 286 default: 287 r = -1; // unknown fourcc - return failure code. 288 } 289 290 if (need_buf) { 291 if (!r) { 292 r = ARGBRotate(crop_argb, argb_stride, 293 dest_argb, dest_argb_stride, 294 crop_width, abs_crop_height, rotation); 295 } 296 free(rotate_buffer); 297 } 298 299 return r; 300} 301 302#ifdef __cplusplus 303} // extern "C" 304} // namespace libyuv 305#endif 306