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