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