typefinding: detect stand-alone SSA/ASS subtitle files
[platform/upstream/gstreamer.git] / gst / videoscale / vs_4tap.c
1 /*
2  * Image Scaling Functions (4 tap)
3  * Copyright (c) 2005 David A. Schleef <ds@schleef.org>
4  * Copyright (c) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "vs_image.h"
30 #include "vs_scanline.h"
31
32 #include "vs_4tap.h"
33
34 #include <gst/math-compat.h>
35
36 #define SHIFT 10
37
38 static int16_t vs_4tap_taps[256][4];
39
40
41 static void vs_scanline_resample_4tap_Y (uint8_t * dest, uint8_t * src,
42     int n, int src_width, int *xacc, int increment);
43 static void vs_scanline_merge_4tap_Y (uint8_t * dest, uint8_t * src1,
44     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
45
46 static void vs_scanline_resample_4tap_RGBA (uint8_t * dest, uint8_t * src,
47     int n, int src_width, int *xacc, int increment);
48 static void vs_scanline_merge_4tap_RGBA (uint8_t * dest, uint8_t * src1,
49     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
50
51 static void vs_scanline_resample_4tap_RGB (uint8_t * dest, uint8_t * src,
52     int n, int src_width, int *xacc, int increment);
53 static void vs_scanline_merge_4tap_RGB (uint8_t * dest, uint8_t * src1,
54     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
55
56 static void vs_scanline_resample_4tap_YUYV (uint8_t * dest, uint8_t * src,
57     int n, int src_width, int *xacc, int increment);
58 static void vs_scanline_merge_4tap_YUYV (uint8_t * dest, uint8_t * src1,
59     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
60
61 static void vs_scanline_resample_4tap_UYVY (uint8_t * dest, uint8_t * src,
62     int n, int src_width, int *xacc, int increment);
63 static void vs_scanline_merge_4tap_UYVY (uint8_t * dest, uint8_t * src1,
64     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
65
66 static void vs_scanline_resample_4tap_RGB565 (uint8_t * dest, uint8_t * src,
67     int n, int src_width, int *xacc, int increment);
68 static void vs_scanline_merge_4tap_RGB565 (uint8_t * dest, uint8_t * src1,
69     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
70
71 static void vs_scanline_resample_4tap_RGB555 (uint8_t * dest, uint8_t * src,
72     int n, int src_width, int *xacc, int increment);
73 static void vs_scanline_merge_4tap_RGB555 (uint8_t * dest, uint8_t * src1,
74     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
75
76 static void vs_scanline_resample_4tap_Y16 (uint8_t * dest, uint8_t * src,
77     int n, int src_width, int *xacc, int increment);
78 static void vs_scanline_merge_4tap_Y16 (uint8_t * dest, uint8_t * src1,
79     uint8_t * src2, uint8_t * src3, uint8_t * src4, int n, int acc);
80
81 static void vs_scanline_resample_4tap_AYUV64 (uint16_t * dest, uint16_t * src,
82     int n, int src_width, int *xacc, int increment);
83 static void vs_scanline_merge_4tap_AYUV64 (uint16_t * dest, uint16_t * src1,
84     uint16_t * src2, uint16_t * src3, uint16_t * src4, int n, int acc);
85
86 static double
87 vs_4tap_func (double x)
88 {
89 #if 0
90   if (x < -1)
91     return 0;
92   if (x > 1)
93     return 0;
94   if (x < 0)
95     return 1 + x;
96   return 1 - x;
97 #endif
98 #if 0
99   if (x == 0)
100     return 1;
101   return sin (G_PI * x) / (G_PI * x) * (1 - 0.25 * x * x);
102 #endif
103 #if 1
104   if (x == 0)
105     return 1;
106   return sin (G_PI * x) / (G_PI * x);
107 #endif
108 }
109
110 void
111 vs_4tap_init (void)
112 {
113   int i;
114   double a, b, c, d;
115   double sum;
116
117   for (i = 0; i < 256; i++) {
118     a = vs_4tap_func (-1 - i / 256.0);
119     b = vs_4tap_func (0 - i / 256.0);
120     c = vs_4tap_func (1 - i / 256.0);
121     d = vs_4tap_func (2 - i / 256.0);
122     sum = a + b + c + d;
123
124     vs_4tap_taps[i][0] = rint ((1 << SHIFT) * (a / sum));
125     vs_4tap_taps[i][1] = rint ((1 << SHIFT) * (b / sum));
126     vs_4tap_taps[i][2] = rint ((1 << SHIFT) * (c / sum));
127     vs_4tap_taps[i][3] = rint ((1 << SHIFT) * (d / sum));
128   }
129 }
130
131
132 void
133 vs_scanline_resample_4tap_Y (uint8_t * dest, uint8_t * src,
134     int n, int src_width, int *xacc, int increment)
135 {
136   int i;
137   int j;
138   int acc;
139   int x;
140   int y;
141
142   acc = *xacc;
143   for (i = 0; i < n; i++) {
144     j = acc >> 16;
145     x = (acc & 0xff00) >> 8;
146     if (j - 1 >= 0 && j + 2 < src_width) {
147       y = vs_4tap_taps[x][0] * src[MAX (j - 1, 0)];
148       y += vs_4tap_taps[x][1] * src[j];
149       y += vs_4tap_taps[x][2] * src[j + 1];
150       y += vs_4tap_taps[x][3] * src[j + 2];
151     } else {
152       y = vs_4tap_taps[x][0] * src[CLAMP (j - 1, 0, src_width - 1)];
153       y += vs_4tap_taps[x][1] * src[CLAMP (j, 0, src_width - 1)];
154       y += vs_4tap_taps[x][2] * src[CLAMP (j + 1, 0, src_width - 1)];
155       y += vs_4tap_taps[x][3] * src[CLAMP (j + 2, 0, src_width - 1)];
156     }
157     y += (1 << (SHIFT - 1));
158     dest[i] = CLAMP (y >> SHIFT, 0, 255);
159     acc += increment;
160   }
161   *xacc = acc;
162 }
163
164 void
165 vs_scanline_merge_4tap_Y (uint8_t * dest, uint8_t * src1, uint8_t * src2,
166     uint8_t * src3, uint8_t * src4, int n, int acc)
167 {
168   int i;
169   int y;
170   int a, b, c, d;
171
172   acc = (acc >> 8) & 0xff;
173   a = vs_4tap_taps[acc][0];
174   b = vs_4tap_taps[acc][1];
175   c = vs_4tap_taps[acc][2];
176   d = vs_4tap_taps[acc][3];
177   for (i = 0; i < n; i++) {
178     y = a * src1[i];
179     y += b * src2[i];
180     y += c * src3[i];
181     y += d * src4[i];
182     y += (1 << (SHIFT - 1));
183     dest[i] = CLAMP (y >> SHIFT, 0, 255);
184   }
185 }
186
187
188 void
189 vs_image_scale_4tap_Y (const VSImage * dest, const VSImage * src,
190     uint8_t * tmpbuf)
191 {
192   int yacc;
193   int y_increment;
194   int x_increment;
195   int i;
196   int j;
197   int xacc;
198   int k;
199
200   if (dest->height == 1)
201     y_increment = 0;
202   else
203     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
204
205   if (dest->width == 1)
206     x_increment = 0;
207   else
208     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
209
210   k = 0;
211   for (i = 0; i < 4; i++) {
212     xacc = 0;
213     vs_scanline_resample_4tap_Y (tmpbuf + i * dest->width,
214         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
215         src->width, &xacc, x_increment);
216   }
217
218   yacc = 0;
219   for (i = 0; i < dest->height; i++) {
220     uint8_t *t0, *t1, *t2, *t3;
221
222     j = yacc >> 16;
223
224     while (j > k) {
225       k++;
226       if (k + 3 < src->height) {
227         xacc = 0;
228         vs_scanline_resample_4tap_Y (tmpbuf + ((k + 3) & 3) * dest->width,
229             src->pixels + (k + 3) * src->stride,
230             dest->width, src->width, &xacc, x_increment);
231       }
232     }
233
234     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->width;
235     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->width;
236     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->width;
237     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->width;
238     vs_scanline_merge_4tap_Y (dest->pixels + i * dest->stride,
239         t0, t1, t2, t3, dest->width, yacc & 0xffff);
240
241     yacc += y_increment;
242   }
243 }
244
245 void
246 vs_scanline_resample_4tap_Y16 (uint8_t * dest, uint8_t * src,
247     int n, int src_width, int *xacc, int increment)
248 {
249   int i;
250   int j;
251   int acc;
252   int x;
253   int y;
254   uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
255
256   acc = *xacc;
257   for (i = 0; i < n; i++) {
258     j = acc >> 16;
259     x = (acc & 0xff00) >> 8;
260     if (j - 1 >= 0 && j + 2 < src_width) {
261       y = vs_4tap_taps[x][0] * s[MAX (j - 1, 0)];
262       y += vs_4tap_taps[x][1] * s[j];
263       y += vs_4tap_taps[x][2] * s[j + 1];
264       y += vs_4tap_taps[x][3] * s[j + 2];
265     } else {
266       y = vs_4tap_taps[x][0] * s[CLAMP (j - 1, 0, src_width - 1)];
267       y += vs_4tap_taps[x][1] * s[CLAMP (j, 0, src_width - 1)];
268       y += vs_4tap_taps[x][2] * s[CLAMP (j + 1, 0, src_width - 1)];
269       y += vs_4tap_taps[x][3] * s[CLAMP (j + 2, 0, src_width - 1)];
270     }
271     y += (1 << (SHIFT - 1));
272     d[i] = CLAMP (y >> SHIFT, 0, 65535);
273     acc += increment;
274   }
275   *xacc = acc;
276 }
277
278 void
279 vs_scanline_merge_4tap_Y16 (uint8_t * dest, uint8_t * src1, uint8_t * src2,
280     uint8_t * src3, uint8_t * src4, int n, int acc)
281 {
282   int i;
283   int y;
284   int a, b, c, d;
285   uint16_t *de = (uint16_t *) dest, *s1 = (uint16_t *) src1;
286   uint16_t *s2 = (uint16_t *) src2, *s3 = (uint16_t *) src3;
287   uint16_t *s4 = (uint16_t *) src4;
288
289   acc = (acc >> 8) & 0xff;
290   a = vs_4tap_taps[acc][0];
291   b = vs_4tap_taps[acc][1];
292   c = vs_4tap_taps[acc][2];
293   d = vs_4tap_taps[acc][3];
294   for (i = 0; i < n; i++) {
295     y = a * s1[i];
296     y += b * s2[i];
297     y += c * s3[i];
298     y += d * s4[i];
299     y += (1 << (SHIFT - 1));
300     de[i] = CLAMP (y >> SHIFT, 0, 65535);
301   }
302 }
303
304
305 void
306 vs_image_scale_4tap_Y16 (const VSImage * dest, const VSImage * src,
307     uint8_t * tmpbuf)
308 {
309   int yacc;
310   int y_increment;
311   int x_increment;
312   int i;
313   int j;
314   int xacc;
315   int k;
316
317   if (dest->height == 1)
318     y_increment = 0;
319   else
320     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
321
322   if (dest->width == 1)
323     x_increment = 0;
324   else
325     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
326
327   k = 0;
328   for (i = 0; i < 4; i++) {
329     xacc = 0;
330     vs_scanline_resample_4tap_Y16 (tmpbuf + i * dest->stride,
331         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
332         src->width, &xacc, x_increment);
333   }
334
335   yacc = 0;
336   for (i = 0; i < dest->height; i++) {
337     uint8_t *t0, *t1, *t2, *t3;
338
339     j = yacc >> 16;
340
341     while (j > k) {
342       k++;
343       if (k + 3 < src->height) {
344         xacc = 0;
345         vs_scanline_resample_4tap_Y16 (tmpbuf + ((k + 3) & 3) * dest->stride,
346             src->pixels + (k + 3) * src->stride,
347             dest->width, src->width, &xacc, x_increment);
348       }
349     }
350
351     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
352     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
353     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
354     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
355     vs_scanline_merge_4tap_Y16 (dest->pixels + i * dest->stride,
356         t0, t1, t2, t3, dest->width, yacc & 0xffff);
357
358     yacc += y_increment;
359   }
360 }
361
362 void
363 vs_scanline_resample_4tap_RGBA (uint8_t * dest, uint8_t * src,
364     int n, int src_width, int *xacc, int increment)
365 {
366   int i;
367   int j;
368   int acc;
369   int x;
370   int y;
371   int off;
372
373   acc = *xacc;
374   for (i = 0; i < n; i++) {
375     j = acc >> 16;
376     x = (acc & 0xffff) >> 8;
377
378     for (off = 0; off < 4; off++) {
379       if (j - 1 >= 0 && j + 2 < src_width) {
380         y = vs_4tap_taps[x][0] * src[MAX ((j - 1) * 4 + off, 0)];
381         y += vs_4tap_taps[x][1] * src[j * 4 + off];
382         y += vs_4tap_taps[x][2] * src[(j + 1) * 4 + off];
383         y += vs_4tap_taps[x][3] * src[(j + 2) * 4 + off];
384       } else {
385         y = vs_4tap_taps[x][0] *
386             src[CLAMP ((j - 1), 0, src_width - 1) * 4 + off];
387         y += vs_4tap_taps[x][1] *
388             src[CLAMP ((j + 0), 0, src_width - 1) * 4 + off];
389         y += vs_4tap_taps[x][2] *
390             src[CLAMP ((j + 1), 0, src_width - 1) * 4 + off];
391         y += vs_4tap_taps[x][3] *
392             src[CLAMP ((j + 2), 0, src_width - 1) * 4 + off];
393       }
394       y += (1 << (SHIFT - 1));
395       dest[i * 4 + off] = CLAMP (y >> SHIFT, 0, 255);
396     }
397     acc += increment;
398   }
399   *xacc = acc;
400 }
401
402 void
403 vs_scanline_merge_4tap_RGBA (uint8_t * dest, uint8_t * src1, uint8_t * src2,
404     uint8_t * src3, uint8_t * src4, int n, int acc)
405 {
406   int i;
407   int y;
408   int off;
409   int a, b, c, d;
410
411   acc = (acc >> 8) & 0xff;
412   a = vs_4tap_taps[acc][0];
413   b = vs_4tap_taps[acc][1];
414   c = vs_4tap_taps[acc][2];
415   d = vs_4tap_taps[acc][3];
416   for (i = 0; i < n; i++) {
417     for (off = 0; off < 4; off++) {
418       y = a * src1[i * 4 + off];
419       y += b * src2[i * 4 + off];
420       y += c * src3[i * 4 + off];
421       y += d * src4[i * 4 + off];
422       y += (1 << (SHIFT - 1));
423       dest[i * 4 + off] = CLAMP (y >> SHIFT, 0, 255);
424     }
425   }
426 }
427
428 void
429 vs_image_scale_4tap_RGBA (const VSImage * dest, const VSImage * src,
430     uint8_t * tmpbuf)
431 {
432   int yacc;
433   int y_increment;
434   int x_increment;
435   int i;
436   int j;
437   int xacc;
438   int k;
439
440   if (dest->height == 1)
441     y_increment = 0;
442   else
443     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
444
445   if (dest->width == 1)
446     x_increment = 0;
447   else
448     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
449
450   k = 0;
451   for (i = 0; i < 4; i++) {
452     xacc = 0;
453     vs_scanline_resample_4tap_RGBA (tmpbuf + i * dest->stride,
454         src->pixels + CLAMP (i, 0, src->height) * src->stride,
455         dest->width, src->width, &xacc, x_increment);
456   }
457
458   yacc = 0;
459   for (i = 0; i < dest->height; i++) {
460     uint8_t *t0, *t1, *t2, *t3;
461
462     j = yacc >> 16;
463
464     while (j > k) {
465       k++;
466       if (k + 3 < src->height) {
467         xacc = 0;
468         vs_scanline_resample_4tap_RGBA (tmpbuf + ((k + 3) & 3) * dest->stride,
469             src->pixels + (k + 3) * src->stride,
470             dest->width, src->width, &xacc, x_increment);
471       }
472     }
473
474     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
475     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
476     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
477     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
478     vs_scanline_merge_4tap_RGBA (dest->pixels + i * dest->stride,
479         t0, t1, t2, t3, dest->width, yacc & 0xffff);
480
481     yacc += y_increment;
482   }
483 }
484
485 void
486 vs_scanline_resample_4tap_RGB (uint8_t * dest, uint8_t * src,
487     int n, int src_width, int *xacc, int increment)
488 {
489   int i;
490   int j;
491   int acc;
492   int x;
493   int y;
494   int off;
495
496   acc = *xacc;
497   for (i = 0; i < n; i++) {
498     j = acc >> 16;
499     x = (acc & 0xffff) >> 8;
500
501     for (off = 0; off < 3; off++) {
502       if (j - 1 >= 0 && j + 2 < src_width) {
503         y = vs_4tap_taps[x][0] * src[MAX ((j - 1) * 3 + off, 0)];
504         y += vs_4tap_taps[x][1] * src[j * 3 + off];
505         y += vs_4tap_taps[x][2] * src[(j + 1) * 3 + off];
506         y += vs_4tap_taps[x][3] * src[(j + 2) * 3 + off];
507       } else {
508         y = vs_4tap_taps[x][0] * src[CLAMP ((j - 1) * 3 + off, 0,
509                 3 * (src_width - 1) + off)];
510         y += vs_4tap_taps[x][1] * src[CLAMP (j * 3 + off, 0,
511                 3 * (src_width - 1) + off)];
512         y += vs_4tap_taps[x][2] * src[CLAMP ((j + 1) * 3 + off, 0,
513                 3 * (src_width - 1) + off)];
514         y += vs_4tap_taps[x][3] * src[CLAMP ((j + 2) * 3 + off, 0,
515                 3 * (src_width - 1) + off)];
516       }
517       y += (1 << (SHIFT - 1));
518       dest[i * 3 + off] = CLAMP (y >> SHIFT, 0, 255);
519     }
520     acc += increment;
521   }
522   *xacc = acc;
523 }
524
525 void
526 vs_scanline_merge_4tap_RGB (uint8_t * dest, uint8_t * src1, uint8_t * src2,
527     uint8_t * src3, uint8_t * src4, int n, int acc)
528 {
529   int i;
530   int y;
531   int off;
532   int a, b, c, d;
533
534   acc = (acc >> 8) & 0xff;
535   a = vs_4tap_taps[acc][0];
536   b = vs_4tap_taps[acc][1];
537   c = vs_4tap_taps[acc][2];
538   d = vs_4tap_taps[acc][3];
539   for (i = 0; i < n; i++) {
540     for (off = 0; off < 3; off++) {
541       y = a * src1[i * 3 + off];
542       y += b * src2[i * 3 + off];
543       y += c * src3[i * 3 + off];
544       y += d * src4[i * 3 + off];
545       y += (1 << (SHIFT - 1));
546       dest[i * 3 + off] = CLAMP (y >> SHIFT, 0, 255);
547     }
548   }
549 }
550
551 void
552 vs_image_scale_4tap_RGB (const VSImage * dest, const VSImage * src,
553     uint8_t * tmpbuf)
554 {
555   int yacc;
556   int y_increment;
557   int x_increment;
558   int i;
559   int j;
560   int xacc;
561   int k;
562
563   if (dest->height == 1)
564     y_increment = 0;
565   else
566     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
567
568   if (dest->width == 1)
569     x_increment = 0;
570   else
571     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
572
573   k = 0;
574   for (i = 0; i < 4; i++) {
575     xacc = 0;
576     vs_scanline_resample_4tap_RGB (tmpbuf + i * dest->stride,
577         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
578         src->width, &xacc, x_increment);
579   }
580
581   yacc = 0;
582   for (i = 0; i < dest->height; i++) {
583     uint8_t *t0, *t1, *t2, *t3;
584
585     j = yacc >> 16;
586
587     while (j > k) {
588       k++;
589       if (k + 3 < src->height) {
590         xacc = 0;
591         vs_scanline_resample_4tap_RGB (tmpbuf + ((k + 3) & 3) * dest->stride,
592             src->pixels + (k + 3) * src->stride,
593             dest->width, src->width, &xacc, x_increment);
594       }
595     }
596
597     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
598     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
599     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
600     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
601     vs_scanline_merge_4tap_RGB (dest->pixels + i * dest->stride,
602         t0, t1, t2, t3, dest->width, yacc & 0xffff);
603
604     yacc += y_increment;
605   }
606 }
607
608 void
609 vs_scanline_resample_4tap_YUYV (uint8_t * dest, uint8_t * src,
610     int n, int src_width, int *xacc, int increment)
611 {
612   int i;
613   int j;
614   int acc;
615   int x;
616   int y;
617   int quads = (n + 1) / 2;
618   int last_y = 2 * (src_width - 1);
619   int last_u =
620       MAX ((2 * (src_width - 1) % 4 ==
621           0) ? 2 * (src_width - 1) + 1 : 2 * (src_width - 1) - 1, 1);
622   int last_v =
623       MAX ((2 * (src_width - 1) % 4 ==
624           2) ? 2 * (src_width - 1) + 1 : 2 * (src_width - 1) - 1, 1);
625
626   acc = *xacc;
627   for (i = 0; i < quads; i++) {
628     j = acc >> 16;
629     x = (acc & 0xffff) >> 8;
630
631     if (j - 1 >= 0 && j + 2 < src_width) {
632       y = vs_4tap_taps[x][0] * src[MAX (j * 2 + 0 - 2, 0)];
633       y += vs_4tap_taps[x][1] * src[j * 2 + 0];
634       y += vs_4tap_taps[x][2] * src[j * 2 + 0 + 2];
635       y += vs_4tap_taps[x][3] * src[j * 2 + 0 + 4];
636     } else {
637       y = vs_4tap_taps[x][0] * src[CLAMP (j * 2 + 0 - 2, 0, last_y)];
638       y += vs_4tap_taps[x][1] * src[CLAMP (j * 2 + 0, 0, last_y)];
639       y += vs_4tap_taps[x][2] * src[CLAMP (j * 2 + 0 + 2, 0, last_y)];
640       y += vs_4tap_taps[x][3] * src[CLAMP (j * 2 + 0 + 4, 0, last_y)];
641     }
642     y += (1 << (SHIFT - 1));
643     dest[i * 4 + 0] = CLAMP (y >> SHIFT, 0, 255);
644
645     j = acc >> 17;
646     x = (acc & 0x1ffff) >> 9;
647
648     if (2 * j - 1 >= 0 && 2 * j + 4 < src_width) {
649       y = vs_4tap_taps[x][0] * src[MAX (j * 4 + 1 - 4, 1)];
650       y += vs_4tap_taps[x][1] * src[j * 4 + 1];
651       y += vs_4tap_taps[x][2] * src[j * 4 + 1 + 4];
652       y += vs_4tap_taps[x][3] * src[j * 4 + 1 + 8];
653     } else {
654       y = vs_4tap_taps[x][0] * src[CLAMP (j * 4 + 1 - 4, 1, last_u)];
655       y += vs_4tap_taps[x][1] * src[CLAMP (j * 4 + 1, 1, last_u)];
656       y += vs_4tap_taps[x][2] * src[CLAMP (j * 4 + 1 + 4, 1, last_u)];
657       y += vs_4tap_taps[x][3] * src[CLAMP (j * 4 + 1 + 8, 1, last_u)];
658     }
659     y += (1 << (SHIFT - 1));
660     dest[i * 4 + 1] = CLAMP (y >> SHIFT, 0, 255);
661
662     if (2 * i + 1 < n) {
663       if (2 * j - 1 >= 0 && 2 * j + 4 < src_width) {
664         y = vs_4tap_taps[x][0] * src[MAX (j * 4 + 3 - 4, 3)];
665         y += vs_4tap_taps[x][1] * src[j * 4 + 3];
666         y += vs_4tap_taps[x][2] * src[j * 4 + 3 + 4];
667         y += vs_4tap_taps[x][3] * src[j * 4 + 3 + 8];
668       } else {
669         y = vs_4tap_taps[x][0] * src[CLAMP (j * 4 + 3 - 4, 3, last_v)];
670         y += vs_4tap_taps[x][1] * src[CLAMP (j * 4 + 3, 3, last_v)];
671         y += vs_4tap_taps[x][2] * src[CLAMP (j * 4 + 3 + 4, 3, last_v)];
672         y += vs_4tap_taps[x][3] * src[CLAMP (j * 4 + 3 + 8, 3, last_v)];
673       }
674       y += (1 << (SHIFT - 1));
675       dest[i * 4 + 3] = CLAMP (y >> SHIFT, 0, 255);
676     }
677
678     acc += increment;
679     j = acc >> 16;
680     x = (acc & 0xffff) >> 8;
681
682     if (2 * i + 1 < n) {
683       if (j - 1 >= 0 && j + 2 < src_width) {
684         y = vs_4tap_taps[x][0] * src[MAX (j * 2 + 0 - 2, 0)];
685         y += vs_4tap_taps[x][1] * src[j * 2 + 0];
686         y += vs_4tap_taps[x][2] * src[j * 2 + 0 + 2];
687         y += vs_4tap_taps[x][3] * src[j * 2 + 0 + 4];
688       } else {
689         y = vs_4tap_taps[x][0] * src[CLAMP (j * 2 + 0 - 2, 0, last_y)];
690         y += vs_4tap_taps[x][1] * src[CLAMP (j * 2 + 0, 0, last_y)];
691         y += vs_4tap_taps[x][2] * src[CLAMP (j * 2 + 0 + 2, 0, last_y)];
692         y += vs_4tap_taps[x][3] * src[CLAMP (j * 2 + 0 + 4, 0, last_y)];
693       }
694       y += (1 << (SHIFT - 1));
695       dest[i * 4 + 2] = CLAMP (y >> SHIFT, 0, 255);
696       acc += increment;
697     }
698   }
699   *xacc = acc;
700 }
701
702 void
703 vs_scanline_merge_4tap_YUYV (uint8_t * dest, uint8_t * src1, uint8_t * src2,
704     uint8_t * src3, uint8_t * src4, int n, int acc)
705 {
706   int i;
707   int y;
708   int a, b, c, d;
709   int quads = (n + 1) / 2;
710
711   acc = (acc >> 8) & 0xff;
712   a = vs_4tap_taps[acc][0];
713   b = vs_4tap_taps[acc][1];
714   c = vs_4tap_taps[acc][2];
715   d = vs_4tap_taps[acc][3];
716   for (i = 0; i < quads; i++) {
717     y = a * src1[i * 4 + 0];
718     y += b * src2[i * 4 + 0];
719     y += c * src3[i * 4 + 0];
720     y += d * src4[i * 4 + 0];
721     y += (1 << (SHIFT - 1));
722     dest[i * 4 + 0] = CLAMP (y >> SHIFT, 0, 255);
723
724     y = a * src1[i * 4 + 1];
725     y += b * src2[i * 4 + 1];
726     y += c * src3[i * 4 + 1];
727     y += d * src4[i * 4 + 1];
728     y += (1 << (SHIFT - 1));
729     dest[i * 4 + 1] = CLAMP (y >> SHIFT, 0, 255);
730
731     if (2 * i + 1 < n) {
732       y = a * src1[i * 4 + 2];
733       y += b * src2[i * 4 + 2];
734       y += c * src3[i * 4 + 2];
735       y += d * src4[i * 4 + 2];
736       y += (1 << (SHIFT - 1));
737       dest[i * 4 + 2] = CLAMP (y >> SHIFT, 0, 255);
738
739       y = a * src1[i * 4 + 3];
740       y += b * src2[i * 4 + 3];
741       y += c * src3[i * 4 + 3];
742       y += d * src4[i * 4 + 3];
743       y += (1 << (SHIFT - 1));
744       dest[i * 4 + 3] = CLAMP (y >> SHIFT, 0, 255);
745     }
746   }
747 }
748
749 void
750 vs_image_scale_4tap_YUYV (const VSImage * dest, const VSImage * src,
751     uint8_t * tmpbuf)
752 {
753   int yacc;
754   int y_increment;
755   int x_increment;
756   int i;
757   int j;
758   int xacc;
759   int k;
760
761   if (dest->height == 1)
762     y_increment = 0;
763   else
764     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
765
766   if (dest->width == 1)
767     x_increment = 0;
768   else
769     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
770
771   k = 0;
772   for (i = 0; i < 4; i++) {
773     xacc = 0;
774     vs_scanline_resample_4tap_YUYV (tmpbuf + i * dest->stride,
775         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
776         src->width, &xacc, x_increment);
777   }
778
779   yacc = 0;
780   for (i = 0; i < dest->height; i++) {
781     uint8_t *t0, *t1, *t2, *t3;
782
783     j = yacc >> 16;
784
785     while (j > k) {
786       k++;
787       if (k + 3 < src->height) {
788         xacc = 0;
789         vs_scanline_resample_4tap_YUYV (tmpbuf + ((k + 3) & 3) * dest->stride,
790             src->pixels + (k + 3) * src->stride,
791             dest->width, src->width, &xacc, x_increment);
792       }
793     }
794
795     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
796     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
797     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
798     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
799     vs_scanline_merge_4tap_YUYV (dest->pixels + i * dest->stride,
800         t0, t1, t2, t3, dest->width, yacc & 0xffff);
801
802     yacc += y_increment;
803   }
804 }
805
806 void
807 vs_scanline_resample_4tap_UYVY (uint8_t * dest, uint8_t * src,
808     int n, int src_width, int *xacc, int increment)
809 {
810   int i;
811   int j;
812   int acc;
813   int x;
814   int y;
815   int quads = (n + 1) / 2;
816   int last_y = 2 * (src_width - 1) + 1;
817   int last_u =
818       MAX ((2 * (src_width - 1) % 4 ==
819           0) ? 2 * (src_width - 1) : 2 * (src_width - 1) - 2, 0);
820   int last_v =
821       MAX ((2 * (src_width - 1) % 4 ==
822           2) ? 2 * (src_width - 1) : 2 * (src_width - 1) - 2, 0);
823
824   acc = *xacc;
825   for (i = 0; i < quads; i++) {
826     j = acc >> 16;
827     x = (acc & 0xffff) >> 8;
828
829     if (j - 1 >= 0 && j + 2 < src_width) {
830       y = vs_4tap_taps[x][0] * src[MAX (j * 2 + 1 - 2, 1)];
831       y += vs_4tap_taps[x][1] * src[j * 2 + 1];
832       y += vs_4tap_taps[x][2] * src[j * 2 + 1 + 2];
833       y += vs_4tap_taps[x][3] * src[j * 2 + 1 + 4];
834     } else {
835       y = vs_4tap_taps[x][0] * src[CLAMP (j * 2 + 1 - 2, 1, last_y)];
836       y += vs_4tap_taps[x][1] * src[CLAMP (j * 2 + 1, 1, last_y)];
837       y += vs_4tap_taps[x][2] * src[CLAMP (j * 2 + 1 + 2, 1, last_y)];
838       y += vs_4tap_taps[x][3] * src[CLAMP (j * 2 + 1 + 4, 1, last_y)];
839     }
840     y += (1 << (SHIFT - 1));
841     dest[i * 4 + 1] = CLAMP (y >> SHIFT, 0, 255);
842
843     j = acc >> 17;
844     x = (acc & 0x1ffff) >> 9;
845
846     if (2 * j - 2 >= 0 && 2 * j + 4 < src_width) {
847       y = vs_4tap_taps[x][0] * src[MAX (j * 4 + 0 - 4, 0)];
848       y += vs_4tap_taps[x][1] * src[j * 4 + 0];
849       y += vs_4tap_taps[x][2] * src[j * 4 + 0 + 4];
850       y += vs_4tap_taps[x][3] * src[j * 4 + 0 + 8];
851     } else {
852       y = vs_4tap_taps[x][0] * src[CLAMP (j * 4 + 0 - 4, 0, last_u)];
853       y += vs_4tap_taps[x][1] * src[CLAMP (j * 4 + 0, 0, last_u)];
854       y += vs_4tap_taps[x][2] * src[CLAMP (j * 4 + 0 + 4, 0, last_u)];
855       y += vs_4tap_taps[x][3] * src[CLAMP (j * 4 + 0 + 8, 0, last_u)];
856     }
857     y += (1 << (SHIFT - 1));
858     dest[i * 4 + 0] = CLAMP (y >> SHIFT, 0, 255);
859
860     if (2 * i + 1 < n) {
861       if (2 * j - 1 >= 0 && 2 * j + 4 < src_width) {
862         y = vs_4tap_taps[x][0] * src[MAX (j * 4 + 2 - 4, 2)];
863         y += vs_4tap_taps[x][1] * src[j * 4 + 2];
864         y += vs_4tap_taps[x][2] * src[j * 4 + 2 + 4];
865         y += vs_4tap_taps[x][3] * src[j * 4 + 2 + 8];
866       } else {
867         y = vs_4tap_taps[x][0] * src[CLAMP (j * 4 + 2 - 4, 2, last_v)];
868         y += vs_4tap_taps[x][1] * src[CLAMP (j * 4 + 2, 2, last_v)];
869         y += vs_4tap_taps[x][2] * src[CLAMP (j * 4 + 2 + 4, 2, last_v)];
870         y += vs_4tap_taps[x][3] * src[CLAMP (j * 4 + 2 + 8, 2, last_v)];
871       }
872       y += (1 << (SHIFT - 1));
873       dest[i * 4 + 2] = CLAMP (y >> SHIFT, 0, 255);
874     }
875
876     acc += increment;
877     j = acc >> 16;
878     x = (acc & 0xffff) >> 8;
879
880     if (2 * i + 1 < n) {
881       if (j - 1 >= 0 && j + 2 < src_width) {
882         y = vs_4tap_taps[x][0] * src[MAX (j * 2 + 1 - 2, 0)];
883         y += vs_4tap_taps[x][1] * src[j * 2 + 1];
884         y += vs_4tap_taps[x][2] * src[j * 2 + 1 + 2];
885         y += vs_4tap_taps[x][3] * src[j * 2 + 1 + 4];
886       } else {
887         y = vs_4tap_taps[x][0] * src[CLAMP (j * 2 + 1 - 2, 1, last_y)];
888         y += vs_4tap_taps[x][1] * src[CLAMP (j * 2 + 1, 1, last_y)];
889         y += vs_4tap_taps[x][2] * src[CLAMP (j * 2 + 1 + 2, 1, last_y)];
890         y += vs_4tap_taps[x][3] * src[CLAMP (j * 2 + 1 + 4, 1, last_y)];
891       }
892       y += (1 << (SHIFT - 1));
893       dest[i * 4 + 3] = CLAMP (y >> SHIFT, 0, 255);
894       acc += increment;
895     }
896   }
897   *xacc = acc;
898 }
899
900 void
901 vs_scanline_merge_4tap_UYVY (uint8_t * dest, uint8_t * src1, uint8_t * src2,
902     uint8_t * src3, uint8_t * src4, int n, int acc)
903 {
904   int i;
905   int y;
906   int a, b, c, d;
907   int quads = (n + 1) / 2;
908
909   acc = (acc >> 8) & 0xff;
910   a = vs_4tap_taps[acc][0];
911   b = vs_4tap_taps[acc][1];
912   c = vs_4tap_taps[acc][2];
913   d = vs_4tap_taps[acc][3];
914   for (i = 0; i < quads; i++) {
915     y = a * src1[i * 4 + 0];
916     y += b * src2[i * 4 + 0];
917     y += c * src3[i * 4 + 0];
918     y += d * src4[i * 4 + 0];
919     y += (1 << (SHIFT - 1));
920     dest[i * 4 + 0] = CLAMP (y >> SHIFT, 0, 255);
921
922     y = a * src1[i * 4 + 1];
923     y += b * src2[i * 4 + 1];
924     y += c * src3[i * 4 + 1];
925     y += d * src4[i * 4 + 1];
926     y += (1 << (SHIFT - 1));
927     dest[i * 4 + 1] = CLAMP (y >> SHIFT, 0, 255);
928
929     if (2 * i + 1 < n) {
930       y = a * src1[i * 4 + 2];
931       y += b * src2[i * 4 + 2];
932       y += c * src3[i * 4 + 2];
933       y += d * src4[i * 4 + 2];
934       y += (1 << (SHIFT - 1));
935       dest[i * 4 + 2] = CLAMP (y >> SHIFT, 0, 255);
936
937       y = a * src1[i * 4 + 3];
938       y += b * src2[i * 4 + 3];
939       y += c * src3[i * 4 + 3];
940       y += d * src4[i * 4 + 3];
941       y += (1 << (SHIFT - 1));
942       dest[i * 4 + 3] = CLAMP (y >> SHIFT, 0, 255);
943     }
944   }
945 }
946
947 void
948 vs_image_scale_4tap_UYVY (const VSImage * dest, const VSImage * src,
949     uint8_t * tmpbuf)
950 {
951   int yacc;
952   int y_increment;
953   int x_increment;
954   int i;
955   int j;
956   int xacc;
957   int k;
958
959   if (dest->height == 1)
960     y_increment = 0;
961   else
962     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
963
964   if (dest->width == 1)
965     x_increment = 0;
966   else
967     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
968
969   k = 0;
970   for (i = 0; i < 4; i++) {
971     xacc = 0;
972     vs_scanline_resample_4tap_UYVY (tmpbuf + i * dest->stride,
973         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
974         src->width, &xacc, x_increment);
975   }
976
977   yacc = 0;
978   for (i = 0; i < dest->height; i++) {
979     uint8_t *t0, *t1, *t2, *t3;
980
981     j = yacc >> 16;
982
983     while (j > k) {
984       k++;
985       if (k + 3 < src->height) {
986         xacc = 0;
987         vs_scanline_resample_4tap_UYVY (tmpbuf + ((k + 3) & 3) * dest->stride,
988             src->pixels + (k + 3) * src->stride,
989             dest->width, src->width, &xacc, x_increment);
990       }
991     }
992
993     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
994     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
995     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
996     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
997     vs_scanline_merge_4tap_UYVY (dest->pixels + i * dest->stride,
998         t0, t1, t2, t3, dest->width, yacc & 0xffff);
999
1000     yacc += y_increment;
1001   }
1002 }
1003
1004 /* note that src and dest are uint16_t, and thus endian dependent */
1005
1006 #define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13)
1007 #define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9)
1008 #define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
1009
1010 #define RGB565(r,g,b) \
1011   ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f))
1012
1013 void
1014 vs_scanline_resample_4tap_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
1015     int n, int src_width, int *xacc, int increment)
1016 {
1017   int i;
1018   int j;
1019   int acc;
1020   int x;
1021   int y, y_r, y_b, y_g;
1022   uint16_t *dest = (uint16_t *) dest_u8;
1023   uint16_t *src = (uint16_t *) src_u8;
1024
1025   acc = *xacc;
1026   for (i = 0; i < n; i++) {
1027     j = acc >> 16;
1028     x = acc & 0xffff >> 8;
1029
1030     if (j - 1 >= 0 && j + 2 < src_width) {
1031       y = vs_4tap_taps[x][0] * RGB565_R (src[MAX ((j - 1), 0)]);
1032       y += vs_4tap_taps[x][1] * RGB565_R (src[j]);
1033       y += vs_4tap_taps[x][2] * RGB565_R (src[(j + 1)]);
1034       y += vs_4tap_taps[x][3] * RGB565_R (src[(j + 2)]);
1035     } else {
1036       y = vs_4tap_taps[x][0] * RGB565_R (src[CLAMP ((j - 1), 0,
1037                   src_width - 1)]);
1038       y += vs_4tap_taps[x][1] * RGB565_R (src[CLAMP (j, 0, src_width - 1)]);
1039       y += vs_4tap_taps[x][2] * RGB565_R (src[CLAMP ((j + 1), 0,
1040                   src_width - 1)]);
1041       y += vs_4tap_taps[x][3] * RGB565_R (src[CLAMP ((j + 2), 0,
1042                   src_width - 1)]);
1043     }
1044     y += (1 << (SHIFT - 1));
1045     y_r = CLAMP (y >> SHIFT, 0, 255);
1046
1047     if (j - 1 >= 0 && j + 2 < src_width) {
1048       y = vs_4tap_taps[x][0] * RGB565_G (src[MAX ((j - 1), 0)]);
1049       y += vs_4tap_taps[x][1] * RGB565_G (src[j]);
1050       y += vs_4tap_taps[x][2] * RGB565_G (src[(j + 1)]);
1051       y += vs_4tap_taps[x][3] * RGB565_G (src[(j + 2)]);
1052     } else {
1053       y = vs_4tap_taps[x][0] * RGB565_G (src[CLAMP ((j - 1), 0,
1054                   src_width - 1)]);
1055       y += vs_4tap_taps[x][1] * RGB565_G (src[CLAMP (j, 0, src_width - 1)]);
1056       y += vs_4tap_taps[x][2] * RGB565_G (src[CLAMP ((j + 1), 0,
1057                   src_width - 1)]);
1058       y += vs_4tap_taps[x][3] * RGB565_G (src[CLAMP ((j + 2), 0,
1059                   src_width - 1)]);
1060     }
1061     y += (1 << (SHIFT - 1));
1062     y_g = CLAMP (y >> SHIFT, 0, 255);
1063
1064     if (j - 1 >= 0 && j + 2 < src_width) {
1065       y = vs_4tap_taps[x][0] * RGB565_B (src[MAX ((j - 1), 0)]);
1066       y += vs_4tap_taps[x][1] * RGB565_B (src[j]);
1067       y += vs_4tap_taps[x][2] * RGB565_B (src[(j + 1)]);
1068       y += vs_4tap_taps[x][3] * RGB565_B (src[(j + 2)]);
1069     } else {
1070       y = vs_4tap_taps[x][0] * RGB565_B (src[CLAMP ((j - 1), 0,
1071                   src_width - 1)]);
1072       y += vs_4tap_taps[x][1] * RGB565_B (src[CLAMP (j, 0, src_width - 1)]);
1073       y += vs_4tap_taps[x][2] * RGB565_B (src[CLAMP ((j + 1), 0,
1074                   src_width - 1)]);
1075       y += vs_4tap_taps[x][3] * RGB565_B (src[CLAMP ((j + 2), 0,
1076                   src_width - 1)]);
1077     }
1078     y += (1 << (SHIFT - 1));
1079     y_b = CLAMP (y >> SHIFT, 0, 255);
1080
1081     dest[i] = RGB565 (y_r, y_b, y_g);
1082     acc += increment;
1083   }
1084   *xacc = acc;
1085 }
1086
1087 void
1088 vs_scanline_merge_4tap_RGB565 (uint8_t * dest_u8, uint8_t * src1_u8,
1089     uint8_t * src2_u8, uint8_t * src3_u8, uint8_t * src4_u8, int n, int acc)
1090 {
1091   int i;
1092   int y, y_r, y_b, y_g;
1093   int a, b, c, d;
1094   uint16_t *dest = (uint16_t *) dest_u8;
1095   uint16_t *src1 = (uint16_t *) src1_u8;
1096   uint16_t *src2 = (uint16_t *) src2_u8;
1097   uint16_t *src3 = (uint16_t *) src3_u8;
1098   uint16_t *src4 = (uint16_t *) src4_u8;
1099
1100   acc = (acc >> 8) & 0xff;
1101   a = vs_4tap_taps[acc][0];
1102   b = vs_4tap_taps[acc][1];
1103   c = vs_4tap_taps[acc][2];
1104   d = vs_4tap_taps[acc][3];
1105
1106   for (i = 0; i < n; i++) {
1107     y = a * RGB565_R (src1[i]);
1108     y += b * RGB565_R (src2[i]);
1109     y += c * RGB565_R (src3[i]);
1110     y += d * RGB565_R (src4[i]);
1111     y += (1 << (SHIFT - 1));
1112     y_r = CLAMP (y >> SHIFT, 0, 255);
1113
1114     y = a * RGB565_G (src1[i]);
1115     y += b * RGB565_G (src2[i]);
1116     y += c * RGB565_G (src3[i]);
1117     y += d * RGB565_G (src4[i]);
1118     y += (1 << (SHIFT - 1));
1119     y_g = CLAMP (y >> SHIFT, 0, 255);
1120
1121     y = a * RGB565_B (src1[i]);
1122     y += b * RGB565_B (src2[i]);
1123     y += c * RGB565_B (src3[i]);
1124     y += d * RGB565_B (src4[i]);
1125     y += (1 << (SHIFT - 1));
1126     y_b = CLAMP (y >> SHIFT, 0, 255);
1127
1128     dest[i] = RGB565 (y_r, y_b, y_g);
1129   }
1130 }
1131
1132 void
1133 vs_image_scale_4tap_RGB565 (const VSImage * dest, const VSImage * src,
1134     uint8_t * tmpbuf)
1135 {
1136   int yacc;
1137   int y_increment;
1138   int x_increment;
1139   int i;
1140   int j;
1141   int xacc;
1142   int k;
1143
1144   if (dest->height == 1)
1145     y_increment = 0;
1146   else
1147     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1148
1149   if (dest->width == 1)
1150     x_increment = 0;
1151   else
1152     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1153
1154   k = 0;
1155   for (i = 0; i < 4; i++) {
1156     xacc = 0;
1157     vs_scanline_resample_4tap_RGB565 (tmpbuf + i * dest->stride,
1158         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
1159         src->width, &xacc, x_increment);
1160   }
1161
1162   yacc = 0;
1163   for (i = 0; i < dest->height; i++) {
1164     uint8_t *t0, *t1, *t2, *t3;
1165
1166     j = yacc >> 16;
1167
1168     while (j > k) {
1169       k++;
1170       if (k + 3 < src->height) {
1171         xacc = 0;
1172         vs_scanline_resample_4tap_RGB565 (tmpbuf + ((k + 3) & 3) * dest->stride,
1173             src->pixels + (k + 3) * src->stride,
1174             dest->width, src->width, &xacc, x_increment);
1175       }
1176     }
1177
1178     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
1179     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
1180     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
1181     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
1182     vs_scanline_merge_4tap_RGB565 (dest->pixels + i * dest->stride,
1183         t0, t1, t2, t3, dest->width, yacc & 0xffff);
1184
1185     yacc += y_increment;
1186   }
1187 }
1188
1189 /* note that src and dest are uint16_t, and thus endian dependent */
1190
1191 #define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13)
1192 #define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9)
1193 #define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
1194
1195 #define RGB555(r,g,b) \
1196   ((((r)<<7)&0x7c00) | (((g)<<2)&0x03e0) | (((b)>>3)&0x001f))
1197
1198 void
1199 vs_scanline_resample_4tap_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
1200     int n, int src_width, int *xacc, int increment)
1201 {
1202   int i;
1203   int j;
1204   int acc;
1205   int x;
1206   int y, y_r, y_b, y_g;
1207   uint16_t *dest = (uint16_t *) dest_u8;
1208   uint16_t *src = (uint16_t *) src_u8;
1209
1210   acc = *xacc;
1211   for (i = 0; i < n; i++) {
1212     j = acc >> 16;
1213     x = acc & 0xffff >> 8;
1214
1215     if (j - 1 >= 0 && j + 2 < src_width) {
1216       y = vs_4tap_taps[x][0] * RGB555_R (src[MAX ((j - 1), 0)]);
1217       y += vs_4tap_taps[x][1] * RGB555_R (src[j]);
1218       y += vs_4tap_taps[x][2] * RGB555_R (src[(j + 1)]);
1219       y += vs_4tap_taps[x][3] * RGB555_R (src[(j + 2)]);
1220     } else {
1221       y = vs_4tap_taps[x][0] * RGB555_R (src[CLAMP ((j - 1), 0,
1222                   src_width - 1)]);
1223       y += vs_4tap_taps[x][1] * RGB555_R (src[CLAMP (j, 0, src_width - 1)]);
1224       y += vs_4tap_taps[x][2] * RGB555_R (src[CLAMP ((j + 1), 0,
1225                   src_width - 1)]);
1226       y += vs_4tap_taps[x][3] * RGB555_R (src[CLAMP ((j + 2), 0,
1227                   src_width - 1)]);
1228     }
1229     y += (1 << (SHIFT - 1));
1230     y_r = CLAMP (y >> SHIFT, 0, 255);
1231
1232     if (j - 1 >= 0 && j + 2 < src_width) {
1233       y = vs_4tap_taps[x][0] * RGB555_G (src[MAX ((j - 1), 0)]);
1234       y += vs_4tap_taps[x][1] * RGB555_G (src[j]);
1235       y += vs_4tap_taps[x][2] * RGB555_G (src[(j + 1)]);
1236       y += vs_4tap_taps[x][3] * RGB555_G (src[(j + 2)]);
1237     } else {
1238       y = vs_4tap_taps[x][0] * RGB555_G (src[CLAMP ((j - 1), 0,
1239                   src_width - 1)]);
1240       y += vs_4tap_taps[x][1] * RGB555_G (src[CLAMP (j, 0, src_width - 1)]);
1241       y += vs_4tap_taps[x][2] * RGB555_G (src[CLAMP ((j + 1), 0,
1242                   src_width - 1)]);
1243       y += vs_4tap_taps[x][3] * RGB555_G (src[CLAMP ((j + 2), 0,
1244                   src_width - 1)]);
1245     }
1246     y += (1 << (SHIFT - 1));
1247     y_g = CLAMP (y >> SHIFT, 0, 255);
1248
1249     if (j - 1 >= 0 && j + 2 < src_width) {
1250       y = vs_4tap_taps[x][0] * RGB555_B (src[MAX ((j - 1), 0)]);
1251       y += vs_4tap_taps[x][1] * RGB555_B (src[j]);
1252       y += vs_4tap_taps[x][2] * RGB555_B (src[(j + 1)]);
1253       y += vs_4tap_taps[x][3] * RGB555_B (src[(j + 2)]);
1254     } else {
1255       y = vs_4tap_taps[x][0] * RGB555_B (src[CLAMP ((j - 1), 0,
1256                   src_width - 1)]);
1257       y += vs_4tap_taps[x][1] * RGB555_B (src[CLAMP (j, 0, src_width - 1)]);
1258       y += vs_4tap_taps[x][2] * RGB555_B (src[CLAMP ((j + 1), 0,
1259                   src_width - 1)]);
1260       y += vs_4tap_taps[x][3] * RGB555_B (src[CLAMP ((j + 2), 0,
1261                   src_width - 1)]);
1262     }
1263     y += (1 << (SHIFT - 1));
1264     y_b = CLAMP (y >> SHIFT, 0, 255);
1265
1266     dest[i] = RGB555 (y_r, y_b, y_g);
1267     acc += increment;
1268   }
1269   *xacc = acc;
1270 }
1271
1272 void
1273 vs_scanline_merge_4tap_RGB555 (uint8_t * dest_u8, uint8_t * src1_u8,
1274     uint8_t * src2_u8, uint8_t * src3_u8, uint8_t * src4_u8, int n, int acc)
1275 {
1276   int i;
1277   int y, y_r, y_b, y_g;
1278   int a, b, c, d;
1279   uint16_t *dest = (uint16_t *) dest_u8;
1280   uint16_t *src1 = (uint16_t *) src1_u8;
1281   uint16_t *src2 = (uint16_t *) src2_u8;
1282   uint16_t *src3 = (uint16_t *) src3_u8;
1283   uint16_t *src4 = (uint16_t *) src4_u8;
1284
1285   acc = (acc >> 8) & 0xff;
1286   a = vs_4tap_taps[acc][0];
1287   b = vs_4tap_taps[acc][1];
1288   c = vs_4tap_taps[acc][2];
1289   d = vs_4tap_taps[acc][3];
1290
1291   for (i = 0; i < n; i++) {
1292     y = a * RGB555_R (src1[i]);
1293     y += b * RGB555_R (src2[i]);
1294     y += c * RGB555_R (src3[i]);
1295     y += d * RGB555_R (src4[i]);
1296     y += (1 << (SHIFT - 1));
1297     y_r = CLAMP (y >> SHIFT, 0, 255);
1298
1299     y = a * RGB555_G (src1[i]);
1300     y += b * RGB555_G (src2[i]);
1301     y += c * RGB555_G (src3[i]);
1302     y += d * RGB555_G (src4[i]);
1303     y += (1 << (SHIFT - 1));
1304     y_g = CLAMP (y >> SHIFT, 0, 255);
1305
1306     y = a * RGB555_B (src1[i]);
1307     y += b * RGB555_B (src2[i]);
1308     y += c * RGB555_B (src3[i]);
1309     y += d * RGB555_B (src4[i]);
1310     y += (1 << (SHIFT - 1));
1311     y_b = CLAMP (y >> SHIFT, 0, 255);
1312
1313     dest[i] = RGB555 (y_r, y_b, y_g);
1314   }
1315 }
1316
1317 void
1318 vs_image_scale_4tap_RGB555 (const VSImage * dest, const VSImage * src,
1319     uint8_t * tmpbuf)
1320 {
1321   int yacc;
1322   int y_increment;
1323   int x_increment;
1324   int i;
1325   int j;
1326   int xacc;
1327   int k;
1328
1329   if (dest->height == 1)
1330     y_increment = 0;
1331   else
1332     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1333
1334   if (dest->width == 1)
1335     x_increment = 0;
1336   else
1337     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1338
1339   k = 0;
1340   for (i = 0; i < 4; i++) {
1341     xacc = 0;
1342     vs_scanline_resample_4tap_RGB555 (tmpbuf + i * dest->stride,
1343         src->pixels + CLAMP (i, 0, src->height - 1) * src->stride, dest->width,
1344         src->width, &xacc, x_increment);
1345   }
1346
1347   yacc = 0;
1348   for (i = 0; i < dest->height; i++) {
1349     uint8_t *t0, *t1, *t2, *t3;
1350
1351     j = yacc >> 16;
1352
1353     while (j > k) {
1354       k++;
1355       if (k + 3 < src->height) {
1356         xacc = 0;
1357         vs_scanline_resample_4tap_RGB555 (tmpbuf + ((k + 3) & 3) * dest->stride,
1358             src->pixels + (k + 3) * src->stride,
1359             dest->width, src->width, &xacc, x_increment);
1360       }
1361     }
1362
1363     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest->stride;
1364     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest->stride;
1365     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest->stride;
1366     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest->stride;
1367     vs_scanline_merge_4tap_RGB555 (dest->pixels + i * dest->stride,
1368         t0, t1, t2, t3, dest->width, yacc & 0xffff);
1369
1370     yacc += y_increment;
1371   }
1372 }
1373
1374 void
1375 vs_scanline_resample_4tap_AYUV64 (uint16_t * dest, uint16_t * src,
1376     int n, int src_width, int *xacc, int increment)
1377 {
1378   int i;
1379   int j;
1380   int acc;
1381   int x;
1382   int y;
1383   int off;
1384
1385   acc = *xacc;
1386   for (i = 0; i < n; i++) {
1387     j = acc >> 16;
1388     x = (acc & 0xffff) >> 8;
1389
1390     for (off = 0; off < 4; off++) {
1391       if (j - 1 >= 0 && j + 2 < src_width) {
1392         y = vs_4tap_taps[x][0] * src[MAX ((j - 1) * 4 + off, 0)];
1393         y += vs_4tap_taps[x][1] * src[j * 4 + off];
1394         y += vs_4tap_taps[x][2] * src[(j + 1) * 4 + off];
1395         y += vs_4tap_taps[x][3] * src[(j + 2) * 4 + off];
1396       } else {
1397         y = vs_4tap_taps[x][0] * src[CLAMP ((j - 1) * 4 + off, 0,
1398                 4 * (src_width - 1) + off)];
1399         y += vs_4tap_taps[x][1] * src[CLAMP (j * 4 + off, 0,
1400                 4 * (src_width - 1) + off)];
1401         y += vs_4tap_taps[x][2] * src[CLAMP ((j + 1) * 4 + off, 0,
1402                 4 * (src_width - 1) + off)];
1403         y += vs_4tap_taps[x][3] * src[CLAMP ((j + 2) * 4 + off, 0,
1404                 4 * (src_width - 1) + off)];
1405       }
1406       y += (1 << (SHIFT - 1));
1407       dest[i * 4 + off] = CLAMP (y >> SHIFT, 0, 255);
1408     }
1409     acc += increment;
1410   }
1411   *xacc = acc;
1412 }
1413
1414 void
1415 vs_scanline_merge_4tap_AYUV64 (uint16_t * dest, uint16_t * src1,
1416     uint16_t * src2, uint16_t * src3, uint16_t * src4, int n, int acc)
1417 {
1418   int i;
1419   int y;
1420   int off;
1421   int a, b, c, d;
1422
1423   acc = (acc >> 8) & 0xff;
1424   a = vs_4tap_taps[acc][0];
1425   b = vs_4tap_taps[acc][1];
1426   c = vs_4tap_taps[acc][2];
1427   d = vs_4tap_taps[acc][3];
1428   for (i = 0; i < n; i++) {
1429     for (off = 0; off < 4; off++) {
1430       y = a * src1[i * 4 + off];
1431       y += b * src2[i * 4 + off];
1432       y += c * src3[i * 4 + off];
1433       y += d * src4[i * 4 + off];
1434       y += (1 << (SHIFT - 1));
1435       dest[i * 4 + off] = CLAMP (y >> SHIFT, 0, 65535);
1436     }
1437   }
1438 }
1439
1440 void
1441 vs_image_scale_4tap_AYUV64 (const VSImage * dest, const VSImage * src,
1442     uint8_t * tmpbuf8)
1443 {
1444   int yacc;
1445   int y_increment;
1446   int x_increment;
1447   int i;
1448   int j;
1449   int xacc;
1450   int k;
1451   guint16 *tmpbuf = (guint16 *) tmpbuf8;
1452   /* destination stride in pixels for easier use with tmpbuf variable */
1453   int dest_pixstride = dest->stride / sizeof (guint16);
1454
1455   if (dest->height == 1)
1456     y_increment = 0;
1457   else
1458     y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1459
1460   if (dest->width == 1)
1461     x_increment = 0;
1462   else
1463     x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1464
1465   k = 0;
1466   for (i = 0; i < 4; i++) {
1467     xacc = 0;
1468     vs_scanline_resample_4tap_AYUV64 (tmpbuf + i * dest_pixstride,
1469         (guint16 *) (src->pixels + CLAMP (i, 0, src->height - 1) * src->stride),
1470         dest->width, src->width, &xacc, x_increment);
1471   }
1472
1473   yacc = 0;
1474   for (i = 0; i < dest->height; i++) {
1475     uint16_t *t0, *t1, *t2, *t3;
1476
1477     j = yacc >> 16;
1478
1479     while (j > k) {
1480       k++;
1481       if (k + 3 < src->height) {
1482         xacc = 0;
1483         vs_scanline_resample_4tap_AYUV64 (tmpbuf + ((k +
1484                     3) & 3) * dest_pixstride,
1485             (guint16 *) (src->pixels + (k + 3) * src->stride), dest->width,
1486             src->width, &xacc, x_increment);
1487       }
1488     }
1489
1490     t0 = tmpbuf + (CLAMP (j - 1, 0, src->height - 1) & 3) * dest_pixstride;
1491     t1 = tmpbuf + (CLAMP (j, 0, src->height - 1) & 3) * dest_pixstride;
1492     t2 = tmpbuf + (CLAMP (j + 1, 0, src->height - 1) & 3) * dest_pixstride;
1493     t3 = tmpbuf + (CLAMP (j + 2, 0, src->height - 1) & 3) * dest_pixstride;
1494     vs_scanline_merge_4tap_AYUV64 ((guint16 *) (dest->pixels +
1495             i * dest->stride), t0, t1, t2, t3, dest->width, yacc & 0xffff);
1496
1497     yacc += y_increment;
1498   }
1499 }