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