• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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