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 video_scale_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 video_scale_orc_resample_nearest_u8 (dest, src, *accumulator, increment, n);
49 *accumulator += n * increment;
54 vs_scanline_resample_linear_Y (uint8_t * dest, uint8_t * src, int src_width,
55 int n, int *accumulator, int increment)
57 video_scale_orc_resample_bilinear_u8 (dest, src, *accumulator, increment, n);
59 *accumulator += n * increment;
63 vs_scanline_merge_linear_Y (uint8_t * dest, uint8_t * src1, uint8_t * src2,
66 uint32_t value = x >> 8;
69 memcpy (dest, src1, n);
71 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n);
76 vs_scanline_downsample_Y16 (uint8_t * dest, uint8_t * src, int n)
78 video_scale_orc_downsample_u16 ((uint16_t *) dest, (uint16_t *) src, n);
82 vs_scanline_resample_nearest_Y16 (uint8_t * dest, uint8_t * src, int src_width,
83 int n, int *accumulator, int increment)
85 int acc = *accumulator;
89 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
91 for (i = 0; i < n; i++) {
94 d[i] = (x < 32768 || j + 1 >= src_width) ? s[j] : s[j + 1];
103 vs_scanline_resample_linear_Y16 (uint8_t * dest, uint8_t * src, int src_width,
104 int n, int *accumulator, int increment)
106 int acc = *accumulator;
110 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
112 for (i = 0; i < n; i++) {
116 if (j + 1 < src_width)
117 d[i] = (s[j] * (65536 - x) + s[j + 1] * x) >> 16;
128 vs_scanline_merge_linear_Y16 (uint8_t * dest, uint8_t * src1, uint8_t * src2,
131 uint16_t *d = (uint16_t *) dest;
132 const uint16_t *s1 = (const uint16_t *) src1;
133 const uint16_t *s2 = (const uint16_t *) src2;
136 memcpy (d, s1, n * 2);
138 video_scale_orc_merge_linear_u16 (d, s1, s2, 65536 - x, x, n);
145 vs_scanline_downsample_RGBA (uint8_t * dest, uint8_t * src, int n)
147 video_scale_orc_downsample_u32 (dest, src, n);
151 vs_scanline_resample_nearest_RGBA (uint8_t * dest, uint8_t * src, int src_width,
152 int n, int *accumulator, int increment)
154 video_scale_orc_resample_nearest_u32 (dest, src, *accumulator, increment, n);
156 *accumulator += n * increment;
160 vs_scanline_resample_linear_RGBA (uint8_t * dest, uint8_t * src, int src_width,
161 int n, int *accumulator, int increment)
163 video_scale_orc_resample_bilinear_u32 (dest, src, *accumulator, increment, n);
165 *accumulator += n * increment;
169 vs_scanline_merge_linear_RGBA (uint8_t * dest, uint8_t * src1, uint8_t * src2,
172 uint32_t value = x >> 8;
175 memcpy (dest, src1, n * 4);
177 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 4);
185 vs_scanline_downsample_RGB (uint8_t * dest, uint8_t * src, int n)
189 for (i = 0; i < n; i++) {
190 dest[i * 3 + 0] = (src[i * 6 + 0] + src[i * 6 + 3]) / 2;
191 dest[i * 3 + 1] = (src[i * 6 + 1] + src[i * 6 + 4]) / 2;
192 dest[i * 3 + 2] = (src[i * 6 + 2] + src[i * 6 + 5]) / 2;
197 vs_scanline_resample_nearest_RGB (uint8_t * dest, uint8_t * src, int src_width,
198 int n, int *accumulator, int increment)
200 int acc = *accumulator;
205 for (i = 0; i < n; i++) {
208 dest[i * 3 + 0] = (x < 32768
209 || j + 1 >= src_width) ? src[j * 3 + 0] : src[j * 3 + 3];
210 dest[i * 3 + 1] = (x < 32768
211 || j + 1 >= src_width) ? src[j * 3 + 1] : src[j * 3 + 4];
212 dest[i * 3 + 2] = (x < 32768
213 || j + 1 >= src_width) ? src[j * 3 + 2] : src[j * 3 + 5];
222 vs_scanline_resample_linear_RGB (uint8_t * dest, uint8_t * src, int src_width,
223 int n, int *accumulator, int increment)
225 int acc = *accumulator;
230 for (i = 0; i < n; i++) {
234 if (j + 1 < src_width) {
236 (src[j * 3 + 0] * (65536 - x) + src[j * 3 + 3] * x) >> 16;
238 (src[j * 3 + 1] * (65536 - x) + src[j * 3 + 4] * x) >> 16;
240 (src[j * 3 + 2] * (65536 - x) + src[j * 3 + 5] * x) >> 16;
242 dest[i * 3 + 0] = src[j * 3 + 0];
243 dest[i * 3 + 1] = src[j * 3 + 1];
244 dest[i * 3 + 2] = src[j * 3 + 2];
254 vs_scanline_merge_linear_RGB (uint8_t * dest, uint8_t * src1, uint8_t * src2,
257 uint32_t value = x >> 8;
260 memcpy (dest, src1, n * 3);
262 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 3);
269 /* n is the number of pixels */
270 /* increment is per Y pixel */
273 vs_scanline_downsample_YUYV (uint8_t * dest, uint8_t * src, int n)
275 video_scale_orc_downsample_yuyv (dest, src, n);
279 vs_scanline_resample_nearest_YUYV (uint8_t * dest, uint8_t * src, int src_width,
280 int n, int *accumulator, int increment)
282 int acc = *accumulator;
286 int quads = (n + 1) / 2;
288 for (i = 0; i < quads; i++) {
291 dest[i * 4 + 0] = (x < 32768
292 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
296 dest[i * 4 + 1] = (x < 65536
297 || 2 * j + 2 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
299 if (2 * i + 1 < n && 2 * j + 1 < src_width)
300 dest[i * 4 + 3] = (x < 65536
301 || 2 * j + 3 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
308 if (2 * i + 1 < n && j < src_width) {
309 dest[i * 4 + 2] = (x < 32768
310 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
319 vs_scanline_resample_linear_YUYV (uint8_t * dest, uint8_t * src, int src_width,
320 int n, int *accumulator, int increment)
322 int acc = *accumulator;
326 int quads = (n + 1) / 2;
328 for (i = 0; i < quads; i++) {
332 if (j + 1 < src_width)
334 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
336 dest[i * 4 + 0] = src[j * 2 + 0];
341 if (2 * j + 2 < src_width)
343 (src[j * 4 + 1] * (131072 - x) + src[j * 4 + 5] * x) >> 17;
345 dest[i * 4 + 1] = src[j * 4 + 1];
347 if (2 * i + 1 < n && 2 * j + 1 < src_width) {
348 if (2 * j + 3 < src_width)
350 (src[j * 4 + 3] * (131072 - x) + src[j * 4 + 7] * x) >> 17;
352 dest[i * 4 + 3] = src[j * 4 + 3];
360 if (2 * i + 1 < n && j < src_width) {
361 if (j + 1 < src_width)
363 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
365 dest[i * 4 + 2] = src[j * 2 + 0];
375 vs_scanline_merge_linear_YUYV (uint8_t * dest, uint8_t * src1, uint8_t * src2,
378 int quads = (n + 1) / 2;
379 uint32_t value = x >> 8;
382 memcpy (dest, src1, quads * 4);
384 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
391 /* n is the number of bi-pixels */
392 /* increment is per Y pixel */
395 vs_scanline_downsample_UYVY (uint8_t * dest, uint8_t * src, int n)
399 for (i = 0; i < n; i++) {
400 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2;
401 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 3]) / 2;
402 dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2;
403 dest[i * 4 + 3] = (src[i * 8 + 5] + src[i * 8 + 7]) / 2;
408 vs_scanline_resample_nearest_UYVY (uint8_t * dest, uint8_t * src, int src_width,
409 int n, int *accumulator, int increment)
411 int acc = *accumulator;
415 int quads = (n + 1) / 2;
417 for (i = 0; i < quads; i++) {
421 dest[i * 4 + 1] = (x < 32768
422 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
427 dest[i * 4 + 0] = (x < 65536
428 || 2 * j + 2 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
430 if (2 * i + 1 < n && 2 * j + 1 < src_width)
431 dest[i * 4 + 2] = (x < 65536
432 || 2 * j + 3 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
439 if (2 * i + 1 < n && j < src_width) {
440 dest[i * 4 + 3] = (x < 32768
441 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
450 vs_scanline_resample_linear_UYVY (uint8_t * dest, uint8_t * src, int src_width,
451 int n, int *accumulator, int increment)
453 int acc = *accumulator;
457 int quads = (n + 1) / 2;
459 for (i = 0; i < quads; i++) {
463 if (j + 1 < src_width)
465 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
467 dest[i * 4 + 1] = src[j * 2 + 1];
471 if (2 * j + 2 < src_width)
473 (src[j * 4 + 0] * (131072 - x) + src[j * 4 + 4] * x) >> 17;
475 dest[i * 4 + 0] = src[j * 4 + 0];
477 if (i * 2 + 1 < n && 2 * j + 1 < src_width) {
478 if (2 * j + 3 < src_width)
480 (src[j * 4 + 2] * (131072 - x) + src[j * 4 + 6] * x) >> 17;
482 dest[i * 4 + 2] = src[j * 4 + 2];
490 if (2 * i + 1 < n && j < src_width) {
491 if (j + 1 < src_width)
493 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
495 dest[i * 4 + 3] = src[j * 2 + 1];
504 vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
505 uint8_t * src2, int n, int x)
507 int quads = (n + 1) / 2;
508 uint32_t value = x >> 8;
511 memcpy (dest, src1, quads * 4);
513 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
520 /* n is the number of bi-pixels */
523 vs_scanline_downsample_NV12 (uint8_t * dest, uint8_t * src, int n)
527 for (i = 0; i < n; i++) {
528 dest[i * 2 + 0] = (src[i * 4 + 0] + src[i * 4 + 2]) / 2;
529 dest[i * 2 + 1] = (src[i * 4 + 1] + src[i * 4 + 3]) / 2;
534 vs_scanline_resample_nearest_NV12 (uint8_t * dest, uint8_t * src, int src_width,
535 int n, int *accumulator, int increment)
537 int acc = *accumulator;
542 for (i = 0; i < n; i++) {
546 dest[i * 2 + 0] = (x < 32768
547 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
548 dest[i * 2 + 1] = (x < 32768
549 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
558 vs_scanline_resample_linear_NV12 (uint8_t * dest, uint8_t * src, int src_width,
559 int n, int *accumulator, int increment)
561 int acc = *accumulator;
566 for (i = 0; i < n; i++) {
570 if (j + 1 < src_width) {
572 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
574 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
576 dest[i * 4 + 0] = src[j * 2 + 0];
577 dest[i * 4 + 1] = src[j * 2 + 1];
587 vs_scanline_merge_linear_NV12 (uint8_t * dest, uint8_t * src1,
588 uint8_t * src2, int n, int x)
590 uint32_t value = x >> 8;
593 memcpy (dest, src1, n * 2);
595 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 2);
602 /* note that src and dest are uint16_t, and thus endian dependent */
604 #define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13)
605 #define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9)
606 #define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
608 #define RGB565(r,g,b) \
609 ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f))
613 vs_scanline_downsample_RGB565 (uint8_t * dest_u8, uint8_t * src_u8, int n)
615 uint16_t *dest = (uint16_t *) dest_u8;
616 uint16_t *src = (uint16_t *) src_u8;
619 for (i = 0; i < n; i++) {
621 (RGB565_R (src[i * 2]) + RGB565_R (src[i * 2 + 1])) / 2,
622 (RGB565_G (src[i * 2]) + RGB565_G (src[i * 2 + 1])) / 2,
623 (RGB565_B (src[i * 2]) + RGB565_B (src[i * 2 + 1])) / 2);
628 vs_scanline_resample_nearest_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
629 int src_width, int n, int *accumulator, int increment)
631 uint16_t *dest = (uint16_t *) dest_u8;
632 uint16_t *src = (uint16_t *) src_u8;
633 int acc = *accumulator;
638 for (i = 0; i < n; i++) {
641 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
650 vs_scanline_resample_linear_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
651 int src_width, int n, int *accumulator, int increment)
653 uint16_t *dest = (uint16_t *) dest_u8;
654 uint16_t *src = (uint16_t *) src_u8;
655 int acc = *accumulator;
660 for (i = 0; i < n; i++) {
664 if (j + 1 < src_width) {
666 (RGB565_R (src[j]) * (65536 - x) + RGB565_R (src[j + 1]) * x) >> 16,
667 (RGB565_G (src[j]) * (65536 - x) + RGB565_G (src[j + 1]) * x) >> 16,
668 (RGB565_B (src[j]) * (65536 - x) + RGB565_B (src[j + 1]) * x) >> 16);
670 dest[i] = RGB565 (RGB565_R (src[j]),
671 RGB565_G (src[j]), RGB565_B (src[j]));
681 vs_scanline_merge_linear_RGB565 (uint8_t * dest_u8, uint8_t * src1_u8,
682 uint8_t * src2_u8, int n, int x)
684 uint16_t *dest = (uint16_t *) dest_u8;
685 uint16_t *src1 = (uint16_t *) src1_u8;
686 uint16_t *src2 = (uint16_t *) src2_u8;
689 for (i = 0; i < n; i++) {
691 (RGB565_R (src1[i]) * (65536 - x) + RGB565_R (src2[i]) * x) >> 16,
692 (RGB565_G (src1[i]) * (65536 - x) + RGB565_G (src2[i]) * x) >> 16,
693 (RGB565_B (src1[i]) * (65536 - x) + RGB565_B (src2[i]) * x) >> 16);
700 /* note that src and dest are uint16_t, and thus endian dependent */
702 #define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13)
703 #define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9)
704 #define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
706 #define RGB555(r,g,b) \
707 ((((r)<<7)&0x7c00) | (((g)<<3)&0x03e0) | (((b)>>3)&0x001f))
711 vs_scanline_downsample_RGB555 (uint8_t * dest_u8, uint8_t * src_u8, int n)
713 uint16_t *dest = (uint16_t *) dest_u8;
714 uint16_t *src = (uint16_t *) src_u8;
717 for (i = 0; i < n; i++) {
719 (RGB555_R (src[i * 2]) + RGB555_R (src[i * 2 + 1])) / 2,
720 (RGB555_G (src[i * 2]) + RGB555_G (src[i * 2 + 1])) / 2,
721 (RGB555_B (src[i * 2]) + RGB555_B (src[i * 2 + 1])) / 2);
726 vs_scanline_resample_nearest_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
727 int src_width, int n, int *accumulator, int increment)
729 uint16_t *dest = (uint16_t *) dest_u8;
730 uint16_t *src = (uint16_t *) src_u8;
731 int acc = *accumulator;
736 for (i = 0; i < n; i++) {
739 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
748 vs_scanline_resample_linear_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
749 int src_width, int n, int *accumulator, int increment)
751 uint16_t *dest = (uint16_t *) dest_u8;
752 uint16_t *src = (uint16_t *) src_u8;
753 int acc = *accumulator;
758 for (i = 0; i < n; i++) {
762 if (j + 1 < src_width) {
764 (RGB555_R (src[j]) * (65536 - x) + RGB555_R (src[j + 1]) * x) >> 16,
765 (RGB555_G (src[j]) * (65536 - x) + RGB555_G (src[j + 1]) * x) >> 16,
766 (RGB555_B (src[j]) * (65536 - x) + RGB555_B (src[j + 1]) * x) >> 16);
768 dest[i] = RGB555 (RGB555_R (src[j]),
769 RGB555_G (src[j]), RGB555_B (src[j]));
779 vs_scanline_merge_linear_RGB555 (uint8_t * dest_u8, uint8_t * src1_u8,
780 uint8_t * src2_u8, int n, int x)
782 uint16_t *dest = (uint16_t *) dest_u8;
783 uint16_t *src1 = (uint16_t *) src1_u8;
784 uint16_t *src2 = (uint16_t *) src2_u8;
787 for (i = 0; i < n; i++) {
789 (RGB555_R (src1[i]) * (65536 - x) + RGB555_R (src2[i]) * x) >> 16,
790 (RGB555_G (src1[i]) * (65536 - x) + RGB555_G (src2[i]) * x) >> 16,
791 (RGB555_B (src1[i]) * (65536 - x) + RGB555_B (src2[i]) * x) >> 16);
796 vs_scanline_resample_nearest_AYUV64 (uint8_t * dest8, uint8_t * src8,
797 int src_width, int n, int *accumulator, int increment)
799 guint16 *dest = (guint16 *) dest8;
800 guint16 *src = (guint16 *) src8;
801 int acc = *accumulator;
806 for (i = 0; i < n; i++) {
809 dest[i * 4 + 0] = (x < 32768
810 || j + 1 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
811 dest[i * 4 + 1] = (x < 32768
812 || j + 1 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
813 dest[i * 4 + 2] = (x < 32768
814 || j + 1 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
815 dest[i * 4 + 3] = (x < 32768
816 || j + 1 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
825 vs_scanline_resample_linear_AYUV64 (uint8_t * dest8, uint8_t * src8,
826 int src_width, int n, int *accumulator, int increment)
828 guint16 *dest = (guint16 *) dest8;
829 guint16 *src = (guint16 *) src8;
830 int acc = *accumulator;
835 for (i = 0; i < n; i++) {
837 x = (acc & 0xffff) >> 1;
839 if (j + 1 < src_width) {
841 (src[j * 3 + 0] * (32768 - x) + src[j * 4 + 4] * x) >> 15;
843 (src[j * 4 + 1] * (32768 - x) + src[j * 4 + 5] * x) >> 15;
845 (src[j * 4 + 2] * (32768 - x) + src[j * 4 + 6] * x) >> 15;
847 (src[j * 4 + 3] * (32768 - x) + src[j * 4 + 7] * x) >> 15;
849 dest[i * 4 + 0] = src[j * 4 + 0];
850 dest[i * 4 + 1] = src[j * 4 + 1];
851 dest[i * 4 + 2] = src[j * 4 + 2];
852 dest[i * 4 + 3] = src[j * 4 + 3];