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.
30 #include "vs_scanline.h"
33 #include "gstvideoscaleorc.h"
36 #define ROUND_UP_2(x) (((x)+1)&~1)
37 #define ROUND_UP_4(x) (((x)+3)&~3)
38 #define ROUND_UP_8(x) (((x)+7)&~7)
41 vs_image_scale_nearest_RGBA (const VSImage * dest, const VSImage * src,
51 if (dest->height == 1)
54 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
59 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
64 for (i = 0; i < dest->height; i++) {
68 memcpy (dest->pixels + i * dest->stride,
69 dest->pixels + (i - 1) * dest->stride, dest->width * 4);
71 gst_videoscale_orc_resample_nearest_u32 (dest->pixels + i * dest->stride,
72 src->pixels + j * src->stride, 0, x_increment, dest->width);
81 vs_image_scale_linear_RGBA (const VSImage * dest, const VSImage * src,
93 if (dest->height == 1)
96 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
101 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
103 dest_size = dest->width * 4;
105 #define LINE(x) ((tmpbuf) + (dest_size)*((x)&1))
108 gst_videoscale_orc_resample_bilinear_u32 (LINE (0), src->pixels,
109 0, x_increment, dest->width);
111 for (i = 0; i < dest->height; i++) {
116 memcpy (dest->pixels + i * dest->stride, LINE (j), dest_size);
119 gst_videoscale_orc_resample_bilinear_u32 (LINE (j),
120 src->pixels + j * src->stride, 0, x_increment, dest->width);
124 gst_videoscale_orc_resample_bilinear_u32 (LINE (j + 1),
125 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
128 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
129 LINE (j), LINE (j + 1), (x >> 8), dest->width * 4);
138 vs_image_scale_nearest_RGB (const VSImage * dest, const VSImage * src,
148 if (dest->height == 1)
151 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
153 if (dest->width == 1)
156 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
159 for (i = 0; i < dest->height; i++) {
163 vs_scanline_resample_nearest_RGB (dest->pixels + i * dest->stride,
164 src->pixels + j * src->stride, src->width, dest->width, &xacc,
172 vs_image_scale_linear_RGB (const VSImage * dest, const VSImage * src,
188 if (dest->height == 1)
191 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
193 if (dest->width == 1)
196 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
198 dest_size = dest->width * 3;
201 tmp2 = tmpbuf + dest_size;
206 vs_scanline_resample_linear_RGB (tmp1, src->pixels, src->width, dest->width,
209 for (i = 0; i < dest->height; i++) {
215 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
216 } else if (j == y2) {
217 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
220 vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride,
221 src->width, dest->width, &xacc, x_increment);
223 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
229 vs_scanline_resample_linear_RGB (tmp2,
230 src->pixels + (j + 1) * src->stride, src->width, dest->width,
234 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
235 tmp1, tmp2, dest->width, x);
236 } else if (j == y2) {
239 vs_scanline_resample_linear_RGB (tmp1,
240 src->pixels + (j + 1) * src->stride, src->width, dest->width,
244 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
245 tmp2, tmp1, dest->width, x);
248 vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride,
249 src->width, dest->width, &xacc, x_increment);
252 vs_scanline_resample_linear_RGB (tmp2,
253 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
256 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
257 tmp1, tmp2, dest->width, x);
268 vs_image_scale_nearest_YUYV (const VSImage * dest, const VSImage * src,
278 if (dest->height == 1)
281 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
283 if (dest->width == 1)
286 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
289 for (i = 0; i < dest->height; i++) {
293 vs_scanline_resample_nearest_YUYV (dest->pixels + i * dest->stride,
294 src->pixels + j * src->stride, src->width, dest->width, &xacc,
302 vs_image_scale_linear_YUYV (const VSImage * dest, const VSImage * src,
318 if (dest->height == 1)
321 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
323 if (dest->width == 1)
326 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
328 dest_size = ROUND_UP_4 (dest->width * 2);
331 tmp2 = tmpbuf + dest_size;
336 vs_scanline_resample_linear_YUYV (tmp1, src->pixels, src->width, dest->width,
339 for (i = 0; i < dest->height; i++) {
345 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
346 } else if (j == y2) {
347 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
350 vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride,
351 src->width, dest->width, &xacc, x_increment);
353 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
359 vs_scanline_resample_linear_YUYV (tmp2,
360 src->pixels + (j + 1) * src->stride, src->width, dest->width,
364 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
365 tmp1, tmp2, dest->width, x);
366 } else if (j == y2) {
369 vs_scanline_resample_linear_YUYV (tmp1,
370 src->pixels + (j + 1) * src->stride, src->width, dest->width,
374 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
375 tmp2, tmp1, dest->width, x);
378 vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride,
379 src->width, dest->width, &xacc, x_increment);
382 vs_scanline_resample_linear_YUYV (tmp2,
383 src->pixels + (j + 1) * src->stride, src->width, dest->width,
386 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
387 tmp1, tmp2, dest->width, x);
398 vs_image_scale_nearest_UYVY (const VSImage * dest, const VSImage * src,
408 if (dest->height == 1)
411 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
413 if (dest->width == 1)
416 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
419 for (i = 0; i < dest->height; i++) {
423 vs_scanline_resample_nearest_UYVY (dest->pixels + i * dest->stride,
424 src->pixels + j * src->stride, src->width, dest->width, &xacc,
432 vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src,
448 if (dest->height == 1)
451 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
453 if (dest->width == 1)
456 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
458 dest_size = ROUND_UP_4 (dest->width * 2);
461 tmp2 = tmpbuf + dest_size;
466 vs_scanline_resample_linear_UYVY (tmp1, src->pixels, src->width, dest->width,
469 for (i = 0; i < dest->height; i++) {
475 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
476 } else if (j == y2) {
477 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
480 vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride,
481 src->width, dest->width, &xacc, x_increment);
483 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
489 vs_scanline_resample_linear_UYVY (tmp2,
490 src->pixels + (j + 1) * src->stride, src->width, dest->width,
494 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
495 tmp1, tmp2, dest->width, x);
496 } else if (j == y2) {
499 vs_scanline_resample_linear_UYVY (tmp1,
500 src->pixels + (j + 1) * src->stride, src->width, dest->width,
504 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
505 tmp2, tmp1, dest->width, x);
508 vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride,
509 src->width, dest->width, &xacc, x_increment);
512 vs_scanline_resample_linear_UYVY (tmp2,
513 src->pixels + (j + 1) * src->stride, src->width, dest->width,
516 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
517 tmp1, tmp2, dest->width, x);
528 vs_image_scale_nearest_Y (const VSImage * dest, const VSImage * src,
537 if (dest->height == 1)
540 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
542 if (dest->width == 1)
545 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
548 for (i = 0; i < dest->height; i++) {
551 gst_videoscale_orc_resample_nearest_u8 (dest->pixels + i * dest->stride,
552 src->pixels + j * src->stride, 0, x_increment, dest->width);
558 vs_image_scale_linear_Y (const VSImage * dest, const VSImage * src,
573 if (dest->height == 1)
576 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
578 if (dest->width == 1)
581 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
583 dest_size = dest->width;
586 tmp2 = tmpbuf + dest_size;
590 gst_videoscale_orc_resample_bilinear_u8 (tmp1, src->pixels,
591 0, x_increment, dest->width);
593 for (i = 0; i < dest->height; i++) {
599 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
600 } else if (j == y2) {
601 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
603 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
604 src->pixels + j * src->stride, 0, x_increment, dest->width);
606 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
611 gst_videoscale_orc_resample_bilinear_u8 (tmp2,
612 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
616 memcpy (dest->pixels + i * dest->stride, tmp1, dest->width);
618 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
619 tmp1, tmp2, (x >> 8), dest->width);
621 } else if (j == y2) {
623 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
624 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
628 memcpy (dest->pixels + i * dest->stride, tmp2, dest->width);
630 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
631 tmp2, tmp1, (x >> 8), dest->width);
634 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
635 src->pixels + j * src->stride, 0, x_increment, dest->width);
637 gst_videoscale_orc_resample_bilinear_u8 (tmp2,
638 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
641 memcpy (dest->pixels + i * dest->stride, tmp1, dest->width);
643 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
644 tmp1, tmp2, (x >> 8), dest->width);
654 vs_image_scale_nearest_Y16 (const VSImage * dest, const VSImage * src,
664 if (dest->height == 1)
667 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
669 if (dest->width == 1)
672 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
675 for (i = 0; i < dest->height; i++) {
679 vs_scanline_resample_nearest_Y16 (dest->pixels + i * dest->stride,
680 src->pixels + j * src->stride, src->width, dest->width, &xacc,
688 vs_image_scale_linear_Y16 (const VSImage * dest, const VSImage * src,
704 if (dest->height == 1)
707 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
709 if (dest->width == 1)
712 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
714 dest_size = 2 * dest->width;
717 tmp2 = tmpbuf + dest_size;
722 vs_scanline_resample_linear_Y16 (tmp1, src->pixels, src->width, dest->width,
725 for (i = 0; i < dest->height; i++) {
731 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
732 } else if (j == y2) {
733 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
736 vs_scanline_resample_linear_Y16 (tmp1, src->pixels + j * src->stride,
737 src->width, dest->width, &xacc, x_increment);
739 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
745 vs_scanline_resample_linear_Y16 (tmp2,
746 src->pixels + (j + 1) * src->stride, src->width, dest->width,
750 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
751 tmp1, tmp2, dest->width, x);
752 } else if (j == y2) {
755 vs_scanline_resample_linear_Y16 (tmp1,
756 src->pixels + (j + 1) * src->stride, src->width, dest->width,
760 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
761 tmp2, tmp1, dest->width, x);
764 vs_scanline_resample_linear_Y16 (tmp1, src->pixels + j * src->stride,
765 src->width, dest->width, &xacc, x_increment);
768 vs_scanline_resample_linear_Y16 (tmp2,
769 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
772 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
773 tmp1, tmp2, dest->width, x);
784 vs_image_scale_nearest_RGB565 (const VSImage * dest, const VSImage * src,
794 if (dest->height == 1)
797 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
799 if (dest->width == 1)
802 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
805 for (i = 0; i < dest->height; i++) {
809 vs_scanline_resample_nearest_RGB565 (dest->pixels + i * dest->stride,
810 src->pixels + j * src->stride, src->width, dest->width, &xacc,
818 vs_image_scale_linear_RGB565 (const VSImage * dest, const VSImage * src,
834 if (dest->height == 1)
837 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
839 if (dest->width == 1)
842 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
844 dest_size = dest->width * 2;
847 tmp2 = tmpbuf + dest_size;
852 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels, src->width,
853 dest->width, &xacc, x_increment);
855 for (i = 0; i < dest->height; i++) {
861 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
862 } else if (j == y2) {
863 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
866 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride,
867 src->width, dest->width, &xacc, x_increment);
869 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
875 vs_scanline_resample_linear_RGB565 (tmp2,
876 src->pixels + (j + 1) * src->stride, src->width, dest->width,
880 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
881 tmp1, tmp2, dest->width, x);
882 } else if (j == y2) {
885 vs_scanline_resample_linear_RGB565 (tmp1,
886 src->pixels + (j + 1) * src->stride, src->width, dest->width,
890 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
891 tmp2, tmp1, dest->width, x);
894 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride,
895 src->width, dest->width, &xacc, x_increment);
898 vs_scanline_resample_linear_RGB565 (tmp2,
899 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
902 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
903 tmp1, tmp2, dest->width, x);
914 vs_image_scale_nearest_RGB555 (const VSImage * dest, const VSImage * src,
924 if (dest->height == 1)
927 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
929 if (dest->width == 1)
932 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
935 for (i = 0; i < dest->height; i++) {
939 vs_scanline_resample_nearest_RGB555 (dest->pixels + i * dest->stride,
940 src->pixels + j * src->stride, src->width, dest->width, &xacc,
948 vs_image_scale_linear_RGB555 (const VSImage * dest, const VSImage * src,
964 if (dest->height == 1)
967 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
969 if (dest->width == 1)
972 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
974 dest_size = dest->width * 2;
977 tmp2 = tmpbuf + dest_size;
982 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels, src->width,
983 dest->width, &xacc, x_increment);
985 for (i = 0; i < dest->height; i++) {
991 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
992 } else if (j == y2) {
993 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
996 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride,
997 src->width, dest->width, &xacc, x_increment);
999 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
1005 vs_scanline_resample_linear_RGB555 (tmp2,
1006 src->pixels + (j + 1) * src->stride, src->width, dest->width,
1007 &xacc, x_increment);
1010 vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride,
1011 tmp1, tmp2, dest->width, x);
1012 } else if (j == y2) {
1015 vs_scanline_resample_linear_RGB555 (tmp1,
1016 src->pixels + (j + 1) * src->stride, src->width, dest->width,
1017 &xacc, x_increment);
1020 vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride,
1021 tmp2, tmp1, dest->width, x);
1024 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride,
1025 src->width, dest->width, &xacc, x_increment);
1028 vs_scanline_resample_linear_RGB555 (tmp2,
1029 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
1032 vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride,
1033 tmp1, tmp2, dest->width, x);
1042 vs_image_scale_nearest_AYUV64 (const VSImage * dest, const VSImage * src,
1052 if (dest->height == 1)
1055 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1057 if (dest->width == 1)
1060 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1065 for (i = 0; i < dest->height; i++) {
1069 memcpy (dest->pixels + i * dest->stride,
1070 dest->pixels + (i - 1) * dest->stride, dest->width * 8);
1073 vs_scanline_resample_nearest_AYUV64 (dest->pixels + i * dest->stride,
1074 src->pixels + j * src->stride, src->width, dest->width, &xacc,
1084 vs_image_scale_linear_AYUV64 (const VSImage * dest, const VSImage * src,
1097 if (dest->height == 1)
1100 y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
1102 if (dest->width == 1)
1105 x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
1107 dest_size = dest->width * 8;
1110 #define LINE(x) ((guint16 *)((tmpbuf) + (dest_size)*((x)&1)))
1113 //gst_videoscale_orc_resample_bilinear_u64 (LINE (0), src->pixels,
1114 // 0, x_increment, dest->width);
1116 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (0),
1117 src->pixels, src->width, dest->width, &xacc, x_increment);
1119 for (i = 0; i < dest->height; i++) {
1124 memcpy (dest->pixels + i * dest->stride, LINE (j), dest_size);
1128 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (j),
1129 src->pixels + j * src->stride, src->width, dest->width, &xacc,
1131 //gst_videoscale_orc_resample_bilinear_u64 (LINE (j),
1132 // src->pixels + j * src->stride, 0, x_increment, dest->width);
1137 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (j + 1),
1138 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
1140 orc_merge_linear_u16 ((guint16 *) (dest->pixels + i * dest->stride),
1141 LINE (j), LINE (j + 1), 65536 - x, x, dest->width * 4);
1142 //gst_videoscale_orc_resample_merge_bilinear_u64 (dest->pixels +
1143 // i * dest->stride, LINE (j + 1), LINE (j),
1144 // src->pixels + (j + 1) * src->stride, (x >> 8), 0, x_increment,
1148 orc_merge_linear_u16 ((guint16 *) (dest->pixels + i * dest->stride),
1149 LINE (j), LINE (j + 1), 65536 - x, x, dest->width * 4);