1// Copyright 2016 Adrien Descamps
2// Distributed under BSD 3-Clause License
3
4/* You need to define the following macros before including this file:
5 STD_FUNCTION_NAME
6 YUV_FORMAT
7 RGB_FORMAT
8*/
9
10#if RGB_FORMAT == RGB_FORMAT_RGB565
11
12#define PACK_PIXEL(rgb_ptr) \
13 *(Uint16 *)rgb_ptr = \
14 ((((Uint16)clampU8(y_tmp+r_tmp)) << 8 ) & 0xF800) | \
15 ((((Uint16)clampU8(y_tmp+g_tmp)) << 3) & 0x07E0) | \
16 (((Uint16)clampU8(y_tmp+b_tmp)) >> 3); \
17 rgb_ptr += 2; \
18
19#elif RGB_FORMAT == RGB_FORMAT_RGB24
20
21#define PACK_PIXEL(rgb_ptr) \
22 rgb_ptr[0] = clampU8(y_tmp+r_tmp); \
23 rgb_ptr[1] = clampU8(y_tmp+g_tmp); \
24 rgb_ptr[2] = clampU8(y_tmp+b_tmp); \
25 rgb_ptr += 3; \
26
27#elif RGB_FORMAT == RGB_FORMAT_RGBA
28
29#define PACK_PIXEL(rgb_ptr) \
30 *(Uint32 *)rgb_ptr = \
31 (((Uint32)clampU8(y_tmp+r_tmp)) << 24) | \
32 (((Uint32)clampU8(y_tmp+g_tmp)) << 16) | \
33 (((Uint32)clampU8(y_tmp+b_tmp)) << 8) | \
34 0x000000FF; \
35 rgb_ptr += 4; \
36
37#elif RGB_FORMAT == RGB_FORMAT_BGRA
38
39#define PACK_PIXEL(rgb_ptr) \
40 *(Uint32 *)rgb_ptr = \
41 (((Uint32)clampU8(y_tmp+b_tmp)) << 24) | \
42 (((Uint32)clampU8(y_tmp+g_tmp)) << 16) | \
43 (((Uint32)clampU8(y_tmp+r_tmp)) << 8) | \
44 0x000000FF; \
45 rgb_ptr += 4; \
46
47#elif RGB_FORMAT == RGB_FORMAT_ARGB
48
49#define PACK_PIXEL(rgb_ptr) \
50 *(Uint32 *)rgb_ptr = \
51 0xFF000000 | \
52 (((Uint32)clampU8(y_tmp+r_tmp)) << 16) | \
53 (((Uint32)clampU8(y_tmp+g_tmp)) << 8) | \
54 (((Uint32)clampU8(y_tmp+b_tmp)) << 0); \
55 rgb_ptr += 4; \
56
57#elif RGB_FORMAT == RGB_FORMAT_ABGR
58
59#define PACK_PIXEL(rgb_ptr) \
60 *(Uint32 *)rgb_ptr = \
61 0xFF000000 | \
62 (((Uint32)clampU8(y_tmp+b_tmp)) << 16) | \
63 (((Uint32)clampU8(y_tmp+g_tmp)) << 8) | \
64 (((Uint32)clampU8(y_tmp+r_tmp)) << 0); \
65 rgb_ptr += 4; \
66
67#elif RGB_FORMAT == RGB_FORMAT_XBGR2101010
68
69#define PACK_PIXEL(rgb_ptr) \
70 *(Uint32 *)rgb_ptr = \
71 0xC0000000 | \
72 (((Uint32)clamp10(y_tmp+b_tmp)) << 20) | \
73 (((Uint32)clamp10(y_tmp+g_tmp)) << 10) | \
74 (((Uint32)clamp10(y_tmp+r_tmp)) << 0); \
75 rgb_ptr += 4; \
76
77#else
78#error PACK_PIXEL unimplemented
79#endif
80
81
82#ifdef _MSC_VER /* Visual Studio analyzer can't tell that we're building this with different constants */
83#pragma warning(push)
84#pragma warning(disable : 6239)
85#endif
86
87#undef YUV_TYPE
88#if YUV_BITS > 8
89#define YUV_TYPE uint16_t
90#else
91#define YUV_TYPE uint8_t
92#endif
93#undef UV_OFFSET
94#define UV_OFFSET (1 << ((YUV_BITS)-1))
95
96#undef GET
97#if YUV_BITS == 10
98#define GET(X) ((X) >> 6)
99#else
100#define GET(X) (X)
101#endif
102
103void STD_FUNCTION_NAME(
104 uint32_t width, uint32_t height,
105 const YUV_TYPE *Y, const YUV_TYPE *U, const YUV_TYPE *V, uint32_t Y_stride, uint32_t UV_stride,
106 uint8_t *RGB, uint32_t RGB_stride,
107 YCbCrType yuv_type)
108{
109 const YUV2RGBParam *const param = &(YUV2RGB[yuv_type]);
110#if YUV_FORMAT == YUV_FORMAT_420
111 #define y_pixel_stride 1
112 #define uv_pixel_stride 1
113 #define uv_x_sample_interval 2
114 #define uv_y_sample_interval 2
115#elif YUV_FORMAT == YUV_FORMAT_422
116 #define y_pixel_stride 2
117 #define uv_pixel_stride 4
118 #define uv_x_sample_interval 2
119 #define uv_y_sample_interval 1
120#elif YUV_FORMAT == YUV_FORMAT_NV12
121 #define y_pixel_stride 1
122 #define uv_pixel_stride 2
123 #define uv_x_sample_interval 2
124 #define uv_y_sample_interval 2
125#endif
126
127 Y_stride /= sizeof(YUV_TYPE);
128 UV_stride /= sizeof(YUV_TYPE);
129
130 uint32_t x, y;
131 for(y=0; y<(height-(uv_y_sample_interval-1)); y+=uv_y_sample_interval)
132 {
133 const YUV_TYPE *y_ptr1=Y+y*Y_stride,
134 *u_ptr=U+(y/uv_y_sample_interval)*UV_stride,
135 *v_ptr=V+(y/uv_y_sample_interval)*UV_stride;
136
137 #if uv_y_sample_interval > 1
138 const YUV_TYPE *y_ptr2=Y+(y+1)*Y_stride;
139 #endif
140
141 uint8_t *rgb_ptr1=RGB+y*RGB_stride;
142
143 #if uv_y_sample_interval > 1
144 uint8_t *rgb_ptr2=RGB+(y+1)*RGB_stride;
145 #endif
146
147 for(x=0; x<(width-(uv_x_sample_interval-1)); x+=uv_x_sample_interval)
148 {
149 // Compute U and V contributions, common to the four pixels
150
151 int32_t u_tmp = (GET(*u_ptr)-UV_OFFSET);
152 int32_t v_tmp = (GET(*v_ptr)-UV_OFFSET);
153
154 int32_t r_tmp = (v_tmp*param->v_r_factor);
155 int32_t g_tmp = (u_tmp*param->u_g_factor + v_tmp*param->v_g_factor);
156 int32_t b_tmp = (u_tmp*param->u_b_factor);
157
158 // Compute the Y contribution for each pixel
159
160 int32_t y_tmp = (GET(y_ptr1[0]-param->y_shift)*param->y_factor);
161 PACK_PIXEL(rgb_ptr1);
162
163 y_tmp = (GET(y_ptr1[y_pixel_stride]-param->y_shift)*param->y_factor);
164 PACK_PIXEL(rgb_ptr1);
165
166 #if uv_y_sample_interval > 1
167 y_tmp = (GET(y_ptr2[0]-param->y_shift)*param->y_factor);
168 PACK_PIXEL(rgb_ptr2);
169
170 y_tmp = (GET(y_ptr2[y_pixel_stride]-param->y_shift)*param->y_factor);
171 PACK_PIXEL(rgb_ptr2);
172 #endif
173
174 y_ptr1+=2*y_pixel_stride;
175 #if uv_y_sample_interval > 1
176 y_ptr2+=2*y_pixel_stride;
177 #endif
178 u_ptr+=2*uv_pixel_stride/uv_x_sample_interval;
179 v_ptr+=2*uv_pixel_stride/uv_x_sample_interval;
180 }
181
182 /* Catch the last pixel, if needed */
183 if (uv_x_sample_interval == 2 && x == (width-1))
184 {
185 // Compute U and V contributions, common to the four pixels
186
187 int32_t u_tmp = (GET(*u_ptr)-UV_OFFSET);
188 int32_t v_tmp = (GET(*v_ptr)-UV_OFFSET);
189
190 int32_t r_tmp = (v_tmp*param->v_r_factor);
191 int32_t g_tmp = (u_tmp*param->u_g_factor + v_tmp*param->v_g_factor);
192 int32_t b_tmp = (u_tmp*param->u_b_factor);
193
194 // Compute the Y contribution for each pixel
195
196 int32_t y_tmp = (GET(y_ptr1[0]-param->y_shift)*param->y_factor);
197 PACK_PIXEL(rgb_ptr1);
198
199 #if uv_y_sample_interval > 1
200 y_tmp = (GET(y_ptr2[0]-param->y_shift)*param->y_factor);
201 PACK_PIXEL(rgb_ptr2);
202 #endif
203 }
204 }
205
206 /* Catch the last line, if needed */
207 if (uv_y_sample_interval == 2 && y == (height-1))
208 {
209 const YUV_TYPE *y_ptr1=Y+y*Y_stride,
210 *u_ptr=U+(y/uv_y_sample_interval)*UV_stride,
211 *v_ptr=V+(y/uv_y_sample_interval)*UV_stride;
212
213 uint8_t *rgb_ptr1=RGB+y*RGB_stride;
214
215 for(x=0; x<(width-(uv_x_sample_interval-1)); x+=uv_x_sample_interval)
216 {
217 // Compute U and V contributions, common to the four pixels
218
219 int32_t u_tmp = (GET(*u_ptr)-UV_OFFSET);
220 int32_t v_tmp = (GET(*v_ptr)-UV_OFFSET);
221
222 int32_t r_tmp = (v_tmp*param->v_r_factor);
223 int32_t g_tmp = (u_tmp*param->u_g_factor + v_tmp*param->v_g_factor);
224 int32_t b_tmp = (u_tmp*param->u_b_factor);
225
226 // Compute the Y contribution for each pixel
227
228 int32_t y_tmp = (GET(y_ptr1[0]-param->y_shift)*param->y_factor);
229 PACK_PIXEL(rgb_ptr1);
230
231 y_tmp = (GET(y_ptr1[y_pixel_stride]-param->y_shift)*param->y_factor);
232 PACK_PIXEL(rgb_ptr1);
233
234 y_ptr1+=2*y_pixel_stride;
235 u_ptr+=2*uv_pixel_stride/uv_x_sample_interval;
236 v_ptr+=2*uv_pixel_stride/uv_x_sample_interval;
237 }
238
239 /* Catch the last pixel, if needed */
240 if (uv_x_sample_interval == 2 && x == (width-1))
241 {
242 // Compute U and V contributions, common to the four pixels
243
244 int32_t u_tmp = (GET(*u_ptr)-UV_OFFSET);
245 int32_t v_tmp = (GET(*v_ptr)-UV_OFFSET);
246
247 int32_t r_tmp = (v_tmp*param->v_r_factor);
248 int32_t g_tmp = (u_tmp*param->u_g_factor + v_tmp*param->v_g_factor);
249 int32_t b_tmp = (u_tmp*param->u_b_factor);
250
251 // Compute the Y contribution for each pixel
252
253 int32_t y_tmp = (GET(y_ptr1[0]-param->y_shift)*param->y_factor);
254 PACK_PIXEL(rgb_ptr1);
255 }
256 }
257
258 #undef y_pixel_stride
259 #undef uv_pixel_stride
260 #undef uv_x_sample_interval
261 #undef uv_y_sample_interval
262}
263
264#ifdef _MSC_VER
265#pragma warning(pop)
266#endif
267
268#undef STD_FUNCTION_NAME
269#undef YUV_FORMAT
270#undef RGB_FORMAT
271#undef PACK_PIXEL
272