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