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