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