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
get_yv12_offsets(int width,int height,uint32_t * yStride_out,uint32_t * cStride_out,uint32_t * totalSz_out)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
get_yuv420p_offsets(int width,int height,uint32_t * yStride_out,uint32_t * cStride_out,uint32_t * totalSz_out)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
clamp_rgb(signed value)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
rgb565_to_yv12(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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
rgb888_to_yv12(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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
rgb888_to_yuv420p(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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.
yv12_to_rgb565(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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.
yv12_to_rgb888(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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.
yuv420p_to_rgb888(char * dest,char * src,int width,int height,int left,int top,int right,int bottom)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
copy_rgb_buffer_from_unlocked(char * _dst,char * raw_data,int unlockedWidth,int width,int height,int top,int left,int bpp)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