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