2 * Image Scaling Functions
3 * Copyright (c) 2005 David A. Schleef <ds@schleef.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
28 #include "vs_scanline.h"
30 #include "gstvideoscaleorc.h"
35 /* greyscale, i.e., single componenet */
38 vs_scanline_downsample_Y (uint8_t * dest, uint8_t * src, int n)
40 orc_downsample_u8 (dest, src, n);
44 vs_scanline_resample_nearest_Y (uint8_t * dest, uint8_t * src, int src_width,
45 int n, int *accumulator, int increment)
47 gst_videoscale_orc_resample_nearest_u8 (dest, src,
48 *accumulator, increment, n);
50 *accumulator += n * increment;
55 vs_scanline_resample_linear_Y (uint8_t * dest, uint8_t * src, int src_width,
56 int n, int *accumulator, int increment)
58 gst_videoscale_orc_resample_bilinear_u8 (dest, src,
59 *accumulator, increment, n);
61 *accumulator += n * increment;
65 vs_scanline_merge_linear_Y (uint8_t * dest, uint8_t * src1, uint8_t * src2,
68 uint32_t value = x >> 8;
71 memcpy (dest, src1, n);
73 orc_merge_linear_u8 (dest, src1, src2, value, n);
78 vs_scanline_downsample_Y16 (uint8_t * dest, uint8_t * src, int n)
80 orc_downsample_u16 ((uint16_t *) dest, (uint16_t *) src, n);
84 vs_scanline_resample_nearest_Y16 (uint8_t * dest, uint8_t * src, int src_width,
85 int n, int *accumulator, int increment)
87 int acc = *accumulator;
91 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
93 for (i = 0; i < n; i++) {
96 d[i] = (x < 32768 || j + 1 >= src_width) ? s[j] : s[j + 1];
105 vs_scanline_resample_linear_Y16 (uint8_t * dest, uint8_t * src, int src_width,
106 int n, int *accumulator, int increment)
108 int acc = *accumulator;
112 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
114 for (i = 0; i < n; i++) {
118 if (j + 1 < src_width)
119 d[i] = (s[j] * (65536 - x) + s[j + 1] * x) >> 16;
130 vs_scanline_merge_linear_Y16 (uint8_t * dest, uint8_t * src1, uint8_t * src2,
133 uint16_t *d = (uint16_t *) dest;
134 const uint16_t *s1 = (const uint16_t *) src1;
135 const uint16_t *s2 = (const uint16_t *) src2;
138 memcpy (d, s1, n * 2);
140 orc_merge_linear_u16 (d, s1, s2, 65536 - x, x, n);
147 vs_scanline_downsample_RGBA (uint8_t * dest, uint8_t * src, int n)
149 gst_videoscale_orc_downsample_u32 (dest, src, n);
153 vs_scanline_resample_nearest_RGBA (uint8_t * dest, uint8_t * src, int src_width,
154 int n, int *accumulator, int increment)
156 gst_videoscale_orc_resample_nearest_u32 (dest, src,
157 *accumulator, increment, n);
159 *accumulator += n * increment;
163 vs_scanline_resample_linear_RGBA (uint8_t * dest, uint8_t * src, int src_width,
164 int n, int *accumulator, int increment)
166 gst_videoscale_orc_resample_bilinear_u32 (dest, src,
167 *accumulator, increment, n);
169 *accumulator += n * increment;
173 vs_scanline_merge_linear_RGBA (uint8_t * dest, uint8_t * src1, uint8_t * src2,
176 uint32_t value = x >> 8;
179 memcpy (dest, src1, n * 4);
181 orc_merge_linear_u8 (dest, src1, src2, value, n * 4);
189 vs_scanline_downsample_RGB (uint8_t * dest, uint8_t * src, int n)
193 for (i = 0; i < n; i++) {
194 dest[i * 3 + 0] = (src[i * 6 + 0] + src[i * 6 + 3]) / 2;
195 dest[i * 3 + 1] = (src[i * 6 + 1] + src[i * 6 + 4]) / 2;
196 dest[i * 3 + 2] = (src[i * 6 + 2] + src[i * 6 + 5]) / 2;
201 vs_scanline_resample_nearest_RGB (uint8_t * dest, uint8_t * src, int src_width,
202 int n, int *accumulator, int increment)
204 int acc = *accumulator;
209 for (i = 0; i < n; i++) {
212 dest[i * 3 + 0] = (x < 32768
213 || j + 1 >= src_width) ? src[j * 3 + 0] : src[j * 3 + 3];
214 dest[i * 3 + 1] = (x < 32768
215 || j + 1 >= src_width) ? src[j * 3 + 1] : src[j * 3 + 4];
216 dest[i * 3 + 2] = (x < 32768
217 || j + 1 >= src_width) ? src[j * 3 + 2] : src[j * 3 + 5];
226 vs_scanline_resample_linear_RGB (uint8_t * dest, uint8_t * src, int src_width,
227 int n, int *accumulator, int increment)
229 int acc = *accumulator;
234 for (i = 0; i < n; i++) {
238 if (j + 1 < src_width) {
240 (src[j * 3 + 0] * (65536 - x) + src[j * 3 + 3] * x) >> 16;
242 (src[j * 3 + 1] * (65536 - x) + src[j * 3 + 4] * x) >> 16;
244 (src[j * 3 + 2] * (65536 - x) + src[j * 3 + 5] * x) >> 16;
246 dest[i * 3 + 0] = src[j * 3 + 0];
247 dest[i * 3 + 1] = src[j * 3 + 1];
248 dest[i * 3 + 2] = src[j * 3 + 2];
258 vs_scanline_merge_linear_RGB (uint8_t * dest, uint8_t * src1, uint8_t * src2,
261 uint32_t value = x >> 8;
264 memcpy (dest, src1, n * 3);
266 orc_merge_linear_u8 (dest, src1, src2, value, n * 3);
273 /* n is the number of pixels */
274 /* increment is per Y pixel */
277 vs_scanline_downsample_YUYV (uint8_t * dest, uint8_t * src, int n)
279 gst_videoscale_orc_downsample_yuyv (dest, src, n);
283 vs_scanline_resample_nearest_YUYV (uint8_t * dest, uint8_t * src, int src_width,
284 int n, int *accumulator, int increment)
286 int acc = *accumulator;
290 int quads = (n + 1) / 2;
292 for (i = 0; i < quads; i++) {
295 dest[i * 4 + 0] = (x < 32768
296 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
300 dest[i * 4 + 1] = (x < 65536
301 || 2 * j + 2 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
303 if (2 * i + 1 < n && 2 * j + 1 < src_width)
304 dest[i * 4 + 3] = (x < 65536
305 || 2 * j + 3 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
312 if (2 * i + 1 < n && j < src_width) {
313 dest[i * 4 + 2] = (x < 32768
314 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
323 vs_scanline_resample_linear_YUYV (uint8_t * dest, uint8_t * src, int src_width,
324 int n, int *accumulator, int increment)
326 int acc = *accumulator;
330 int quads = (n + 1) / 2;
332 for (i = 0; i < quads; i++) {
336 if (j + 1 < src_width)
338 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
340 dest[i * 4 + 0] = src[j * 2 + 0];
345 if (2 * j + 2 < src_width)
347 (src[j * 4 + 1] * (131072 - x) + src[j * 4 + 5] * x) >> 17;
349 dest[i * 4 + 1] = src[j * 4 + 1];
351 if (2 * i + 1 < n && 2 * j + 1 < src_width) {
352 if (2 * j + 3 < src_width)
354 (src[j * 4 + 3] * (131072 - x) + src[j * 4 + 7] * x) >> 17;
356 dest[i * 4 + 3] = src[j * 4 + 3];
364 if (2 * i + 1 < n && j < src_width) {
365 if (j + 1 < src_width)
367 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
369 dest[i * 4 + 2] = src[j * 2 + 0];
379 vs_scanline_merge_linear_YUYV (uint8_t * dest, uint8_t * src1, uint8_t * src2,
382 int quads = (n + 1) / 2;
383 uint32_t value = x >> 8;
386 memcpy (dest, src1, quads * 4);
388 orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
395 /* n is the number of bi-pixels */
396 /* increment is per Y pixel */
399 vs_scanline_downsample_UYVY (uint8_t * dest, uint8_t * src, int n)
403 for (i = 0; i < n; i++) {
404 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2;
405 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 3]) / 2;
406 dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2;
407 dest[i * 4 + 3] = (src[i * 8 + 5] + src[i * 8 + 7]) / 2;
412 vs_scanline_resample_nearest_UYVY (uint8_t * dest, uint8_t * src, int src_width,
413 int n, int *accumulator, int increment)
415 int acc = *accumulator;
419 int quads = (n + 1) / 2;
421 for (i = 0; i < quads; i++) {
425 dest[i * 4 + 1] = (x < 32768
426 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
431 dest[i * 4 + 0] = (x < 65536
432 || 2 * j + 2 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
434 if (2 * i + 1 < n && 2 * j + 1 < src_width)
435 dest[i * 4 + 2] = (x < 65536
436 || 2 * j + 3 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
443 if (2 * i + 1 < n && j < src_width) {
444 dest[i * 4 + 3] = (x < 32768
445 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
454 vs_scanline_resample_linear_UYVY (uint8_t * dest, uint8_t * src, int src_width,
455 int n, int *accumulator, int increment)
457 int acc = *accumulator;
461 int quads = (n + 1) / 2;
463 for (i = 0; i < quads; i++) {
467 if (j + 1 < src_width)
469 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
471 dest[i * 4 + 1] = src[j * 2 + 1];
475 if (2 * j + 2 < src_width)
477 (src[j * 4 + 0] * (131072 - x) + src[j * 4 + 4] * x) >> 17;
479 dest[i * 4 + 0] = src[j * 4 + 0];
481 if (i * 2 + 1 < n && 2 * j + 1 < src_width) {
482 if (2 * j + 3 < src_width)
484 (src[j * 4 + 2] * (131072 - x) + src[j * 4 + 6] * x) >> 17;
486 dest[i * 4 + 2] = src[j * 4 + 2];
494 if (2 * i + 1 < n && j < src_width) {
495 if (j + 1 < src_width)
497 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
499 dest[i * 4 + 3] = src[j * 2 + 1];
508 vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
509 uint8_t * src2, int n, int x)
511 int quads = (n + 1) / 2;
512 uint32_t value = x >> 8;
515 memcpy (dest, src1, quads * 4);
517 orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
524 /* note that src and dest are uint16_t, and thus endian dependent */
526 #define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13)
527 #define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9)
528 #define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
530 #define RGB565(r,g,b) \
531 ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f))
535 vs_scanline_downsample_RGB565 (uint8_t * dest_u8, uint8_t * src_u8, int n)
537 uint16_t *dest = (uint16_t *) dest_u8;
538 uint16_t *src = (uint16_t *) src_u8;
541 for (i = 0; i < n; i++) {
543 (RGB565_R (src[i * 2]) + RGB565_R (src[i * 2 + 1])) / 2,
544 (RGB565_G (src[i * 2]) + RGB565_G (src[i * 2 + 1])) / 2,
545 (RGB565_B (src[i * 2]) + RGB565_B (src[i * 2 + 1])) / 2);
550 vs_scanline_resample_nearest_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
551 int src_width, int n, int *accumulator, int increment)
553 uint16_t *dest = (uint16_t *) dest_u8;
554 uint16_t *src = (uint16_t *) src_u8;
555 int acc = *accumulator;
560 for (i = 0; i < n; i++) {
563 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
572 vs_scanline_resample_linear_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
573 int src_width, int n, int *accumulator, int increment)
575 uint16_t *dest = (uint16_t *) dest_u8;
576 uint16_t *src = (uint16_t *) src_u8;
577 int acc = *accumulator;
582 for (i = 0; i < n; i++) {
586 if (j + 1 < src_width) {
588 (RGB565_R (src[j]) * (65536 - x) + RGB565_R (src[j + 1]) * x) >> 16,
589 (RGB565_G (src[j]) * (65536 - x) + RGB565_G (src[j + 1]) * x) >> 16,
590 (RGB565_B (src[j]) * (65536 - x) + RGB565_B (src[j + 1]) * x) >> 16);
592 dest[i] = RGB565 (RGB565_R (src[j]),
593 RGB565_G (src[j]), RGB565_B (src[j]));
603 vs_scanline_merge_linear_RGB565 (uint8_t * dest_u8, uint8_t * src1_u8,
604 uint8_t * src2_u8, int n, int x)
606 uint16_t *dest = (uint16_t *) dest_u8;
607 uint16_t *src1 = (uint16_t *) src1_u8;
608 uint16_t *src2 = (uint16_t *) src2_u8;
611 for (i = 0; i < n; i++) {
613 (RGB565_R (src1[i]) * (65536 - x) + RGB565_R (src2[i]) * x) >> 16,
614 (RGB565_G (src1[i]) * (65536 - x) + RGB565_G (src2[i]) * x) >> 16,
615 (RGB565_B (src1[i]) * (65536 - x) + RGB565_B (src2[i]) * x) >> 16);
622 /* note that src and dest are uint16_t, and thus endian dependent */
624 #define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13)
625 #define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9)
626 #define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
628 #define RGB555(r,g,b) \
629 ((((r)<<7)&0x7c00) | (((g)<<3)&0x03e0) | (((b)>>3)&0x001f))
633 vs_scanline_downsample_RGB555 (uint8_t * dest_u8, uint8_t * src_u8, int n)
635 uint16_t *dest = (uint16_t *) dest_u8;
636 uint16_t *src = (uint16_t *) src_u8;
639 for (i = 0; i < n; i++) {
641 (RGB555_R (src[i * 2]) + RGB555_R (src[i * 2 + 1])) / 2,
642 (RGB555_G (src[i * 2]) + RGB555_G (src[i * 2 + 1])) / 2,
643 (RGB555_B (src[i * 2]) + RGB555_B (src[i * 2 + 1])) / 2);
648 vs_scanline_resample_nearest_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
649 int src_width, int n, int *accumulator, int increment)
651 uint16_t *dest = (uint16_t *) dest_u8;
652 uint16_t *src = (uint16_t *) src_u8;
653 int acc = *accumulator;
658 for (i = 0; i < n; i++) {
661 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
670 vs_scanline_resample_linear_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
671 int src_width, int n, int *accumulator, int increment)
673 uint16_t *dest = (uint16_t *) dest_u8;
674 uint16_t *src = (uint16_t *) src_u8;
675 int acc = *accumulator;
680 for (i = 0; i < n; i++) {
684 if (j + 1 < src_width) {
686 (RGB555_R (src[j]) * (65536 - x) + RGB555_R (src[j + 1]) * x) >> 16,
687 (RGB555_G (src[j]) * (65536 - x) + RGB555_G (src[j + 1]) * x) >> 16,
688 (RGB555_B (src[j]) * (65536 - x) + RGB555_B (src[j + 1]) * x) >> 16);
690 dest[i] = RGB555 (RGB555_R (src[j]),
691 RGB555_G (src[j]), RGB555_B (src[j]));
701 vs_scanline_merge_linear_RGB555 (uint8_t * dest_u8, uint8_t * src1_u8,
702 uint8_t * src2_u8, int n, int x)
704 uint16_t *dest = (uint16_t *) dest_u8;
705 uint16_t *src1 = (uint16_t *) src1_u8;
706 uint16_t *src2 = (uint16_t *) src2_u8;
709 for (i = 0; i < n; i++) {
711 (RGB555_R (src1[i]) * (65536 - x) + RGB555_R (src2[i]) * x) >> 16,
712 (RGB555_G (src1[i]) * (65536 - x) + RGB555_G (src2[i]) * x) >> 16,
713 (RGB555_B (src1[i]) * (65536 - x) + RGB555_B (src2[i]) * x) >> 16);
718 vs_scanline_resample_nearest_AYUV64 (uint8_t * dest8, uint8_t * src8,
719 int src_width, int n, int *accumulator, int increment)
721 guint16 *dest = (guint16 *) dest8;
722 guint16 *src = (guint16 *) src8;
723 int acc = *accumulator;
728 for (i = 0; i < n; i++) {
731 dest[i * 4 + 0] = (x < 32768
732 || j + 1 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
733 dest[i * 4 + 1] = (x < 32768
734 || j + 1 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
735 dest[i * 4 + 2] = (x < 32768
736 || j + 1 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
737 dest[i * 4 + 3] = (x < 32768
738 || j + 1 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
747 vs_scanline_resample_linear_AYUV64 (uint8_t * dest8, uint8_t * src8,
748 int src_width, int n, int *accumulator, int increment)
750 guint16 *dest = (guint16 *) dest8;
751 guint16 *src = (guint16 *) src8;
752 int acc = *accumulator;
757 for (i = 0; i < n; i++) {
759 x = (acc & 0xffff) >> 1;
761 if (j + 1 < src_width) {
763 (src[j * 3 + 0] * (32768 - x) + src[j * 4 + 4] * x) >> 15;
765 (src[j * 4 + 1] * (32768 - x) + src[j * 4 + 5] * x) >> 15;
767 (src[j * 4 + 2] * (32768 - x) + src[j * 4 + 6] * x) >> 15;
769 (src[j * 4 + 3] * (32768 - x) + src[j * 4 + 7] * x) >> 15;
771 dest[i * 4 + 0] = src[j * 4 + 0];
772 dest[i * 4 + 1] = src[j * 4 + 1];
773 dest[i * 4 + 2] = src[j * 4 + 2];
774 dest[i * 4 + 3] = src[j * 4 + 3];