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.
31 #include "vs_scanline.h"
33 #include "gstvideoscaleorc.h"
38 /* greyscale, i.e., single componenet */
41 vs_scanline_downsample_Y (uint8_t * dest, uint8_t * src, int n)
43 video_scale_orc_downsample_u8 (dest, src, n);
47 vs_scanline_resample_nearest_Y (uint8_t * dest, uint8_t * src, int src_width,
48 int n, int *accumulator, int increment)
50 video_scale_orc_resample_nearest_u8 (dest, src, *accumulator, increment, n);
52 *accumulator += n * increment;
57 vs_scanline_resample_linear_Y (uint8_t * dest, uint8_t * src, int src_width,
58 int n, int *accumulator, int increment)
60 video_scale_orc_resample_bilinear_u8 (dest, src, *accumulator, increment, n);
62 *accumulator += n * increment;
66 vs_scanline_merge_linear_Y (uint8_t * dest, uint8_t * src1, uint8_t * src2,
69 uint32_t value = x >> 8;
72 memcpy (dest, src1, n);
74 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n);
79 vs_scanline_downsample_Y16 (uint8_t * dest, uint8_t * src, int n)
81 video_scale_orc_downsample_u16 ((uint16_t *) dest, (uint16_t *) src, n);
85 vs_scanline_resample_nearest_Y16 (uint8_t * dest, uint8_t * src, int src_width,
86 int n, int *accumulator, int increment)
88 int acc = *accumulator;
92 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
94 for (i = 0; i < n; i++) {
97 d[i] = (x < 32768 || j + 1 >= src_width) ? s[j] : s[j + 1];
106 vs_scanline_resample_linear_Y16 (uint8_t * dest, uint8_t * src, int src_width,
107 int n, int *accumulator, int increment)
109 int acc = *accumulator;
113 uint16_t *d = (uint16_t *) dest, *s = (uint16_t *) src;
115 for (i = 0; i < n; i++) {
119 if (j + 1 < src_width)
120 d[i] = (s[j] * (65536 - x) + s[j + 1] * x) >> 16;
131 vs_scanline_merge_linear_Y16 (uint8_t * dest, uint8_t * src1, uint8_t * src2,
134 uint16_t *d = (uint16_t *) dest;
135 const uint16_t *s1 = (const uint16_t *) src1;
136 const uint16_t *s2 = (const uint16_t *) src2;
139 memcpy (d, s1, n * 2);
141 video_scale_orc_merge_linear_u16 (d, s1, s2, 65536 - x, x, n);
148 vs_scanline_downsample_RGBA (uint8_t * dest, uint8_t * src, int n)
150 video_scale_orc_downsample_u32 (dest, src, n);
154 vs_scanline_resample_nearest_RGBA (uint8_t * dest, uint8_t * src, int src_width,
155 int n, int *accumulator, int increment)
157 video_scale_orc_resample_nearest_u32 (dest, src, *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 video_scale_orc_resample_bilinear_u32 (dest, src, *accumulator, increment, n);
168 *accumulator += n * increment;
172 vs_scanline_merge_linear_RGBA (uint8_t * dest, uint8_t * src1, uint8_t * src2,
175 uint32_t value = x >> 8;
178 memcpy (dest, src1, n * 4);
180 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 4);
188 vs_scanline_downsample_RGB (uint8_t * dest, uint8_t * src, int n)
192 for (i = 0; i < n; i++) {
193 dest[i * 3 + 0] = (src[i * 6 + 0] + src[i * 6 + 3]) / 2;
194 dest[i * 3 + 1] = (src[i * 6 + 1] + src[i * 6 + 4]) / 2;
195 dest[i * 3 + 2] = (src[i * 6 + 2] + src[i * 6 + 5]) / 2;
200 vs_scanline_resample_nearest_RGB (uint8_t * dest, uint8_t * src, int src_width,
201 int n, int *accumulator, int increment)
203 int acc = *accumulator;
208 for (i = 0; i < n; i++) {
211 dest[i * 3 + 0] = (x < 32768
212 || j + 1 >= src_width) ? src[j * 3 + 0] : src[j * 3 + 3];
213 dest[i * 3 + 1] = (x < 32768
214 || j + 1 >= src_width) ? src[j * 3 + 1] : src[j * 3 + 4];
215 dest[i * 3 + 2] = (x < 32768
216 || j + 1 >= src_width) ? src[j * 3 + 2] : src[j * 3 + 5];
225 vs_scanline_resample_linear_RGB (uint8_t * dest, uint8_t * src, int src_width,
226 int n, int *accumulator, int increment)
228 int acc = *accumulator;
233 for (i = 0; i < n; i++) {
237 if (j + 1 < src_width) {
239 (src[j * 3 + 0] * (65536 - x) + src[j * 3 + 3] * x) >> 16;
241 (src[j * 3 + 1] * (65536 - x) + src[j * 3 + 4] * x) >> 16;
243 (src[j * 3 + 2] * (65536 - x) + src[j * 3 + 5] * x) >> 16;
245 dest[i * 3 + 0] = src[j * 3 + 0];
246 dest[i * 3 + 1] = src[j * 3 + 1];
247 dest[i * 3 + 2] = src[j * 3 + 2];
257 vs_scanline_merge_linear_RGB (uint8_t * dest, uint8_t * src1, uint8_t * src2,
260 uint32_t value = x >> 8;
263 memcpy (dest, src1, n * 3);
265 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 3);
272 /* n is the number of pixels */
273 /* increment is per Y pixel */
276 vs_scanline_downsample_YUYV (uint8_t * dest, uint8_t * src, int n)
278 video_scale_orc_downsample_yuyv (dest, src, n);
282 vs_scanline_resample_nearest_YUYV (uint8_t * dest, uint8_t * src, int src_width,
283 int n, int *accumulator, int increment)
285 int acc = *accumulator;
289 int quads = (n + 1) / 2;
291 for (i = 0; i < quads; i++) {
294 dest[i * 4 + 0] = (x < 32768
295 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
299 dest[i * 4 + 1] = (x < 65536
300 || 2 * j + 2 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
302 if (2 * i + 1 < n && 2 * j + 1 < src_width)
303 dest[i * 4 + 3] = (x < 65536
304 || 2 * j + 3 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
311 if (2 * i + 1 < n && j < src_width) {
312 dest[i * 4 + 2] = (x < 32768
313 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
322 vs_scanline_resample_linear_YUYV (uint8_t * dest, uint8_t * src, int src_width,
323 int n, int *accumulator, int increment)
325 int acc = *accumulator;
329 int quads = (n + 1) / 2;
331 for (i = 0; i < quads; i++) {
335 if (j + 1 < src_width)
337 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
339 dest[i * 4 + 0] = src[j * 2 + 0];
344 if (2 * j + 2 < src_width)
346 (src[j * 4 + 1] * (131072 - x) + src[j * 4 + 5] * x) >> 17;
348 dest[i * 4 + 1] = src[j * 4 + 1];
350 if (2 * i + 1 < n && 2 * j + 1 < src_width) {
351 if (2 * j + 3 < src_width)
353 (src[j * 4 + 3] * (131072 - x) + src[j * 4 + 7] * x) >> 17;
355 dest[i * 4 + 3] = src[j * 4 + 3];
363 if (2 * i + 1 < n && j < src_width) {
364 if (j + 1 < src_width)
366 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
368 dest[i * 4 + 2] = src[j * 2 + 0];
378 vs_scanline_merge_linear_YUYV (uint8_t * dest, uint8_t * src1, uint8_t * src2,
381 int quads = (n + 1) / 2;
382 uint32_t value = x >> 8;
385 memcpy (dest, src1, quads * 4);
387 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
394 /* n is the number of bi-pixels */
395 /* increment is per Y pixel */
398 vs_scanline_downsample_UYVY (uint8_t * dest, uint8_t * src, int n)
402 for (i = 0; i < n; i++) {
403 dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2;
404 dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 3]) / 2;
405 dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2;
406 dest[i * 4 + 3] = (src[i * 8 + 5] + src[i * 8 + 7]) / 2;
411 vs_scanline_resample_nearest_UYVY (uint8_t * dest, uint8_t * src, int src_width,
412 int n, int *accumulator, int increment)
414 int acc = *accumulator;
418 int quads = (n + 1) / 2;
420 for (i = 0; i < quads; i++) {
424 dest[i * 4 + 1] = (x < 32768
425 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
430 dest[i * 4 + 0] = (x < 65536
431 || 2 * j + 2 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
433 if (2 * i + 1 < n && 2 * j + 1 < src_width)
434 dest[i * 4 + 2] = (x < 65536
435 || 2 * j + 3 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
442 if (2 * i + 1 < n && j < src_width) {
443 dest[i * 4 + 3] = (x < 32768
444 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
453 vs_scanline_resample_linear_UYVY (uint8_t * dest, uint8_t * src, int src_width,
454 int n, int *accumulator, int increment)
456 int acc = *accumulator;
460 int quads = (n + 1) / 2;
462 for (i = 0; i < quads; i++) {
466 if (j + 1 < src_width)
468 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
470 dest[i * 4 + 1] = src[j * 2 + 1];
474 if (2 * j + 2 < src_width)
476 (src[j * 4 + 0] * (131072 - x) + src[j * 4 + 4] * x) >> 17;
478 dest[i * 4 + 0] = src[j * 4 + 0];
480 if (i * 2 + 1 < n && 2 * j + 1 < src_width) {
481 if (2 * j + 3 < src_width)
483 (src[j * 4 + 2] * (131072 - x) + src[j * 4 + 6] * x) >> 17;
485 dest[i * 4 + 2] = src[j * 4 + 2];
493 if (2 * i + 1 < n && j < src_width) {
494 if (j + 1 < src_width)
496 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
498 dest[i * 4 + 3] = src[j * 2 + 1];
507 vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
508 uint8_t * src2, int n, int x)
510 int quads = (n + 1) / 2;
511 uint32_t value = x >> 8;
514 memcpy (dest, src1, quads * 4);
516 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, quads * 4);
523 /* n is the number of bi-pixels */
526 vs_scanline_downsample_NV12 (uint8_t * dest, uint8_t * src, int n)
530 for (i = 0; i < n; i++) {
531 dest[i * 2 + 0] = (src[i * 4 + 0] + src[i * 4 + 2]) / 2;
532 dest[i * 2 + 1] = (src[i * 4 + 1] + src[i * 4 + 3]) / 2;
537 vs_scanline_resample_nearest_NV12 (uint8_t * dest, uint8_t * src, int src_width,
538 int n, int *accumulator, int increment)
540 int acc = *accumulator;
545 for (i = 0; i < n; i++) {
549 dest[i * 2 + 0] = (x < 32768
550 || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
551 dest[i * 2 + 1] = (x < 32768
552 || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
561 vs_scanline_resample_linear_NV12 (uint8_t * dest, uint8_t * src, int src_width,
562 int n, int *accumulator, int increment)
564 int acc = *accumulator;
569 for (i = 0; i < n; i++) {
573 if (j + 1 < src_width) {
575 (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
577 (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
579 dest[i * 4 + 0] = src[j * 2 + 0];
580 dest[i * 4 + 1] = src[j * 2 + 1];
590 vs_scanline_merge_linear_NV12 (uint8_t * dest, uint8_t * src1,
591 uint8_t * src2, int n, int x)
593 uint32_t value = x >> 8;
596 memcpy (dest, src1, n * 2);
598 video_scale_orc_merge_linear_u8 (dest, src1, src2, value, n * 2);
605 /* note that src and dest are uint16_t, and thus endian dependent */
607 #define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13)
608 #define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9)
609 #define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
611 #define RGB565(r,g,b) \
612 ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f))
616 vs_scanline_downsample_RGB565 (uint8_t * dest_u8, uint8_t * src_u8, int n)
618 uint16_t *dest = (uint16_t *) dest_u8;
619 uint16_t *src = (uint16_t *) src_u8;
622 for (i = 0; i < n; i++) {
624 (RGB565_R (src[i * 2]) + RGB565_R (src[i * 2 + 1])) / 2,
625 (RGB565_G (src[i * 2]) + RGB565_G (src[i * 2 + 1])) / 2,
626 (RGB565_B (src[i * 2]) + RGB565_B (src[i * 2 + 1])) / 2);
631 vs_scanline_resample_nearest_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
632 int src_width, int n, int *accumulator, int increment)
634 uint16_t *dest = (uint16_t *) dest_u8;
635 uint16_t *src = (uint16_t *) src_u8;
636 int acc = *accumulator;
641 for (i = 0; i < n; i++) {
644 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
653 vs_scanline_resample_linear_RGB565 (uint8_t * dest_u8, uint8_t * src_u8,
654 int src_width, int n, int *accumulator, int increment)
656 uint16_t *dest = (uint16_t *) dest_u8;
657 uint16_t *src = (uint16_t *) src_u8;
658 int acc = *accumulator;
663 for (i = 0; i < n; i++) {
667 if (j + 1 < src_width) {
669 (RGB565_R (src[j]) * (65536 - x) + RGB565_R (src[j + 1]) * x) >> 16,
670 (RGB565_G (src[j]) * (65536 - x) + RGB565_G (src[j + 1]) * x) >> 16,
671 (RGB565_B (src[j]) * (65536 - x) + RGB565_B (src[j + 1]) * x) >> 16);
673 dest[i] = RGB565 (RGB565_R (src[j]),
674 RGB565_G (src[j]), RGB565_B (src[j]));
684 vs_scanline_merge_linear_RGB565 (uint8_t * dest_u8, uint8_t * src1_u8,
685 uint8_t * src2_u8, int n, int x)
687 uint16_t *dest = (uint16_t *) dest_u8;
688 uint16_t *src1 = (uint16_t *) src1_u8;
689 uint16_t *src2 = (uint16_t *) src2_u8;
692 for (i = 0; i < n; i++) {
694 (RGB565_R (src1[i]) * (65536 - x) + RGB565_R (src2[i]) * x) >> 16,
695 (RGB565_G (src1[i]) * (65536 - x) + RGB565_G (src2[i]) * x) >> 16,
696 (RGB565_B (src1[i]) * (65536 - x) + RGB565_B (src2[i]) * x) >> 16);
703 /* note that src and dest are uint16_t, and thus endian dependent */
705 #define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13)
706 #define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9)
707 #define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2)
709 #define RGB555(r,g,b) \
710 ((((r)<<7)&0x7c00) | (((g)<<3)&0x03e0) | (((b)>>3)&0x001f))
714 vs_scanline_downsample_RGB555 (uint8_t * dest_u8, uint8_t * src_u8, int n)
716 uint16_t *dest = (uint16_t *) dest_u8;
717 uint16_t *src = (uint16_t *) src_u8;
720 for (i = 0; i < n; i++) {
722 (RGB555_R (src[i * 2]) + RGB555_R (src[i * 2 + 1])) / 2,
723 (RGB555_G (src[i * 2]) + RGB555_G (src[i * 2 + 1])) / 2,
724 (RGB555_B (src[i * 2]) + RGB555_B (src[i * 2 + 1])) / 2);
729 vs_scanline_resample_nearest_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
730 int src_width, int n, int *accumulator, int increment)
732 uint16_t *dest = (uint16_t *) dest_u8;
733 uint16_t *src = (uint16_t *) src_u8;
734 int acc = *accumulator;
739 for (i = 0; i < n; i++) {
742 dest[i] = (x < 32768 || j + 1 >= src_width) ? src[j] : src[j + 1];
751 vs_scanline_resample_linear_RGB555 (uint8_t * dest_u8, uint8_t * src_u8,
752 int src_width, int n, int *accumulator, int increment)
754 uint16_t *dest = (uint16_t *) dest_u8;
755 uint16_t *src = (uint16_t *) src_u8;
756 int acc = *accumulator;
761 for (i = 0; i < n; i++) {
765 if (j + 1 < src_width) {
767 (RGB555_R (src[j]) * (65536 - x) + RGB555_R (src[j + 1]) * x) >> 16,
768 (RGB555_G (src[j]) * (65536 - x) + RGB555_G (src[j + 1]) * x) >> 16,
769 (RGB555_B (src[j]) * (65536 - x) + RGB555_B (src[j + 1]) * x) >> 16);
771 dest[i] = RGB555 (RGB555_R (src[j]),
772 RGB555_G (src[j]), RGB555_B (src[j]));
782 vs_scanline_merge_linear_RGB555 (uint8_t * dest_u8, uint8_t * src1_u8,
783 uint8_t * src2_u8, int n, int x)
785 uint16_t *dest = (uint16_t *) dest_u8;
786 uint16_t *src1 = (uint16_t *) src1_u8;
787 uint16_t *src2 = (uint16_t *) src2_u8;
790 for (i = 0; i < n; i++) {
792 (RGB555_R (src1[i]) * (65536 - x) + RGB555_R (src2[i]) * x) >> 16,
793 (RGB555_G (src1[i]) * (65536 - x) + RGB555_G (src2[i]) * x) >> 16,
794 (RGB555_B (src1[i]) * (65536 - x) + RGB555_B (src2[i]) * x) >> 16);
799 vs_scanline_resample_nearest_AYUV64 (uint8_t * dest8, uint8_t * src8,
800 int src_width, int n, int *accumulator, int increment)
802 guint16 *dest = (guint16 *) dest8;
803 guint16 *src = (guint16 *) src8;
804 int acc = *accumulator;
809 for (i = 0; i < n; i++) {
812 dest[i * 4 + 0] = (x < 32768
813 || j + 1 >= src_width) ? src[j * 4 + 0] : src[j * 4 + 4];
814 dest[i * 4 + 1] = (x < 32768
815 || j + 1 >= src_width) ? src[j * 4 + 1] : src[j * 4 + 5];
816 dest[i * 4 + 2] = (x < 32768
817 || j + 1 >= src_width) ? src[j * 4 + 2] : src[j * 4 + 6];
818 dest[i * 4 + 3] = (x < 32768
819 || j + 1 >= src_width) ? src[j * 4 + 3] : src[j * 4 + 7];
828 vs_scanline_resample_linear_AYUV64 (uint8_t * dest8, uint8_t * src8,
829 int src_width, int n, int *accumulator, int increment)
831 guint16 *dest = (guint16 *) dest8;
832 guint16 *src = (guint16 *) src8;
833 int acc = *accumulator;
838 for (i = 0; i < n; i++) {
840 x = (acc & 0xffff) >> 1;
842 if (j + 1 < src_width) {
844 (src[j * 3 + 0] * (32768 - x) + src[j * 4 + 4] * x) >> 15;
846 (src[j * 4 + 1] * (32768 - x) + src[j * 4 + 5] * x) >> 15;
848 (src[j * 4 + 2] * (32768 - x) + src[j * 4 + 6] * x) >> 15;
850 (src[j * 4 + 3] * (32768 - x) + src[j * 4 + 7] * x) >> 15;
852 dest[i * 4 + 0] = src[j * 4 + 0];
853 dest[i * 4 + 1] = src[j * 4 + 1];
854 dest[i * 4 + 2] = src[j * 4 + 2];
855 dest[i * 4 + 3] = src[j * 4 + 3];