blob: ca4286c83ae1bbd4943094da9dc05eae4098d73d [file] [log] [blame]
Lingfeng Yang88c170c2016-11-30 00:52:35 +00001/*
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 Kiryanov1b830a42019-10-09 14:19:10 -070015#include <hardware/gralloc.h>
Lingfeng Yang88c170c2016-11-30 00:52:35 +000016#include "FormatConversions.h"
17
Luca Stefani1cb647a2019-03-07 21:58:17 +010018#if PLATFORM_SDK_VERSION < 26
Logan Chiend7bf00d2018-09-21 06:30:09 +000019#include <cutils/log.h>
Luca Stefani1cb647a2019-03-07 21:58:17 +010020#else
21#include <log/log.h>
22#endif
Lingfeng Yang88c170c2016-11-30 00:52:35 +000023#include <string.h>
bohu8db86df2019-07-03 14:36:17 -070024#include <stdio.h>
Lingfeng Yang88c170c2016-11-30 00:52:35 +000025
26#define DEBUG 0
27
28#if DEBUG
Roman Kiryanov5dd4c7f2019-03-12 15:06:15 -070029#define DD(...) ALOGD(__VA_ARGS__)
Lingfeng Yang88c170c2016-11-30 00:52:35 +000030#else
31#define DD(...)
32#endif
33
Roman Kiryanov95cdab12019-03-12 15:24:31 -070034static int get_rgb_offset(int row, int width, int rgbStride) {
35 return row * width * rgbStride;
36}
37
Roman Kiryanov1b830a42019-10-09 14:19:10 -070038bool 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 Yang88c170c2016-11-30 00:52:35 +000050void 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
65void 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 Song9b140c42019-10-10 15:59:26 -070071 uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1);
Lingfeng Yang88c170c2016-11-30 00:52:35 +000072 uint32_t uvHeight = height / 2;
Huan Song9b140c42019-10-10 15:59:26 -070073 uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +000074
75 if (yStride_out) *yStride_out = yStride;
76 if (cStride_out) *cStride_out = uvStride;
77 if (totalSz_out) *totalSz_out = sz;
78}
79
80signed 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
89void rgb565_to_yv12(char* dest, char* src, int width, int height,
90 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -070091 const int rgb_stride = 2;
92
Lingfeng Yang88c170c2016-11-30 00:52:35 +000093 int align = 16;
94 int yStride = (width + (align -1)) & ~(align-1);
95 int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
Lingfeng Yang88c170c2016-11-30 00:52:35 +000096 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 Yang88c170c2016-11-30 00:52:35 +0000101
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;
bohu8db86df2019-07-03 14:36:17 -0700106 uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride) / 2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000107 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
129void rgb888_to_yv12(char* dest, char* src, int width, int height,
130 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700131 const int rgb_stride = 3;
132
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000133 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 Yang88c170c2016-11-30 00:52:35 +0000137 int cSize = cStride * height/2;
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700138
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000139
140 uint8_t *rgb_ptr0 = (uint8_t *)src;
141 uint8_t *yv12_y0 = (uint8_t *)dest;
bohu8db86df2019-07-03 14:36:17 -0700142 uint8_t *yv12_u0 = yv12_y0 + yStride * height + cSize;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000143 uint8_t *yv12_v0 = yv12_y0 + yStride * height;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000144
bohu8db86df2019-07-03 14:36:17 -0700145#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 Yang88c170c2016-11-30 00:52:35 +0000160 for (int j = top; j <= bottom; ++j) {
161 uint8_t *yv12_y = yv12_y0 + j * yStride;
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700162 uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000163 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
bohu8db86df2019-07-03 14:36:17 -0700169 // 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 Yang88c170c2016-11-30 00:52:35 +0000172 bool ieven = (i & 1) == 0;
173 if (jeven && ieven) {
bohu8db86df2019-07-03 14:36:17 -0700174 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 Yang88c170c2016-11-30 00:52:35 +0000177 }
178 }
bohu8db86df2019-07-03 14:36:17 -0700179 if (jeven) {
180 yv12_u0 += cStride;
181 yv12_v0 += cStride;
182 uvcount = 0;
183 }
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000184 }
bohu8db86df2019-07-03 14:36:17 -0700185
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 Yang88c170c2016-11-30 00:52:35 +0000195}
196
197void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
198 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700199 const int rgb_stride = 3;
200
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000201 DD("%s convert %d by %d", __func__, width, height);
202 int yStride = width;
203 int cStride = yStride / 2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000204 int cSize = cStride * height/2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000205
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 Yang88c170c2016-11-30 00:52:35 +0000209
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 Kiryanov87b0c2b2019-03-12 16:29:48 -0700213 uint8_t *yv12_v = yv12_u + cSize;
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700214 uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000215 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 Song036f1812019-06-24 17:05:54 -0700231
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000232// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
233// certain stride requirements for Y and UV respectively.
234void yv12_to_rgb565(char* dest, char* src, int width, int height,
235 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700236 const int rgb_stride = 2;
237
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000238 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 Yang88c170c2016-11-30 00:52:35 +0000242 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 Yang88c170c2016-11-30 00:52:35 +0000247
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 Kiryanov95cdab12019-03-12 15:24:31 -0700252 uint16_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j, width, rgb_stride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000253 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.
279void yv12_to_rgb888(char* dest, char* src, int width, int height,
280 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700281 const int rgb_stride = 3;
282
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000283 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 Yang88c170c2016-11-30 00:52:35 +0000287 int cSize = cStride * height/2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000288
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 Yang88c170c2016-11-30 00:52:35 +0000292
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 Kiryanov95cdab12019-03-12 15:24:31 -0700297 uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000298 for (int i = left; i <= right; ++i) {
299 // convert to rgb
bohu8db86df2019-07-03 14:36:17 -0700300 // 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 Yang88c170c2016-11-30 00:52:35 +0000302 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
bohu8db86df2019-07-03 14:36:17 -0700306 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 Yang88c170c2016-11-30 00:52:35 +0000309
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 Song9b140c42019-10-10 15:59:26 -0700317// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
318// certain stride requirements for Y and UV respectively.
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000319void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
320 int left, int top, int right, int bottom) {
Roman Kiryanov95cdab12019-03-12 15:24:31 -0700321 const int rgb_stride = 3;
322
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000323 DD("%s convert %d by %d", __func__, width, height);
324 int yStride = width;
325 int cStride = yStride / 2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000326 int cSize = cStride * height/2;
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000327
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 Yang88c170c2016-11-30 00:52:35 +0000331
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 Kiryanov95cdab12019-03-12 15:24:31 -0700336 uint8_t *rgb_ptr = rgb_ptr0 + get_rgb_offset(j - top, right - left + 1, rgb_stride);
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000337 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 Yang96ffd142016-12-14 13:13:51 -0800361void copy_rgb_buffer_from_unlocked(
Roman Kiryanov44a53402019-10-08 16:49:46 -0700362 char* dst, const char* raw_data,
Lingfeng Yang96ffd142016-12-14 13:13:51 -0800363 int unlockedWidth,
364 int width, int height, int top, int left,
365 int bpp) {
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000366 int dst_line_len = width * bpp;
Lingfeng Yang96ffd142016-12-14 13:13:51 -0800367 int src_line_len = unlockedWidth * bpp;
Roman Kiryanov44a53402019-10-08 16:49:46 -0700368 const char *src = raw_data + top*src_line_len + left*bpp;
Lingfeng Yang96ffd142016-12-14 13:13:51 -0800369 for (int y = 0; y < height; y++) {
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000370 memcpy(dst, src, dst_line_len);
Lingfeng Yang96ffd142016-12-14 13:13:51 -0800371 src += src_line_len;
372 dst += dst_line_len;
373 }
Lingfeng Yang88c170c2016-11-30 00:52:35 +0000374}