1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Contains implemenation of framebuffer conversion routines.
19 */
20
21 #define LOG_NDEBUG 0
22 #define LOG_TAG "EmulatedCamera_Converter"
23 #include <cutils/log.h>
24 #include "Converters.h"
25
26 #include "Alignment.h"
27
28 namespace android {
29
_YUV420SToRGB565(const uint8_t * Y,const uint8_t * U,const uint8_t * V,int dUV,uint16_t * rgb,int width,int height,int y_stride,int uv_stride)30 static void _YUV420SToRGB565(const uint8_t* Y,
31 const uint8_t* U,
32 const uint8_t* V,
33 int dUV,
34 uint16_t* rgb,
35 int width,
36 int height,
37 int y_stride,
38 int uv_stride)
39 {
40 const uint8_t* Y_pos = Y;
41 const uint8_t* U_pos = U;
42 const uint8_t* V_pos = V;
43
44 for (int y = 0; y < height; y++) {
45 Y = Y_pos + y_stride * y;
46 U = U_pos + uv_stride * (y / 2);
47 V = V_pos + uv_stride * (y / 2);
48 for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
49 const uint8_t nU = *U;
50 const uint8_t nV = *V;
51 *rgb = YUVToRGB565(*Y, nU, nV);
52 Y++; rgb++;
53 *rgb = YUVToRGB565(*Y, nU, nV);
54 Y++; rgb++;
55 }
56 }
57 }
58
_YUV420SToRGB32(const uint8_t * Y,const uint8_t * U,const uint8_t * V,int dUV,uint32_t * rgb,int width,int height,int y_stride,int uv_stride)59 static void _YUV420SToRGB32(const uint8_t* Y,
60 const uint8_t* U,
61 const uint8_t* V,
62 int dUV,
63 uint32_t* rgb,
64 int width,
65 int height,
66 int y_stride,
67 int uv_stride)
68 {
69 const uint8_t* Y_pos = Y;
70 const uint8_t* U_pos = U;
71 const uint8_t* V_pos = V;
72
73 for (int y = 0; y < height; y++) {
74 Y = Y_pos + y_stride * y;
75 U = U_pos + uv_stride * (y / 2);
76 V = V_pos + uv_stride * (y / 2);
77 for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
78 const uint8_t nU = *U;
79 const uint8_t nV = *V;
80 *rgb = YUVToRGB32(*Y, nU, nV);
81 Y++; rgb++;
82 *rgb = YUVToRGB32(*Y, nU, nV);
83 Y++; rgb++;
84 }
85 }
86 }
87
88 /* The YV12 and YU12 formats require that the row strides are aligned to 16 byte
89 * boundaries as per the format specification at:
90 * https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
91 *
92 * This means that we can't just use the width or assume that pixels are
93 * tightly packed, we have to calculate aligned strides and use them to find the
94 * next row.
95 */
YV12ToRGB565(const void * yv12,void * rgb,int width,int height)96 void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
97 {
98 // See note above about alignment
99 const int y_stride = align(width, 16);
100 const int uv_stride = align(y_stride / 2, 16);
101 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
102 const uint8_t* U = Y + y_stride * height;
103 const uint8_t* V = U + uv_stride * (height / 2);
104 _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb),
105 width, height, y_stride, uv_stride);
106 }
107
YV12ToRGB32(const void * yv12,void * rgb,int width,int height)108 void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
109 {
110 // See note above about alignment
111 const int y_stride = align(width, 16);
112 const int uv_stride = align(y_stride / 2, 16);
113 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
114 const uint8_t* V = Y + y_stride * height;
115 const uint8_t* U = V + uv_stride * (height / 2);
116 _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height,
117 y_stride, uv_stride);
118 }
119
YU12ToRGB32(const void * yu12,void * rgb,int width,int height)120 void YU12ToRGB32(const void* yu12, void* rgb, int width, int height)
121 {
122 // See note above about alignment
123 const int y_stride = align(width, 16);
124 const int uv_stride = align(y_stride / 2, 16);
125 const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12);
126 const uint8_t* U = Y + y_stride * height;
127 const uint8_t* V = U + uv_stride * (height / 2);
128 _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height,
129 y_stride, uv_stride);
130 }
131
132 /* Common converter for YUV 4:2:0 interleaved to RGB565.
133 * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
134 */
_NVXXToRGB565(const uint8_t * Y,const uint8_t * U,const uint8_t * V,uint16_t * rgb,int width,int height)135 static void _NVXXToRGB565(const uint8_t* Y,
136 const uint8_t* U,
137 const uint8_t* V,
138 uint16_t* rgb,
139 int width,
140 int height)
141 {
142 // The UV stride for NV21 and NV12 is the same as the width because the
143 // U and V values are interleaved, making each row twice as wide even though
144 // each value covers a two pixel wide area. These formats do not require any
145 // kind of alignment.
146 int y_stride = width;
147 int uv_stride = width;
148 _YUV420SToRGB565(Y, U, V, 2, rgb, width, height, y_stride, uv_stride);
149 }
150
151 /* Common converter for YUV 4:2:0 interleaved to RGB32.
152 * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
153 */
_NVXXToRGB32(const uint8_t * Y,const uint8_t * U,const uint8_t * V,uint32_t * rgb,int width,int height)154 static void _NVXXToRGB32(const uint8_t* Y,
155 const uint8_t* U,
156 const uint8_t* V,
157 uint32_t* rgb,
158 int width,
159 int height)
160 {
161 // The UV stride for NV21 and NV12 is the same as the width because the
162 // U and V values are interleaved, making each row twice as wide even though
163 // each value covers a two pixel wide area. These formats do not require any
164 // kind of alignment.
165 int y_stride = width;
166 int uv_stride = width;
167 _YUV420SToRGB32(Y, U, V, 2, rgb, width, height, y_stride, uv_stride);
168 }
169
NV12ToRGB565(const void * nv12,void * rgb,int width,int height)170 void NV12ToRGB565(const void* nv12, void* rgb, int width, int height)
171 {
172 const int pix_total = width * height;
173 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
174 _NVXXToRGB565(y, y + pix_total, y + pix_total + 1,
175 reinterpret_cast<uint16_t*>(rgb), width, height);
176 }
177
NV12ToRGB32(const void * nv12,void * rgb,int width,int height)178 void NV12ToRGB32(const void* nv12, void* rgb, int width, int height)
179 {
180 const int pix_total = width * height;
181 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
182 _NVXXToRGB32(y, y + pix_total, y + pix_total + 1,
183 reinterpret_cast<uint32_t*>(rgb), width, height);
184 }
185
NV21ToRGB565(const void * nv21,void * rgb,int width,int height)186 void NV21ToRGB565(const void* nv21, void* rgb, int width, int height)
187 {
188 const int pix_total = width * height;
189 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
190 _NVXXToRGB565(y, y + pix_total + 1, y + pix_total,
191 reinterpret_cast<uint16_t*>(rgb), width, height);
192 }
193
NV21ToRGB32(const void * nv21,void * rgb,int width,int height)194 void NV21ToRGB32(const void* nv21, void* rgb, int width, int height)
195 {
196 const int pix_total = width * height;
197 const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
198 _NVXXToRGB32(y, y + pix_total + 1, y + pix_total,
199 reinterpret_cast<uint32_t*>(rgb), width, height);
200 }
201
202 }; /* namespace android */
203