1 /**
2  * @file vconv.c Video Conversion
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 
7 #include <string.h>
8 #include <re.h>
9 #include <rem_vid.h>
10 #include <rem_dsp.h>
11 #include <rem_vidconv.h>
12 
13 
14 #if 0
15 
16 /*
17  * The lookup tables are generated with the following code:
18  */
19 
20 #define P 14
21 
22 #define COEF_RV ((int32_t) (1.370705f * (float)(1 << P)))
23 #define COEF_GU ((int32_t) (-0.337633f * (float)(1 << P)))
24 #define COEF_GV ((int32_t) (-0.698001f * (float)(1 << P)))
25 #define COEF_BU ((int32_t) (1.732446f * (float)(1 << P)))
26 
27 #define ERV(a) (COEF_RV * ((a) - 128))
28 #define EGU(a) (COEF_GU * ((a) - 128))
29 #define EGV(a) (COEF_GV * ((a) - 128))
30 #define EBU(a) (COEF_BU * ((a) - 128))
31 
32 
33 int16_t CRV[256];
34 int16_t CGU[256];
35 int16_t CGV[256];
36 int16_t CBU[256];
37 
38 
39 static void init_table(void)
40 {
41 	int i;
42 
43 	for (i = 0; i < 256; ++i) {
44 		CRV[i] = ERV(i) >> P;
45 		CGU[i] = EGU(i) >> P;
46 		CGV[i] = EGV(i) >> P;
47 		CBU[i] = EBU(i) >> P;
48 	}
49 }
50 #endif
51 
52 
53 static const int16_t CRV[256] = {
54 	-176,-175,-173,-172,-170,-169,-168,-166,-165,-164,-162,-161,
55 	-159,-158,-157,-155,-154,-153,-151,-150,-149,-147,-146,-144,
56 	-143,-142,-140,-139,-138,-136,-135,-133,-132,-131,-129,-128,
57 	-127,-125,-124,-122,-121,-120,-118,-117,-116,-114,-113,-112,
58 	-110,-109,-107,-106,-105,-103,-102,-101, -99, -98, -96, -95,
59 	 -94, -92, -91, -90, -88, -87, -85, -84, -83, -81, -80, -79,
60 	 -77, -76, -75, -73, -72, -70, -69, -68, -66, -65, -64, -62,
61 	 -61, -59, -58, -57, -55, -54, -53, -51, -50, -48, -47, -46,
62 	 -44, -43, -42, -40, -39, -38, -36, -35, -33, -32, -31, -29,
63 	 -28, -27, -25, -24, -22, -21, -20, -18, -17, -16, -14, -13,
64 	 -11, -10,  -9,  -7,  -6,  -5,  -3,  -2,   0,   1,   2,   4,
65 	   5,   6,   8,   9,  10,  12,  13,  15,  16,  17,  19,  20,
66 	  21,  23,  24,  26,  27,  28,  30,  31,  32,  34,  35,  37,
67 	  38,  39,  41,  42,  43,  45,  46,  47,  49,  50,  52,  53,
68 	  54,  56,  57,  58,  60,  61,  63,  64,  65,  67,  68,  69,
69 	  71,  72,  74,  75,  76,  78,  79,  80,  82,  83,  84,  86,
70 	  87,  89,  90,  91,  93,  94,  95,  97,  98, 100, 101, 102,
71 	 104, 105, 106, 108, 109, 111, 112, 113, 115, 116, 117, 119,
72 	 120, 121, 123, 124, 126, 127, 128, 130, 131, 132, 134, 135,
73 	 137, 138, 139, 141, 142, 143, 145, 146, 148, 149, 150, 152,
74 	 153, 154, 156, 157, 158, 160, 161, 163, 164, 165, 167, 168,
75 	 169, 171, 172, 174};
76 
77 static const int16_t CGU[256] = {
78 	  43,  42,  42,  42,  41,  41,  41,  40,  40,  40,  39,  39,
79 	  39,  38,  38,  38,  37,  37,  37,  36,  36,  36,  35,  35,
80 	  35,  34,  34,  34,  33,  33,  33,  32,  32,  32,  31,  31,
81 	  31,  30,  30,  30,  29,  29,  29,  28,  28,  28,  27,  27,
82 	  27,  26,  26,  25,  25,  25,  24,  24,  24,  23,  23,  23,
83 	  22,  22,  22,  21,  21,  21,  20,  20,  20,  19,  19,  19,
84 	  18,  18,  18,  17,  17,  17,  16,  16,  16,  15,  15,  15,
85 	  14,  14,  14,  13,  13,  13,  12,  12,  12,  11,  11,  11,
86 	  10,  10,  10,   9,   9,   9,   8,   8,   8,   7,   7,   7,
87 	   6,   6,   6,   5,   5,   5,   4,   4,   4,   3,   3,   3,
88 	   2,   2,   2,   1,   1,   1,   0,   0,   0,  -1,  -1,  -2,
89 	  -2,  -2,  -3,  -3,  -3,  -4,  -4,  -4,  -5,  -5,  -5,  -6,
90 	  -6,  -6,  -7,  -7,  -7,  -8,  -8,  -8,  -9,  -9,  -9, -10,
91 	 -10, -10, -11, -11, -11, -12, -12, -12, -13, -13, -13, -14,
92 	 -14, -14, -15, -15, -15, -16, -16, -16, -17, -17, -17, -18,
93 	 -18, -18, -19, -19, -19, -20, -20, -20, -21, -21, -21, -22,
94 	 -22, -22, -23, -23, -23, -24, -24, -24, -25, -25, -25, -26,
95 	 -26, -26, -27, -27, -28, -28, -28, -29, -29, -29, -30, -30,
96 	 -30, -31, -31, -31, -32, -32, -32, -33, -33, -33, -34, -34,
97 	 -34, -35, -35, -35, -36, -36, -36, -37, -37, -37, -38, -38,
98 	 -38, -39, -39, -39, -40, -40, -40, -41, -41, -41, -42, -42,
99 	 -42, -43, -43, -43};
100 
101 static const int16_t CGV[256] = {
102 	  89,  88,  87,  87,  86,  85,  85,  84,  83,  83,  82,  81,
103 	  80,  80,  79,  78,  78,  77,  76,  76,  75,  74,  73,  73,
104 	  72,  71,  71,  70,  69,  69,  68,  67,  67,  66,  65,  64,
105 	  64,  63,  62,  62,  61,  60,  60,  59,  58,  57,  57,  56,
106 	  55,  55,  54,  53,  53,  52,  51,  50,  50,  49,  48,  48,
107 	  47,  46,  46,  45,  44,  43,  43,  42,  41,  41,  40,  39,
108 	  39,  38,  37,  36,  36,  35,  34,  34,  33,  32,  32,  31,
109 	  30,  30,  29,  28,  27,  27,  26,  25,  25,  24,  23,  23,
110 	  22,  21,  20,  20,  19,  18,  18,  17,  16,  16,  15,  14,
111 	  13,  13,  12,  11,  11,  10,   9,   9,   8,   7,   6,   6,
112 	   5,   4,   4,   3,   2,   2,   1,   0,   0,  -1,  -2,  -3,
113 	  -3,  -4,  -5,  -5,  -6,  -7,  -7,  -8,  -9, -10, -10, -11,
114 	 -12, -12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -19,
115 	 -20, -21, -21, -22, -23, -24, -24, -25, -26, -26, -27, -28,
116 	 -28, -29, -30, -31, -31, -32, -33, -33, -34, -35, -35, -36,
117 	 -37, -37, -38, -39, -40, -40, -41, -42, -42, -43, -44, -44,
118 	 -45, -46, -47, -47, -48, -49, -49, -50, -51, -51, -52, -53,
119 	 -54, -54, -55, -56, -56, -57, -58, -58, -59, -60, -61, -61,
120 	 -62, -63, -63, -64, -65, -65, -66, -67, -68, -68, -69, -70,
121 	 -70, -71, -72, -72, -73, -74, -74, -75, -76, -77, -77, -78,
122 	 -79, -79, -80, -81, -81, -82, -83, -84, -84, -85, -86, -86,
123 	 -87, -88, -88, -89};
124 
125 static const int16_t CBU[256] = {
126 	-222,-221,-219,-217,-215,-214,-212,-210,-208,-207,-205,-203,
127 	-201,-200,-198,-196,-195,-193,-191,-189,-188,-186,-184,-182,
128 	-181,-179,-177,-175,-174,-172,-170,-169,-167,-165,-163,-162,
129 	-160,-158,-156,-155,-153,-151,-149,-148,-146,-144,-143,-141,
130 	-139,-137,-136,-134,-132,-130,-129,-127,-125,-124,-122,-120,
131 	-118,-117,-115,-113,-111,-110,-108,-106,-104,-103,-101, -99,
132 	 -98, -96, -94, -92, -91, -89, -87, -85, -84, -82, -80, -78,
133 	 -77, -75, -73, -72, -70, -68, -66, -65, -63, -61, -59, -58,
134 	 -56, -54, -52, -51, -49, -47, -46, -44, -42, -40, -39, -37,
135 	 -35, -33, -32, -30, -28, -26, -25, -23, -21, -20, -18, -16,
136 	 -14, -13, -11,  -9,  -7,  -6,  -4,  -2,   0,   1,   3,   5,
137 	   6,   8,  10,  12,  13,  15,  17,  19,  20,  22,  24,  25,
138 	  27,  29,  31,  32,  34,  36,  38,  39,  41,  43,  45,  46,
139 	  48,  50,  51,  53,  55,  57,  58,  60,  62,  64,  65,  67,
140 	  69,  71,  72,  74,  76,  77,  79,  81,  83,  84,  86,  88,
141 	  90,  91,  93,  95,  97,  98, 100, 102, 103, 105, 107, 109,
142 	 110, 112, 114, 116, 117, 119, 121, 123, 124, 126, 128, 129,
143 	 131, 133, 135, 136, 138, 140, 142, 143, 145, 147, 148, 150,
144 	 152, 154, 155, 157, 159, 161, 162, 164, 166, 168, 169, 171,
145 	 173, 174, 176, 178, 180, 181, 183, 185, 187, 188, 190, 192,
146 	 194, 195, 197, 199, 200, 202, 204, 206, 207, 209, 211, 213,
147 	 214, 216, 218, 220};
148 
149 
yuv2rgb(uint8_t * rgb,uint8_t y,int ruv,int guv,int buv)150 static inline void yuv2rgb(uint8_t *rgb, uint8_t y, int ruv, int guv, int buv)
151 {
152 	*rgb++ = saturate_u8(y + buv);
153 	*rgb++ = saturate_u8(y + guv);
154 	*rgb++ = saturate_u8(y + ruv);
155 	*rgb   = 0;
156 }
157 
158 
yuv2rgb565(uint8_t * rgb,uint8_t y,int ruv,int guv,int buv)159 static inline void yuv2rgb565(uint8_t *rgb, uint8_t y,
160 			      int ruv, int guv, int buv)
161 {
162 	int r = saturate_u8(y + ruv) >> 3;
163 	int g = saturate_u8(y + guv) >> 2;
164 	int b = saturate_u8(y + buv) >> 3;
165 
166 	rgb[1] = r << 3 | g >> 3;
167 	rgb[0] = g << 5 | b;
168 }
169 
170 
yuv2rgb555(uint8_t * rgb,uint8_t y,int ruv,int guv,int buv)171 static inline void yuv2rgb555(uint8_t *rgb, uint8_t y,
172 			      int ruv, int guv, int buv)
173 {
174 	uint8_t r = saturate_u8(y + ruv) >> 3;
175 	uint8_t g = saturate_u8(y + guv) >> 3;
176 	uint8_t b = saturate_u8(y + buv) >> 3;
177 
178 	rgb[1] = r << 2 | g >> 3;
179 	rgb[0] = g << 5 | b;
180 }
181 
182 
_yuv2rgb(uint8_t * rgb,uint8_t y,uint8_t u,uint8_t v)183 static inline void _yuv2rgb(uint8_t *rgb, uint8_t y, uint8_t u, uint8_t v)
184 {
185 	int ruv, guv, buv;
186 
187 	ruv = CRV[v];
188 	guv = CGV[v] + CGU[u];
189 	buv = CBU[u];
190 
191 	yuv2rgb(rgb, y, ruv, guv, buv);
192 }
193 
194 
195 typedef void (line_h)(unsigned xoffs, unsigned width, double rw,
196 		      unsigned yd, unsigned ys, unsigned ys2,
197 		      uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
198 		      unsigned lsd,
199 		      const uint8_t *sd0, const uint8_t *sd1,
200 		      const uint8_t *sd2, unsigned lss);
201 
202 
yuv420p_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)203 static void yuv420p_to_yuv420p(unsigned xoffs, unsigned width, double rw,
204 			       unsigned yd, unsigned ys, unsigned ys2,
205 			       uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
206 			       unsigned lsd,
207 			       const uint8_t *ds0, const uint8_t *ds1,
208 			       const uint8_t *ds2, unsigned lss
209 			       )
210 {
211 	unsigned x, xd, xs, xs2;
212 	unsigned id, is;
213 
214 	for (x=0; x<width; x+=2) {
215 
216 		xd  = x + xoffs;
217 
218 		xs  = (unsigned)(x * rw);
219 		xs2 = (unsigned)((x+1) * rw);
220 
221 		id = xd + yd*lsd;
222 
223 		dd0[id]         = ds0[xs  + ys*lss];
224 		dd0[id+1]       = ds0[xs2 + ys*lss];
225 		dd0[id + lsd]   = ds0[xs  + ys2*lss];
226 		dd0[id+1 + lsd] = ds0[xs2 + ys2*lss];
227 
228 		id = xd/2    + yd*lsd/4;
229 		is = (xs>>1) + (ys>>1)*lss/2;
230 
231 		dd1[id] = ds1[is];
232 		dd2[id] = ds2[is];
233 	}
234 }
235 
236 
yuyv422_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * sd0,const uint8_t * sd1,const uint8_t * sd2,unsigned lss)237 static void yuyv422_to_yuv420p(unsigned xoffs, unsigned width, double rw,
238 			       unsigned yd, unsigned ys, unsigned ys2,
239 			       uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
240 			       unsigned lsd,
241 			       const uint8_t *sd0, const uint8_t *sd1,
242 			       const uint8_t *sd2, unsigned lss
243 			       )
244 {
245 	unsigned x, xd, xs;
246 	unsigned id, is, is2;
247 
248 	(void)sd1;
249 	(void)sd2;
250 
251 	for (x=0; x<width; x+=2) {
252 
253 		xd  = x + xoffs;
254 
255 		xs  = ((unsigned)(x * rw * 2)) & ~3;
256 
257 		id  = xd + yd*lsd;
258 		is  = xs + ys*lss;
259 		is2 = xs  + ys2*lss;
260 
261 		dd0[id]         = sd0[is];
262 		dd0[id+1]       = sd0[is + 2];
263 		dd0[id + lsd]   = sd0[is2];
264 		dd0[id+1 + lsd] = sd0[is2 + 2];
265 
266 		id = xd/2 + yd*lsd/4;
267 
268 		dd1[id] = sd0[is + 1];
269 		dd2[id] = sd0[is + 3];
270 	}
271 }
272 
273 
uyvy422_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * sd0,const uint8_t * sd1,const uint8_t * sd2,unsigned lss)274 static void uyvy422_to_yuv420p(unsigned xoffs, unsigned width, double rw,
275 			       unsigned yd, unsigned ys, unsigned ys2,
276 			       uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
277 			       unsigned lsd,
278 			       const uint8_t *sd0, const uint8_t *sd1,
279 			       const uint8_t *sd2, unsigned lss
280 			       )
281 {
282 	unsigned x, xd, xs;
283 	unsigned id, is, is2;
284 
285 	(void)sd1;
286 	(void)sd2;
287 
288 	for (x=0; x<width; x+=2) {
289 
290 		xd  = x + xoffs;
291 
292 		xs  = ((unsigned)(x * rw * 2)) & ~3;
293 
294 		id  = xd + yd*lsd;
295 		is  = xs + ys*lss;
296 		is2 = xs  + ys2*lss;
297 
298 		dd0[id]         = sd0[is + 1];
299 		dd0[id+1]       = sd0[is + 3];
300 		dd0[id + lsd]   = sd0[is2 + 1];
301 		dd0[id+1 + lsd] = sd0[is2 + 3];
302 
303 		id = xd/2 + yd*lsd/4;
304 
305 		dd1[id] = sd0[is + 0];
306 		dd2[id] = sd0[is + 2];
307 	}
308 }
309 
310 
rgb32_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)311 static void rgb32_to_yuv420p(unsigned xoffs, unsigned width, double rw,
312 			     unsigned yd, unsigned ys, unsigned ys2,
313 			     uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
314 			     unsigned lsd,
315 			     const uint8_t *ds0, const uint8_t *ds1,
316 			     const uint8_t *ds2, unsigned lss
317 			     )
318 {
319 	unsigned x, xd, xs, xs2;
320 	unsigned id;
321 
322 	(void)ds1;
323 	(void)ds2;
324 
325 	for (x=0; x<width; x+=2) {
326 
327 		uint32_t x0;
328 		uint32_t x1;
329 		uint32_t x2;
330 		uint32_t x3;
331 
332 		xd  = x + xoffs;
333 
334 		xs  = 4 * ((unsigned)( x    * rw));
335 		xs2 = 4 * ((unsigned)((x+1) * rw));
336 
337 		id = xd + yd*lsd;
338 
339 		x0 = *(uint32_t *)(void *)&ds0[xs  + ys*lss];
340 		x1 = *(uint32_t *)(void *)&ds0[xs2 + ys*lss];
341 		x2 = *(uint32_t *)(void *)&ds0[xs  + ys2*lss];
342 		x3 = *(uint32_t *)(void *)&ds0[xs2 + ys2*lss];
343 
344 		dd0[id]         = rgb2y(x0 >> 16, x0 >> 8, x0);
345 		dd0[id+1]       = rgb2y(x1 >> 16, x1 >> 8, x1);
346 		dd0[id + lsd]   = rgb2y(x2 >> 16, x2 >> 8, x2);
347 		dd0[id+1 + lsd] = rgb2y(x3 >> 16, x3 >> 8, x3);
348 
349 		id = xd/2 + yd*lsd/4;
350 
351 		dd1[id] = rgb2u(x0 >> 16, x0 >> 8, x0);
352 		dd2[id] = rgb2v(x0 >> 16, x0 >> 8, x0);
353 	}
354 }
355 
356 
rgb32_to_yuv444p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)357 static void rgb32_to_yuv444p(unsigned xoffs, unsigned width, double rw,
358 			     unsigned yd, unsigned ys, unsigned ys2,
359 			     uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
360 			     unsigned lsd,
361 			     const uint8_t *ds0, const uint8_t *ds1,
362 			     const uint8_t *ds2, unsigned lss
363 			     )
364 {
365 	unsigned x, xd, xs;
366 	unsigned id;
367 
368 	(void)ds1;
369 	(void)ds2;
370 
371 	for (x=0; x<width; x++) {
372 
373 		uint32_t x0;
374 		uint32_t x1;
375 
376 		xd = x + xoffs;
377 
378 		xs = 4 * ((unsigned)(x * rw));
379 
380 		id = xd + yd*lsd;
381 
382 		x0 = *(uint32_t *)(void *)&ds0[xs + ys *lss];
383 		x1 = *(uint32_t *)(void *)&ds0[xs + ys2*lss];
384 
385 		dd0[id]       = rgb2y(x0 >> 16, x0 >> 8, x0);
386 		dd0[id + lsd] = rgb2y(x1 >> 16, x1 >> 8, x1);
387 
388 		dd1[id]       = rgb2u(x0 >> 16, x0 >> 8, x0);
389 		dd1[id + lsd] = rgb2u(x1 >> 16, x1 >> 8, x1);
390 
391 		dd2[id]       = rgb2v(x0 >> 16, x0 >> 8, x0);
392 		dd2[id + lsd] = rgb2v(x1 >> 16, x1 >> 8, x1);
393 	}
394 }
395 
396 
yuv420p_to_rgb32(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)397 static void yuv420p_to_rgb32(unsigned xoffs, unsigned width, double rw,
398 			     unsigned yd, unsigned ys, unsigned ys2,
399 			     uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
400 			     unsigned lsd,
401 			     const uint8_t *ds0, const uint8_t *ds1,
402 			     const uint8_t *ds2, unsigned lss)
403 {
404 	unsigned x, xd, xs, xs2;
405 	unsigned id, is;
406 
407 	(void)dd1;
408 	(void)dd2;
409 
410 	for (x=0; x<width; x+=2) {
411 
412 		int ruv, guv, buv;
413 		uint8_t u, v;
414 
415 		xd  = (x + xoffs) * 4;
416 
417 		xs  = (unsigned)(x * rw);
418 		xs2 = (unsigned)((x+1) * rw);
419 
420 		id = (xd + yd*lsd);
421 		is  = (xs>>1) + (ys>>1)*lss/2;
422 
423 		u = ds1[is];
424 		v = ds2[is];
425 
426 		ruv = CRV[v];
427 		guv = CGV[v] + CGU[u];
428 		buv = CBU[u];
429 
430 		yuv2rgb(&dd0[id],         ds0[xs  + ys*lss],  ruv, guv, buv);
431 		yuv2rgb(&dd0[id+4],       ds0[xs2 + ys*lss],  ruv, guv, buv);
432 		yuv2rgb(&dd0[id   + lsd], ds0[xs  + ys2*lss], ruv, guv, buv);
433 		yuv2rgb(&dd0[id+4 + lsd], ds0[xs2 + ys2*lss], ruv, guv, buv);
434 	}
435 }
436 
437 
yuv420p_to_rgb565(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)438 static void yuv420p_to_rgb565(unsigned xoffs, unsigned width, double rw,
439 			      unsigned yd, unsigned ys, unsigned ys2,
440 			      uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
441 			      unsigned lsd,
442 			      const uint8_t *ds0, const uint8_t *ds1,
443 			      const uint8_t *ds2, unsigned lss)
444 {
445 	unsigned x, xd, xs, xs2;
446 	unsigned id, is;
447 
448 	(void)dd1;
449 	(void)dd2;
450 
451 	for (x=0; x<width; x+=2) {
452 
453 		int ruv, guv, buv;
454 		uint8_t u, v;
455 
456 		xd  = (x + xoffs) * 2;
457 
458 		xs  = (unsigned)(x * rw);
459 		xs2 = (unsigned)((x+1) * rw);
460 
461 		id = (xd + yd*lsd);
462 		is  = (xs>>1) + (ys>>1)*lss/2;
463 
464 		u = ds1[is];
465 		v = ds2[is];
466 
467 		ruv = CRV[v];
468 		guv = CGV[v] + CGU[u];
469 		buv = CBU[u];
470 
471 		yuv2rgb565(&dd0[id],         ds0[xs  + ys*lss],  ruv, guv,buv);
472 		yuv2rgb565(&dd0[id+2],       ds0[xs2 + ys*lss],  ruv, guv,buv);
473 		yuv2rgb565(&dd0[id   + lsd], ds0[xs  + ys2*lss], ruv, guv,buv);
474 		yuv2rgb565(&dd0[id+2 + lsd], ds0[xs2 + ys2*lss], ruv, guv,buv);
475 	}
476 }
477 
478 
yuv420p_to_rgb555(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)479 static void yuv420p_to_rgb555(unsigned xoffs, unsigned width, double rw,
480 			      unsigned yd, unsigned ys, unsigned ys2,
481 			      uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
482 			      unsigned lsd,
483 			      const uint8_t *ds0, const uint8_t *ds1,
484 			      const uint8_t *ds2, unsigned lss)
485 {
486 	unsigned x, xd, xs, xs2;
487 	unsigned id, is;
488 
489 	(void)dd1;
490 	(void)dd2;
491 
492 	for (x=0; x<width; x+=2) {
493 
494 		int ruv, guv, buv;
495 		uint8_t u, v;
496 
497 		xd  = (x + xoffs) * 2;
498 
499 		xs  = (unsigned)(x * rw);
500 		xs2 = (unsigned)((x+1) * rw);
501 
502 		id = (xd + yd*lsd);
503 		is  = (xs>>1) + (ys>>1)*lss/2;
504 
505 		u = ds1[is];
506 		v = ds2[is];
507 
508 		ruv = CRV[v];
509 		guv = CGV[v] + CGU[u];
510 		buv = CBU[u];
511 
512 		yuv2rgb555(&dd0[id],         ds0[xs  + ys*lss],  ruv, guv,buv);
513 		yuv2rgb555(&dd0[id+2],       ds0[xs2 + ys*lss],  ruv, guv,buv);
514 		yuv2rgb555(&dd0[id   + lsd], ds0[xs  + ys2*lss], ruv, guv,buv);
515 		yuv2rgb555(&dd0[id+2 + lsd], ds0[xs2 + ys2*lss], ruv, guv,buv);
516 	}
517 }
518 
519 
nv12_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)520 static void nv12_to_yuv420p(unsigned xoffs, unsigned width, double rw,
521 			    unsigned yd, unsigned ys, unsigned ys2,
522 			    uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
523 			    unsigned lsd,
524 			    const uint8_t *ds0, const uint8_t *ds1,
525 			    const uint8_t *ds2, unsigned lss
526 			    )
527 {
528 	unsigned x, xd, xs, xs2;
529 	unsigned id, is;
530 
531 	(void)ds2;
532 
533 	for (x=0; x<width; x+=2) {
534 
535 		xd  = x + xoffs;
536 
537 		xs  = (unsigned)(x * rw);
538 		xs2 = (unsigned)((x+1) * rw);
539 
540 		id = xd + yd*lsd;
541 
542 		dd0[id]         = ds0[xs  + ys*lss];
543 		dd0[id+1]       = ds0[xs2 + ys*lss];
544 		dd0[id + lsd]   = ds0[xs  + ys2*lss];
545 		dd0[id+1 + lsd] = ds0[xs2 + ys2*lss];
546 
547 		id = (xd>>1) + (yd>>1)*lsd/2;
548 		is = xs/2    + ys*lss/4;
549 
550 		dd1[id] = ds1[2*is];
551 		dd2[id] = ds1[2*is+1];
552 	}
553 }
554 
555 
yuv420p_to_nv12(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)556 static void yuv420p_to_nv12(unsigned xoffs, unsigned width, double rw,
557 			    unsigned yd, unsigned ys, unsigned ys2,
558 			    uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
559 			    unsigned lsd,
560 			    const uint8_t *ds0, const uint8_t *ds1,
561 			    const uint8_t *ds2, unsigned lss
562 			    )
563 {
564 	unsigned x, xd, xs, xs2;
565 	unsigned id, is;
566 
567 	(void)dd2;
568 
569 	for (x=0; x<width; x+=2) {
570 
571 		xd  = x + xoffs;
572 
573 		xs  = (unsigned)(x * rw);
574 		xs2 = (unsigned)((x+1) * rw);
575 
576 		id = xd + yd*lsd;
577 
578 		dd0[id]         = ds0[xs  + ys*lss];
579 		dd0[id+1]       = ds0[xs2 + ys*lss];
580 		dd0[id + lsd]   = ds0[xs  + ys2*lss];
581 		dd0[id+1 + lsd] = ds0[xs2 + ys2*lss];
582 
583 		id = xd/2    + yd*lsd/4;
584 		is = (xs>>1) + (ys>>1)*lss/2;
585 
586 		dd1[2*id]   = ds1[is];
587 		dd1[2*id+1] = ds2[is];
588 	}
589 }
590 
591 
nv21_to_yuv420p(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)592 static void nv21_to_yuv420p(unsigned xoffs, unsigned width, double rw,
593 			    unsigned yd, unsigned ys, unsigned ys2,
594 			    uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
595 			    unsigned lsd,
596 			    const uint8_t *ds0, const uint8_t *ds1,
597 			    const uint8_t *ds2, unsigned lss
598 			    )
599 {
600 	unsigned x, xd, xs, xs2;
601 	unsigned id, is;
602 
603 	(void)ds2;
604 
605 	for (x=0; x<width; x+=2) {
606 
607 		xd  = x + xoffs;
608 
609 		xs  = (unsigned)(x * rw);
610 		xs2 = (unsigned)((x+1) * rw);
611 
612 		id = xd + yd*lsd;
613 
614 		dd0[id]         = ds0[xs  + ys*lss];
615 		dd0[id+1]       = ds0[xs2 + ys*lss];
616 		dd0[id + lsd]   = ds0[xs  + ys2*lss];
617 		dd0[id+1 + lsd] = ds0[xs2 + ys2*lss];
618 
619 		id = xd/2    + yd*lsd/4;
620 		is = ((xs>>1) + (ys>>1)*lss/2) & ~1;
621 
622 		dd2[id] = ds1[2*is];
623 		dd1[id] = ds1[2*is+1];
624 	}
625 }
626 
627 
yuv444p_to_rgb32(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)628 static void yuv444p_to_rgb32(unsigned xoffs, unsigned width, double rw,
629 			     unsigned yd, unsigned ys, unsigned ys2,
630 			     uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
631 			     unsigned lsd,
632 			     const uint8_t *ds0, const uint8_t *ds1,
633 			     const uint8_t *ds2, unsigned lss)
634 {
635 	unsigned x, xd, xs;
636 	unsigned id;
637 	unsigned is1, is2;
638 
639 	(void)dd1;
640 	(void)dd2;
641 
642 	for (x=0; x<width; x++) {
643 
644 		xd = (x + xoffs) * 4;
645 
646 		xs = (unsigned)(x * rw);
647 
648 		id = xd + yd*lsd;
649 
650 		is1 = xs + ys *lss;
651 		is2 = xs + ys2*lss;
652 
653 		_yuv2rgb(&dd0[id],       ds0[is1], ds1[is1], ds2[is1]);
654 		_yuv2rgb(&dd0[id + lsd], ds0[is2], ds1[is2], ds2[is2]);
655 	}
656 }
657 
658 
nv12_to_rgb32(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)659 static void nv12_to_rgb32(unsigned xoffs, unsigned width, double rw,
660                            unsigned yd, unsigned ys, unsigned ys2,
661                            uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
662                            unsigned lsd,
663                            const uint8_t *ds0, const uint8_t *ds1,
664                            const uint8_t *ds2, unsigned lss
665                            )
666 {
667        unsigned x, xd, xs, xs2;
668        unsigned id, is;
669 
670        (void)ds2;
671        (void)dd1;
672        (void)dd2;
673 
674        for (x=0; x<width; x+=2) {
675                int ruv, guv, buv;
676                uint8_t u, v;
677 
678                xd  = (x + xoffs) * 4;
679 
680                xs  = (unsigned)(x * rw);
681                xs2 = (unsigned)((x+1) * rw);
682 
683                id = (xd + yd*lsd);
684                is = xs/2 + ys*lss/4;
685 
686                u = ds1[2*is];
687                v = ds1[2*is+1];
688                ruv = CRV[v];
689                guv = CGV[v] + CGU[u];
690                buv = CBU[u];
691 
692                yuv2rgb(&dd0[id],         ds0[xs  + ys*lss],  ruv, guv, buv);
693                yuv2rgb(&dd0[id+4],       ds0[xs2 + ys*lss],  ruv, guv, buv);
694                yuv2rgb(&dd0[id   + lsd], ds0[xs  + ys2*lss], ruv, guv, buv);
695                yuv2rgb(&dd0[id+4 + lsd], ds0[xs2 + ys2*lss], ruv, guv, buv);
696        }
697 }
698 
699 
nv21_to_rgb32(unsigned xoffs,unsigned width,double rw,unsigned yd,unsigned ys,unsigned ys2,uint8_t * dd0,uint8_t * dd1,uint8_t * dd2,unsigned lsd,const uint8_t * ds0,const uint8_t * ds1,const uint8_t * ds2,unsigned lss)700 static void nv21_to_rgb32(unsigned xoffs, unsigned width, double rw,
701                            unsigned yd, unsigned ys, unsigned ys2,
702                            uint8_t *dd0, uint8_t *dd1, uint8_t *dd2,
703                            unsigned lsd,
704                            const uint8_t *ds0, const uint8_t *ds1,
705                            const uint8_t *ds2, unsigned lss
706                            )
707 {
708        unsigned x, xd, xs, xs2;
709        unsigned id, is;
710 
711        (void)ds2;
712        (void)dd1;
713        (void)dd2;
714 
715        for (x=0; x<width; x+=2) {
716                int ruv, guv, buv;
717                uint8_t u, v;
718 
719                xd  = (x + xoffs) * 4;
720 
721                xs  = (unsigned)(x * rw);
722                xs2 = (unsigned)((x+1) * rw);
723 
724                id = (xd + yd*lsd);
725                is = xs/2 + ys*lss/4;
726 
727                v = ds1[2*is];
728                u = ds1[2*is+1];
729                ruv = CRV[v];
730                guv = CGV[v] + CGU[u];
731                buv = CBU[u];
732 
733                yuv2rgb(&dd0[id],         ds0[xs  + ys*lss],  ruv, guv, buv);
734                yuv2rgb(&dd0[id+4],       ds0[xs2 + ys*lss],  ruv, guv, buv);
735                yuv2rgb(&dd0[id   + lsd], ds0[xs  + ys2*lss], ruv, guv, buv);
736                yuv2rgb(&dd0[id+4 + lsd], ds0[xs2 + ys2*lss], ruv, guv, buv);
737        }
738 }
739 
740 
741 #define MAX_SRC 10
742 #define MAX_DST 10
743 
744 
745 /**
746  * Pixel conversion table:  [src][dst]
747  *
748  * @note Index must be aligned to values in enum vidfmt
749  */
750 static line_h *conv_table[MAX_SRC][MAX_DST] = {
751 
752 /*
753  * Dst:  YUV420P              YUYV422   UYVY422   RGB32
754  */
755 	{yuv420p_to_yuv420p,  NULL,     NULL,     yuv420p_to_rgb32, NULL,
756 	 yuv420p_to_rgb565, yuv420p_to_rgb555, yuv420p_to_nv12},
757 	{yuyv422_to_yuv420p,  NULL,     NULL,     NULL, NULL, NULL, NULL},
758 	{uyvy422_to_yuv420p,  NULL,     NULL,     NULL, NULL, NULL, NULL},
759 	{rgb32_to_yuv420p,    NULL,     NULL,     NULL, NULL, NULL, NULL,
760 	 NULL, NULL, rgb32_to_yuv444p},
761 	{rgb32_to_yuv420p,    NULL,     NULL,     NULL, NULL, NULL, NULL},
762 	{NULL,                NULL,     NULL,     NULL, NULL, NULL, NULL},
763 	{NULL,                NULL,     NULL,     NULL, NULL, NULL, NULL},
764 	{nv12_to_yuv420p,     NULL,     NULL,     nv12_to_rgb32,
765 	 NULL, NULL, NULL},
766 	{nv21_to_yuv420p,     NULL,     NULL,     nv21_to_rgb32,
767 	 NULL, NULL, NULL},
768 	{NULL,                NULL,     NULL,     yuv444p_to_rgb32}
769 };
770 
771 
772 /**
773  * Convert a video frame from one pixel format to another pixel format
774  *
775  * Speed matches swscale: SWS_BILINEAR
776  *
777  * todo: optimize (check out SWS_FAST_BILINEAR)
778  *
779  * @param dst  Destination video frame
780  * @param src  Source video frame
781  * @param r    Drawing area in destination frame, NULL means whole frame
782  */
vidconv(struct vidframe * dst,const struct vidframe * src,struct vidrect * r)783 void vidconv(struct vidframe *dst, const struct vidframe *src,
784 	     struct vidrect *r)
785 {
786 	struct vidrect rdst;
787 	unsigned yd, ys, ys2, lsd, lss, y;
788 	const uint8_t *ds0, *ds1, *ds2;
789 	uint8_t *dd0, *dd1, *dd2;
790 	double rw, rh;
791 	line_h *lineh = NULL;
792 
793 	if (!vidframe_isvalid(dst) || !vidframe_isvalid(src))
794 		return;
795 
796 	if (src->fmt < MAX_SRC && dst->fmt < MAX_DST) {
797 
798 		/* Lookup conversion function */
799 		lineh = conv_table[src->fmt][dst->fmt];
800 	}
801 	if (!lineh) {
802 		(void)re_printf("vidconv: no pixel converter found for"
803 				" %s -> %s\n", vidfmt_name(src->fmt),
804 				vidfmt_name(dst->fmt));
805 		return;
806 	}
807 
808 	if (r) {
809 		r->x &= ~1;
810 		r->y &= ~1;
811 		r->w &= ~1;
812 		r->h &= ~1;
813 
814 		if ((r->x + r->w) > dst->size.w ||
815 		    (r->y + r->h) > dst->size.h) {
816 			(void)re_printf("vidconv: out of bounds (%u x %u)\n",
817 					dst->size.w, dst->size.h);
818 			return;
819 		}
820 	}
821 	else {
822 		rdst.x = rdst.y = 0;
823 		rdst.w = dst->size.w & ~1;
824 		rdst.h = dst->size.h & ~1;
825 		r = &rdst;
826 	}
827 
828 	rw = (double)src->size.w / (double)r->w;
829 	rh = (double)src->size.h / (double)r->h;
830 
831 	lsd = dst->linesize[0];
832 	lss = src->linesize[0];
833 
834 	dd0 = dst->data[0];
835 	dd1 = dst->data[1];
836 	dd2 = dst->data[2];
837 
838 	ds0 = src->data[0];
839 	ds1 = src->data[1];
840 	ds2 = src->data[2];
841 
842 	for (y=0; y<r->h; y+=2) {
843 
844 		yd  = y + r->y;
845 
846 		ys  = (unsigned)(y * rh);
847 		ys2 = (unsigned)((y+1) * rh);
848 
849 		lineh(r->x, r->w, rw, yd, ys, ys2,
850 		      dd0, dd1, dd2, lsd,
851 		      ds0, ds1, ds2, lss);
852 	}
853 }
854 
855 
856 /**
857  * Same as vidconv(), but maintain source aspect ratio within bounds of r
858  *
859  * @param dst  Destination video frame
860  * @param src  Source video frame
861  * @param r    Drawing area in destination frame
862  */
vidconv_aspect(struct vidframe * dst,const struct vidframe * src,struct vidrect * r)863 void vidconv_aspect(struct vidframe *dst, const struct vidframe *src,
864 		    struct vidrect *r)
865 {
866 	struct vidsz asz;
867 	double ar;
868 
869 	ar = (double)src->size.w / (double)src->size.h;
870 
871 	asz.w = r->w;
872 	asz.h = r->h;
873 
874 	r->w = (unsigned)min((double)asz.w, (double)asz.h * ar);
875 	r->h = (unsigned)min((double)asz.h, (double)asz.w / ar);
876 	r->x = r->x + (asz.w - r->w) / 2;
877 	r->y = r->y + (asz.h - r->h) / 2;
878 
879 	vidconv(dst, src, r);
880 }
881