1 /* 2 * Copyright (C) 2016 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #include "FormatConversions.h" 16 17 #include <cutils/log.h> 18 #include <string.h> 19 20 #define DEBUG 0 21 22 #if DEBUG 23 #define DD(...) ALOGD(...) 24 #else 25 #define DD(...) 26 #endif 27 28 void get_yv12_offsets(int width, int height, 29 uint32_t* yStride_out, 30 uint32_t* cStride_out, 31 uint32_t* totalSz_out) { 32 uint32_t align = 16; 33 uint32_t yStride = (width + (align - 1)) & ~(align-1); 34 uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1); 35 uint32_t uvHeight = height / 2; 36 uint32_t sz = yStride * height + 2 * (uvHeight * uvStride); 37 38 if (yStride_out) *yStride_out = yStride; 39 if (cStride_out) *cStride_out = uvStride; 40 if (totalSz_out) *totalSz_out = sz; 41 } 42 43 void get_yuv420p_offsets(int width, int height, 44 uint32_t* yStride_out, 45 uint32_t* cStride_out, 46 uint32_t* totalSz_out) { 47 uint32_t align = 1; 48 uint32_t yStride = (width + (align - 1)) & ~(align-1); 49 uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1); 50 uint32_t uvHeight = height / 2; 51 uint32_t sz = yStride * height + 2 * (uvHeight * uvStride); 52 53 if (yStride_out) *yStride_out = yStride; 54 if (cStride_out) *cStride_out = uvStride; 55 if (totalSz_out) *totalSz_out = sz; 56 } 57 58 signed clamp_rgb(signed value) { 59 if (value > 255) { 60 value = 255; 61 } else if (value < 0) { 62 value = 0; 63 } 64 return value; 65 } 66 67 void rgb565_to_yv12(char* dest, char* src, int width, int height, 68 int left, int top, int right, int bottom) { 69 int align = 16; 70 int yStride = (width + (align -1)) & ~(align-1); 71 int cStride = (yStride / 2 + (align - 1)) & ~(align-1); 72 int yOffset = 0; 73 int cSize = cStride * height/2; 74 75 uint16_t *rgb_ptr0 = (uint16_t *)src; 76 uint8_t *yv12_y0 = (uint8_t *)dest; 77 uint8_t *yv12_v0 = yv12_y0 + yStride * height; 78 uint8_t *yv12_u0 = yv12_v0 + cSize; 79 80 for (int j = top; j <= bottom; ++j) { 81 uint8_t *yv12_y = yv12_y0 + j * yStride; 82 uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; 83 uint8_t *yv12_u = yv12_v + cSize; 84 uint16_t *rgb_ptr = rgb_ptr0 + j * width; 85 bool jeven = (j & 1) == 0; 86 for (int i = left; i <= right; ++i) { 87 uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f; 88 uint8_t g = ((rgb_ptr[i]) >> 5) & 0x03f; 89 uint8_t b = (rgb_ptr[i]) & 0x01f; 90 // convert to 8bits 91 // http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888 92 uint8_t R = (r * 527 + 23) >> 6; 93 uint8_t G = (g * 259 + 33) >> 6; 94 uint8_t B = (b * 527 + 23) >> 6; 95 // convert to YV12 96 // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp 97 yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8); 98 bool ieven = (i & 1) == 0; 99 if (jeven && ieven) { 100 yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128); 101 yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128); 102 } 103 } 104 } 105 } 106 107 void rgb888_to_yv12(char* dest, char* src, int width, int height, 108 int left, int top, int right, int bottom) { 109 DD("%s convert %d by %d", __func__, width, height); 110 int align = 16; 111 int yStride = (width + (align -1)) & ~(align-1); 112 int cStride = (yStride / 2 + (align - 1)) & ~(align-1); 113 int yOffset = 0; 114 int cSize = cStride * height/2; 115 int rgb_stride = 3; 116 117 uint8_t *rgb_ptr0 = (uint8_t *)src; 118 uint8_t *yv12_y0 = (uint8_t *)dest; 119 uint8_t *yv12_v0 = yv12_y0 + yStride * height; 120 uint8_t *yv12_u0 = yv12_v0 + cSize; 121 122 for (int j = top; j <= bottom; ++j) { 123 uint8_t *yv12_y = yv12_y0 + j * yStride; 124 uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; 125 uint8_t *yv12_u = yv12_v + cSize; 126 uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride; 127 bool jeven = (j & 1) == 0; 128 for (int i = left; i <= right; ++i) { 129 uint8_t R = rgb_ptr[i*rgb_stride]; 130 uint8_t G = rgb_ptr[i*rgb_stride+1]; 131 uint8_t B = rgb_ptr[i*rgb_stride+2]; 132 // convert to YV12 133 // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp 134 yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8); 135 bool ieven = (i & 1) == 0; 136 if (jeven && ieven) { 137 yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128); 138 yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128); 139 } 140 } 141 } 142 } 143 144 void rgb888_to_yuv420p(char* dest, char* src, int width, int height, 145 int left, int top, int right, int bottom) { 146 DD("%s convert %d by %d", __func__, width, height); 147 int yStride = width; 148 int cStride = yStride / 2; 149 int yOffset = 0; 150 int cSize = cStride * height/2; 151 int rgb_stride = 3; 152 153 uint8_t *rgb_ptr0 = (uint8_t *)src; 154 uint8_t *yv12_y0 = (uint8_t *)dest; 155 uint8_t *yv12_u0 = yv12_y0 + yStride * height; 156 uint8_t *yv12_v0 = yv12_u0 + cSize; 157 158 for (int j = top; j <= bottom; ++j) { 159 uint8_t *yv12_y = yv12_y0 + j * yStride; 160 uint8_t *yv12_u = yv12_u0 + (j/2) * cStride; 161 uint8_t *yv12_v = yv12_u + cStride; 162 uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride; 163 bool jeven = (j & 1) == 0; 164 for (int i = left; i <= right; ++i) { 165 uint8_t R = rgb_ptr[i*rgb_stride]; 166 uint8_t G = rgb_ptr[i*rgb_stride+1]; 167 uint8_t B = rgb_ptr[i*rgb_stride+2]; 168 // convert to YV12 169 // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp 170 yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8); 171 bool ieven = (i & 1) == 0; 172 if (jeven && ieven) { 173 yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128); 174 yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128); 175 } 176 } 177 } 178 } 179 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has 180 // certain stride requirements for Y and UV respectively. 181 void yv12_to_rgb565(char* dest, char* src, int width, int height, 182 int left, int top, int right, int bottom) { 183 DD("%s convert %d by %d", __func__, width, height); 184 int align = 16; 185 int yStride = (width + (align -1)) & ~(align-1); 186 int cStride = (yStride / 2 + (align - 1)) & ~(align-1); 187 int yOffset = 0; 188 int cSize = cStride * height/2; 189 190 uint16_t *rgb_ptr0 = (uint16_t *)dest; 191 uint8_t *yv12_y0 = (uint8_t *)src; 192 uint8_t *yv12_v0 = yv12_y0 + yStride * height; 193 uint8_t *yv12_u0 = yv12_v0 + cSize; 194 195 for (int j = top; j <= bottom; ++j) { 196 uint8_t *yv12_y = yv12_y0 + j * yStride; 197 uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; 198 uint8_t *yv12_u = yv12_v + cSize; 199 uint16_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1); 200 for (int i = left; i <= right; ++i) { 201 // convert to rgb 202 // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp 203 signed y1 = (signed)yv12_y[i] - 16; 204 signed u = (signed)yv12_u[i / 2] - 128; 205 signed v = (signed)yv12_v[i / 2] - 128; 206 207 signed u_b = u * 517; 208 signed u_g = -u * 100; 209 signed v_g = -v * 208; 210 signed v_r = v * 409; 211 212 signed tmp1 = y1 * 298; 213 signed b1 = clamp_rgb((tmp1 + u_b) / 256); 214 signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256); 215 signed r1 = clamp_rgb((tmp1 + v_r) / 256); 216 217 uint16_t rgb1 = ((r1 >> 3) << 11) | ((g1 >> 2) << 5) | (b1 >> 3); 218 219 rgb_ptr[i-left] = rgb1; 220 } 221 } 222 } 223 224 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has 225 // certain stride requirements for Y and UV respectively. 226 void yv12_to_rgb888(char* dest, char* src, int width, int height, 227 int left, int top, int right, int bottom) { 228 DD("%s convert %d by %d", __func__, width, height); 229 int align = 16; 230 int yStride = (width + (align -1)) & ~(align-1); 231 int cStride = (yStride / 2 + (align - 1)) & ~(align-1); 232 int yOffset = 0; 233 int cSize = cStride * height/2; 234 int rgb_stride = 3; 235 236 uint8_t *rgb_ptr0 = (uint8_t *)dest; 237 uint8_t *yv12_y0 = (uint8_t *)src; 238 uint8_t *yv12_v0 = yv12_y0 + yStride * height; 239 uint8_t *yv12_u0 = yv12_v0 + cSize; 240 241 for (int j = top; j <= bottom; ++j) { 242 uint8_t *yv12_y = yv12_y0 + j * yStride; 243 uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; 244 uint8_t *yv12_u = yv12_v + cSize; 245 uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride; 246 for (int i = left; i <= right; ++i) { 247 // convert to rgb 248 // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp 249 signed y1 = (signed)yv12_y[i] - 16; 250 signed u = (signed)yv12_u[i / 2] - 128; 251 signed v = (signed)yv12_v[i / 2] - 128; 252 253 signed u_b = u * 517; 254 signed u_g = -u * 100; 255 signed v_g = -v * 208; 256 signed v_r = v * 409; 257 258 signed tmp1 = y1 * 298; 259 signed b1 = clamp_rgb((tmp1 + u_b) / 256); 260 signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256); 261 signed r1 = clamp_rgb((tmp1 + v_r) / 256); 262 263 rgb_ptr[(i-left)*rgb_stride] = r1; 264 rgb_ptr[(i-left)*rgb_stride+1] = g1; 265 rgb_ptr[(i-left)*rgb_stride+2] = b1; 266 } 267 } 268 } 269 270 // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has 271 // certain stride requirements for Y and UV respectively. 272 void yuv420p_to_rgb888(char* dest, char* src, int width, int height, 273 int left, int top, int right, int bottom) { 274 DD("%s convert %d by %d", __func__, width, height); 275 int yStride = width; 276 int cStride = yStride / 2; 277 int yOffset = 0; 278 int cSize = cStride * height/2; 279 int rgb_stride = 3; 280 281 uint8_t *rgb_ptr0 = (uint8_t *)dest; 282 uint8_t *yv12_y0 = (uint8_t *)src; 283 uint8_t *yv12_u0 = yv12_y0 + yStride * height; 284 uint8_t *yv12_v0 = yv12_u0 + cSize; 285 286 for (int j = top; j <= bottom; ++j) { 287 uint8_t *yv12_y = yv12_y0 + j * yStride; 288 uint8_t *yv12_u = yv12_u0 + (j/2) * cStride; 289 uint8_t *yv12_v = yv12_u + cSize; 290 uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride; 291 for (int i = left; i <= right; ++i) { 292 // convert to rgb 293 // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp 294 signed y1 = (signed)yv12_y[i] - 16; 295 signed u = (signed)yv12_u[i / 2] - 128; 296 signed v = (signed)yv12_v[i / 2] - 128; 297 298 signed u_b = u * 517; 299 signed u_g = -u * 100; 300 signed v_g = -v * 208; 301 signed v_r = v * 409; 302 303 signed tmp1 = y1 * 298; 304 signed b1 = clamp_rgb((tmp1 + u_b) / 256); 305 signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256); 306 signed r1 = clamp_rgb((tmp1 + v_r) / 256); 307 308 rgb_ptr[(i-left)*rgb_stride] = r1; 309 rgb_ptr[(i-left)*rgb_stride+1] = g1; 310 rgb_ptr[(i-left)*rgb_stride+2] = b1; 311 } 312 } 313 } 314 315 void copy_rgb_buffer_from_unlocked( 316 char* _dst, char* raw_data, 317 int unlockedWidth, 318 int width, int height, int top, int left, 319 int bpp) { 320 char* dst = _dst; 321 int dst_line_len = width * bpp; 322 int src_line_len = unlockedWidth * bpp; 323 char *src = (char *)raw_data + top*src_line_len + left*bpp; 324 for (int y = 0; y < height; y++) { 325 memcpy(dst, src, dst_line_len); 326 src += src_line_len; 327 dst += dst_line_len; 328 } 329 } 330