Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 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 | |
Roman Kiryanov | 1b830a4 | 2019-10-09 14:19:10 -0700 | [diff] [blame] | 15 | #include <hardware/gralloc.h> |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 16 | #include "FormatConversions.h" |
| 17 | |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 18 | #if PLATFORM_SDK_VERSION < 26 |
Logan Chien | d7bf00d | 2018-09-21 06:30:09 +0000 | [diff] [blame] | 19 | #include <cutils/log.h> |
Luca Stefani | 1cb647a | 2019-03-07 21:58:17 +0100 | [diff] [blame] | 20 | #else |
| 21 | #include <log/log.h> |
| 22 | #endif |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 23 | #include <string.h> |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 24 | #include <stdio.h> |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 25 | |
| 26 | #define DEBUG 0 |
| 27 | |
| 28 | #if DEBUG |
Roman Kiryanov | 5dd4c7f | 2019-03-12 15:06:15 -0700 | [diff] [blame] | 29 | #define DD(...) ALOGD(__VA_ARGS__) |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 30 | #else |
| 31 | #define DD(...) |
| 32 | #endif |
| 33 | |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 34 | static int get_rgb_offset(int row, int width, int rgbStride) { |
| 35 | return row * width * rgbStride; |
| 36 | } |
| 37 | |
Roman Kiryanov | 1b830a4 | 2019-10-09 14:19:10 -0700 | [diff] [blame] | 38 | bool gralloc_is_yuv_format(const int format) { |
| 39 | switch (format) { |
| 40 | case HAL_PIXEL_FORMAT_YV12: |
| 41 | case HAL_PIXEL_FORMAT_YCbCr_420_888: |
| 42 | case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| 43 | return true; |
| 44 | |
| 45 | default: |
| 46 | return false; |
| 47 | } |
| 48 | } |
| 49 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 50 | void get_yv12_offsets(int width, int height, |
| 51 | uint32_t* yStride_out, |
| 52 | uint32_t* cStride_out, |
| 53 | uint32_t* totalSz_out) { |
| 54 | uint32_t align = 16; |
| 55 | uint32_t yStride = (width + (align - 1)) & ~(align-1); |
| 56 | uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1); |
| 57 | uint32_t uvHeight = height / 2; |
| 58 | uint32_t sz = yStride * height + 2 * (uvHeight * uvStride); |
| 59 | |
| 60 | if (yStride_out) *yStride_out = yStride; |
| 61 | if (cStride_out) *cStride_out = uvStride; |
| 62 | if (totalSz_out) *totalSz_out = sz; |
| 63 | } |
| 64 | |
| 65 | void get_yuv420p_offsets(int width, int height, |
| 66 | uint32_t* yStride_out, |
| 67 | uint32_t* cStride_out, |
| 68 | uint32_t* totalSz_out) { |
| 69 | uint32_t align = 1; |
| 70 | uint32_t yStride = (width + (align - 1)) & ~(align-1); |
Huan Song | 9b140c4 | 2019-10-10 15:59:26 -0700 | [diff] [blame] | 71 | uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 72 | uint32_t uvHeight = height / 2; |
Huan Song | 9b140c4 | 2019-10-10 15:59:26 -0700 | [diff] [blame] | 73 | uint32_t sz = yStride * height + 2 * (uvHeight * uvStride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 74 | |
| 75 | if (yStride_out) *yStride_out = yStride; |
| 76 | if (cStride_out) *cStride_out = uvStride; |
| 77 | if (totalSz_out) *totalSz_out = sz; |
| 78 | } |
| 79 | |
| 80 | signed clamp_rgb(signed value) { |
| 81 | if (value > 255) { |
| 82 | value = 255; |
| 83 | } else if (value < 0) { |
| 84 | value = 0; |
| 85 | } |
| 86 | return value; |
| 87 | } |
| 88 | |
| 89 | void rgb565_to_yv12(char* dest, char* src, int width, int height, |
| 90 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 91 | const int rgb_stride = 2; |
| 92 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 93 | int align = 16; |
| 94 | int yStride = (width + (align -1)) & ~(align-1); |
| 95 | int cStride = (yStride / 2 + (align - 1)) & ~(align-1); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 96 | int cSize = cStride * height/2; |
| 97 | |
| 98 | uint16_t *rgb_ptr0 = (uint16_t *)src; |
| 99 | uint8_t *yv12_y0 = (uint8_t *)dest; |
| 100 | uint8_t *yv12_v0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 101 | |
| 102 | for (int j = top; j <= bottom; ++j) { |
| 103 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
| 104 | uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; |
| 105 | uint8_t *yv12_u = yv12_v + cSize; |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 106 | uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride) / 2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 107 | bool jeven = (j & 1) == 0; |
| 108 | for (int i = left; i <= right; ++i) { |
| 109 | uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f; |
| 110 | uint8_t g = ((rgb_ptr[i]) >> 5) & 0x03f; |
| 111 | uint8_t b = (rgb_ptr[i]) & 0x01f; |
| 112 | // convert to 8bits |
| 113 | // http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888 |
| 114 | uint8_t R = (r * 527 + 23) >> 6; |
| 115 | uint8_t G = (g * 259 + 33) >> 6; |
| 116 | uint8_t B = (b * 527 + 23) >> 6; |
| 117 | // convert to YV12 |
| 118 | // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp |
| 119 | yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8); |
| 120 | bool ieven = (i & 1) == 0; |
| 121 | if (jeven && ieven) { |
| 122 | yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128); |
| 123 | yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128); |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | void rgb888_to_yv12(char* dest, char* src, int width, int height, |
| 130 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 131 | const int rgb_stride = 3; |
| 132 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 133 | DD("%s convert %d by %d", __func__, width, height); |
| 134 | int align = 16; |
| 135 | int yStride = (width + (align -1)) & ~(align-1); |
| 136 | int cStride = (yStride / 2 + (align - 1)) & ~(align-1); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 137 | int cSize = cStride * height/2; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 138 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 139 | |
| 140 | uint8_t *rgb_ptr0 = (uint8_t *)src; |
| 141 | uint8_t *yv12_y0 = (uint8_t *)dest; |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 142 | uint8_t *yv12_u0 = yv12_y0 + yStride * height + cSize; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 143 | uint8_t *yv12_v0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 144 | |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 145 | #if DEBUG |
| 146 | char mybuf[1024]; |
| 147 | snprintf(mybuf, sizeof(mybuf), "/sdcard/raw_%d_%d_rgb.ppm", width, height); |
| 148 | FILE *myfp = fopen(mybuf, "wb"); /* b - binary mode */ |
| 149 | (void) fprintf(myfp, "P6\n%d %d\n255\n", width, height); |
| 150 | |
| 151 | if (myfp == NULL) { |
| 152 | DD("failed to open /sdcard/raw_rgb888.ppm"); |
| 153 | } else { |
| 154 | fwrite(rgb_ptr0, width * height * rgb_stride, 1, myfp); |
| 155 | fclose(myfp); |
| 156 | } |
| 157 | #endif |
| 158 | |
| 159 | int uvcount = 0; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 160 | for (int j = top; j <= bottom; ++j) { |
| 161 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 162 | uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 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 |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 169 | // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion |
| 170 | // but scale up U by 1/0.96 |
| 171 | yv12_y[i] = clamp_rgb(1.0 * ((0.25678823529411765 * R) + (0.5041294117647058 * G) + (0.09790588235294118 * B)) + 16); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 172 | bool ieven = (i & 1) == 0; |
| 173 | if (jeven && ieven) { |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 174 | yv12_u0[uvcount] = clamp_rgb((1/0.96) * (-(0.1482235294117647 * R) - (0.2909921568627451 * G) + (0.4392156862745098 * B)) + 128); |
| 175 | yv12_v0[uvcount] = clamp_rgb((1.0)* ((0.4392156862745098 * R) - (0.36778823529411764 * G) - (0.07142745098039215 * B)) + 128); |
| 176 | uvcount ++; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 177 | } |
| 178 | } |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 179 | if (jeven) { |
| 180 | yv12_u0 += cStride; |
| 181 | yv12_v0 += cStride; |
| 182 | uvcount = 0; |
| 183 | } |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 184 | } |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 185 | |
| 186 | #if DEBUG |
| 187 | snprintf(mybuf, sizeof(mybuf), "/sdcard/raw_%d_%d_yv12.yuv", width, height); |
| 188 | FILE *yuvfp = fopen(mybuf, "wb"); /* b - binary mode */ |
| 189 | if (yuvfp != NULL) { |
| 190 | fwrite(yv12_y0, yStride * height + 2 * cSize, 1, yuvfp); |
| 191 | fclose(yuvfp); |
| 192 | } |
| 193 | #endif |
| 194 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | void rgb888_to_yuv420p(char* dest, char* src, int width, int height, |
| 198 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 199 | const int rgb_stride = 3; |
| 200 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 201 | DD("%s convert %d by %d", __func__, width, height); |
| 202 | int yStride = width; |
| 203 | int cStride = yStride / 2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 204 | int cSize = cStride * height/2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 205 | |
| 206 | uint8_t *rgb_ptr0 = (uint8_t *)src; |
| 207 | uint8_t *yv12_y0 = (uint8_t *)dest; |
| 208 | uint8_t *yv12_u0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 209 | |
| 210 | for (int j = top; j <= bottom; ++j) { |
| 211 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
| 212 | uint8_t *yv12_u = yv12_u0 + (j/2) * cStride; |
Roman Kiryanov | 87b0c2b | 2019-03-12 16:29:48 -0700 | [diff] [blame] | 213 | uint8_t *yv12_v = yv12_u + cSize; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 214 | uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 215 | bool jeven = (j & 1) == 0; |
| 216 | for (int i = left; i <= right; ++i) { |
| 217 | uint8_t R = rgb_ptr[i*rgb_stride]; |
| 218 | uint8_t G = rgb_ptr[i*rgb_stride+1]; |
| 219 | uint8_t B = rgb_ptr[i*rgb_stride+2]; |
| 220 | // convert to YV12 |
| 221 | // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp |
| 222 | yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8); |
| 223 | bool ieven = (i & 1) == 0; |
| 224 | if (jeven && ieven) { |
| 225 | yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128); |
| 226 | yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128); |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | } |
Huan Song | 036f181 | 2019-06-24 17:05:54 -0700 | [diff] [blame] | 231 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 232 | // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has |
| 233 | // certain stride requirements for Y and UV respectively. |
| 234 | void yv12_to_rgb565(char* dest, char* src, int width, int height, |
| 235 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 236 | const int rgb_stride = 2; |
| 237 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 238 | DD("%s convert %d by %d", __func__, width, height); |
| 239 | int align = 16; |
| 240 | int yStride = (width + (align -1)) & ~(align-1); |
| 241 | int cStride = (yStride / 2 + (align - 1)) & ~(align-1); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 242 | int cSize = cStride * height/2; |
| 243 | |
| 244 | uint16_t *rgb_ptr0 = (uint16_t *)dest; |
| 245 | uint8_t *yv12_y0 = (uint8_t *)src; |
| 246 | uint8_t *yv12_v0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 247 | |
| 248 | for (int j = top; j <= bottom; ++j) { |
| 249 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
| 250 | uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; |
| 251 | uint8_t *yv12_u = yv12_v + cSize; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 252 | uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 253 | for (int i = left; i <= right; ++i) { |
| 254 | // convert to rgb |
| 255 | // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp |
| 256 | signed y1 = (signed)yv12_y[i] - 16; |
| 257 | signed u = (signed)yv12_u[i / 2] - 128; |
| 258 | signed v = (signed)yv12_v[i / 2] - 128; |
| 259 | |
| 260 | signed u_b = u * 517; |
| 261 | signed u_g = -u * 100; |
| 262 | signed v_g = -v * 208; |
| 263 | signed v_r = v * 409; |
| 264 | |
| 265 | signed tmp1 = y1 * 298; |
| 266 | signed b1 = clamp_rgb((tmp1 + u_b) / 256); |
| 267 | signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256); |
| 268 | signed r1 = clamp_rgb((tmp1 + v_r) / 256); |
| 269 | |
| 270 | uint16_t rgb1 = ((r1 >> 3) << 11) | ((g1 >> 2) << 5) | (b1 >> 3); |
| 271 | |
| 272 | rgb_ptr[i-left] = rgb1; |
| 273 | } |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has |
| 278 | // certain stride requirements for Y and UV respectively. |
| 279 | void yv12_to_rgb888(char* dest, char* src, int width, int height, |
| 280 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 281 | const int rgb_stride = 3; |
| 282 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 283 | DD("%s convert %d by %d", __func__, width, height); |
| 284 | int align = 16; |
| 285 | int yStride = (width + (align -1)) & ~(align-1); |
| 286 | int cStride = (yStride / 2 + (align - 1)) & ~(align-1); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 287 | int cSize = cStride * height/2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 288 | |
| 289 | uint8_t *rgb_ptr0 = (uint8_t *)dest; |
| 290 | uint8_t *yv12_y0 = (uint8_t *)src; |
| 291 | uint8_t *yv12_v0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 292 | |
| 293 | for (int j = top; j <= bottom; ++j) { |
| 294 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
| 295 | uint8_t *yv12_v = yv12_v0 + (j/2) * cStride; |
| 296 | uint8_t *yv12_u = yv12_v + cSize; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 297 | uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 298 | for (int i = left; i <= right; ++i) { |
| 299 | // convert to rgb |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 300 | // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion |
| 301 | // but scale down U by 0.96 to mitigate rgb over/under flow |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 302 | signed y1 = (signed)yv12_y[i] - 16; |
| 303 | signed u = (signed)yv12_u[i / 2] - 128; |
| 304 | signed v = (signed)yv12_v[i / 2] - 128; |
| 305 | |
bohu | 8db86df | 2019-07-03 14:36:17 -0700 | [diff] [blame] | 306 | signed r1 = clamp_rgb(1 * (1.1643835616438356 * y1 + 1.5960267857142856 * v)); |
| 307 | signed g1 = clamp_rgb(1 * (1.1643835616438356 * y1 - 0.39176229009491365 * u * 0.97 - 0.8129676472377708 * v)); |
| 308 | signed b1 = clamp_rgb(1 * (1.1643835616438356 * y1 + 2.017232142857143 * u * 0.97)); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 309 | |
| 310 | rgb_ptr[(i-left)*rgb_stride] = r1; |
| 311 | rgb_ptr[(i-left)*rgb_stride+1] = g1; |
| 312 | rgb_ptr[(i-left)*rgb_stride+2] = b1; |
| 313 | } |
| 314 | } |
| 315 | } |
| 316 | |
Huan Song | 9b140c4 | 2019-10-10 15:59:26 -0700 | [diff] [blame] | 317 | // YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has |
| 318 | // certain stride requirements for Y and UV respectively. |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 319 | void yuv420p_to_rgb888(char* dest, char* src, int width, int height, |
| 320 | int left, int top, int right, int bottom) { |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 321 | const int rgb_stride = 3; |
| 322 | |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 323 | DD("%s convert %d by %d", __func__, width, height); |
| 324 | int yStride = width; |
| 325 | int cStride = yStride / 2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 326 | int cSize = cStride * height/2; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 327 | |
| 328 | uint8_t *rgb_ptr0 = (uint8_t *)dest; |
| 329 | uint8_t *yv12_y0 = (uint8_t *)src; |
| 330 | uint8_t *yv12_u0 = yv12_y0 + yStride * height; |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 331 | |
| 332 | for (int j = top; j <= bottom; ++j) { |
| 333 | uint8_t *yv12_y = yv12_y0 + j * yStride; |
| 334 | uint8_t *yv12_u = yv12_u0 + (j/2) * cStride; |
| 335 | uint8_t *yv12_v = yv12_u + cSize; |
Roman Kiryanov | 95cdab1 | 2019-03-12 15:24:31 -0700 | [diff] [blame] | 336 | uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride); |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 337 | for (int i = left; i <= right; ++i) { |
| 338 | // convert to rgb |
| 339 | // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp |
| 340 | signed y1 = (signed)yv12_y[i] - 16; |
| 341 | signed u = (signed)yv12_u[i / 2] - 128; |
| 342 | signed v = (signed)yv12_v[i / 2] - 128; |
| 343 | |
| 344 | signed u_b = u * 517; |
| 345 | signed u_g = -u * 100; |
| 346 | signed v_g = -v * 208; |
| 347 | signed v_r = v * 409; |
| 348 | |
| 349 | signed tmp1 = y1 * 298; |
| 350 | signed b1 = clamp_rgb((tmp1 + u_b) / 256); |
| 351 | signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256); |
| 352 | signed r1 = clamp_rgb((tmp1 + v_r) / 256); |
| 353 | |
| 354 | rgb_ptr[(i-left)*rgb_stride] = r1; |
| 355 | rgb_ptr[(i-left)*rgb_stride+1] = g1; |
| 356 | rgb_ptr[(i-left)*rgb_stride+2] = b1; |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | |
Lingfeng Yang | 96ffd14 | 2016-12-14 13:13:51 -0800 | [diff] [blame] | 361 | void copy_rgb_buffer_from_unlocked( |
Roman Kiryanov | 44a5340 | 2019-10-08 16:49:46 -0700 | [diff] [blame] | 362 | char* dst, const char* raw_data, |
Lingfeng Yang | 96ffd14 | 2016-12-14 13:13:51 -0800 | [diff] [blame] | 363 | int unlockedWidth, |
| 364 | int width, int height, int top, int left, |
| 365 | int bpp) { |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 366 | int dst_line_len = width * bpp; |
Lingfeng Yang | 96ffd14 | 2016-12-14 13:13:51 -0800 | [diff] [blame] | 367 | int src_line_len = unlockedWidth * bpp; |
Roman Kiryanov | 44a5340 | 2019-10-08 16:49:46 -0700 | [diff] [blame] | 368 | const char *src = raw_data + top*src_line_len + left*bpp; |
Lingfeng Yang | 96ffd14 | 2016-12-14 13:13:51 -0800 | [diff] [blame] | 369 | for (int y = 0; y < height; y++) { |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 370 | memcpy(dst, src, dst_line_len); |
Lingfeng Yang | 96ffd14 | 2016-12-14 13:13:51 -0800 | [diff] [blame] | 371 | src += src_line_len; |
| 372 | dst += dst_line_len; |
| 373 | } |
Lingfeng Yang | 88c170c | 2016-11-30 00:52:35 +0000 | [diff] [blame] | 374 | } |