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,
94 if (dest->height == 1)
97 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
102 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
104 dest_size = dest->width * 4;
106 #define LINE(x) ((tmpbuf) + (dest_size)*((x)&1))
110 gst_videoscale_orc_resample_bilinear_u32 (LINE (0), src->pixels,
111 0, x_increment, dest->width);
113 for (i = 0; i < dest->height; i++) {
118 memcpy (dest->pixels + i * dest->stride, LINE (j), dest_size);
121 gst_videoscale_orc_resample_bilinear_u32 (LINE (j),
122 src->pixels + j * src->stride, 0, x_increment, dest->width);
126 gst_videoscale_orc_resample_merge_bilinear_u32 (dest->pixels +
127 i * dest->stride, LINE (j + 1), LINE (j),
128 src->pixels + (j + 1) * src->stride, (x >> 8), 0, x_increment,
132 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
133 LINE (j), LINE (j + 1), (x >> 8), dest->width * 4);
143 vs_image_scale_nearest_RGB (const VSImage * dest, const VSImage * src,
153 if (dest->height == 1)
156 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
158 if (dest->width == 1)
161 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
164 for (i = 0; i < dest->height; i++) {
168 vs_scanline_resample_nearest_RGB (dest->pixels + i * dest->stride,
169 src->pixels + j * src->stride, src->width, dest->width, &xacc,
177 vs_image_scale_linear_RGB (const VSImage * dest, const VSImage * src,
193 if (dest->height == 1)
196 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
198 if (dest->width == 1)
201 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
203 dest_size = dest->width * 3;
206 tmp2 = tmpbuf + dest_size;
211 vs_scanline_resample_linear_RGB (tmp1, src->pixels, src->width, dest->width,
214 for (i = 0; i < dest->height; i++) {
220 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
221 } else if (j == y2) {
222 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
225 vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride,
226 src->width, dest->width, &xacc, x_increment);
228 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
234 vs_scanline_resample_linear_RGB (tmp2,
235 src->pixels + (j + 1) * src->stride, src->width, dest->width,
239 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
240 tmp1, tmp2, dest->width, x);
241 } else if (j == y2) {
244 vs_scanline_resample_linear_RGB (tmp1,
245 src->pixels + (j + 1) * src->stride, src->width, dest->width,
249 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
250 tmp2, tmp1, dest->width, x);
253 vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride,
254 src->width, dest->width, &xacc, x_increment);
257 vs_scanline_resample_linear_RGB (tmp2,
258 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
261 vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride,
262 tmp1, tmp2, dest->width, x);
273 vs_image_scale_nearest_YUYV (const VSImage * dest, const VSImage * src,
283 if (dest->height == 1)
286 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
288 if (dest->width == 1)
291 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
294 for (i = 0; i < dest->height; i++) {
298 vs_scanline_resample_nearest_YUYV (dest->pixels + i * dest->stride,
299 src->pixels + j * src->stride, src->width, dest->width, &xacc,
307 vs_image_scale_linear_YUYV (const VSImage * dest, const VSImage * src,
323 if (dest->height == 1)
326 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
328 if (dest->width == 1)
331 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
333 dest_size = ROUND_UP_4 (dest->width * 2);
336 tmp2 = tmpbuf + dest_size;
341 vs_scanline_resample_linear_YUYV (tmp1, src->pixels, src->width, dest->width,
344 for (i = 0; i < dest->height; i++) {
350 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
351 } else if (j == y2) {
352 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
355 vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride,
356 src->width, dest->width, &xacc, x_increment);
358 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
364 vs_scanline_resample_linear_YUYV (tmp2,
365 src->pixels + (j + 1) * src->stride, src->width, dest->width,
369 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
370 tmp1, tmp2, dest->width, x);
371 } else if (j == y2) {
374 vs_scanline_resample_linear_YUYV (tmp1,
375 src->pixels + (j + 1) * src->stride, src->width, dest->width,
379 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
380 tmp2, tmp1, dest->width, x);
383 vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride,
384 src->width, dest->width, &xacc, x_increment);
387 vs_scanline_resample_linear_YUYV (tmp2,
388 src->pixels + (j + 1) * src->stride, src->width, dest->width,
391 vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride,
392 tmp1, tmp2, dest->width, x);
403 vs_image_scale_nearest_UYVY (const VSImage * dest, const VSImage * src,
413 if (dest->height == 1)
416 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
418 if (dest->width == 1)
421 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
424 for (i = 0; i < dest->height; i++) {
428 vs_scanline_resample_nearest_UYVY (dest->pixels + i * dest->stride,
429 src->pixels + j * src->stride, src->width, dest->width, &xacc,
437 vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src,
453 if (dest->height == 1)
456 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
458 if (dest->width == 1)
461 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
463 dest_size = ROUND_UP_4 (dest->width * 2);
466 tmp2 = tmpbuf + dest_size;
471 vs_scanline_resample_linear_UYVY (tmp1, src->pixels, src->width, dest->width,
474 for (i = 0; i < dest->height; i++) {
480 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
481 } else if (j == y2) {
482 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
485 vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride,
486 src->width, dest->width, &xacc, x_increment);
488 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
494 vs_scanline_resample_linear_UYVY (tmp2,
495 src->pixels + (j + 1) * src->stride, src->width, dest->width,
499 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
500 tmp1, tmp2, dest->width, x);
501 } else if (j == y2) {
504 vs_scanline_resample_linear_UYVY (tmp1,
505 src->pixels + (j + 1) * src->stride, src->width, dest->width,
509 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
510 tmp2, tmp1, dest->width, x);
513 vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride,
514 src->width, dest->width, &xacc, x_increment);
517 vs_scanline_resample_linear_UYVY (tmp2,
518 src->pixels + (j + 1) * src->stride, src->width, dest->width,
521 vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride,
522 tmp1, tmp2, dest->width, x);
533 vs_image_scale_nearest_Y (const VSImage * dest, const VSImage * src,
542 if (dest->height == 1)
545 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
547 if (dest->width == 1)
550 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
553 for (i = 0; i < dest->height; i++) {
556 gst_videoscale_orc_resample_nearest_u8 (dest->pixels + i * dest->stride,
557 src->pixels + j * src->stride, 0, x_increment, dest->width);
563 vs_image_scale_linear_Y (const VSImage * dest, const VSImage * src,
579 if (dest->height == 1)
582 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
584 if (dest->width == 1)
587 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
589 dest_size = dest->width;
592 tmp2 = tmpbuf + dest_size;
597 gst_videoscale_orc_resample_bilinear_u8 (tmp1, src->pixels,
598 0, x_increment, dest->width);
600 for (i = 0; i < dest->height; i++) {
606 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
607 } else if (j == y2) {
608 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
611 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
612 src->pixels + j * src->stride, 0, x_increment, dest->width);
614 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
620 gst_videoscale_orc_resample_bilinear_u8 (tmp2,
621 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
625 memcpy (dest->pixels + i * dest->stride, tmp1, dest->width);
627 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
628 tmp1, tmp2, (x >> 8), dest->width);
630 } else if (j == y2) {
633 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
634 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
638 memcpy (dest->pixels + i * dest->stride, tmp2, dest->width);
640 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
641 tmp2, tmp1, (x >> 8), dest->width);
644 gst_videoscale_orc_resample_bilinear_u8 (tmp1,
645 src->pixels + j * src->stride, 0, x_increment, dest->width);
647 gst_videoscale_orc_resample_bilinear_u8 (tmp2,
648 src->pixels + (j + 1) * src->stride, 0, x_increment, dest->width);
651 memcpy (dest->pixels + i * dest->stride, tmp1, dest->width);
653 orc_merge_linear_u8 (dest->pixels + i * dest->stride,
654 tmp1, tmp2, (x >> 8), dest->width);
664 vs_image_scale_nearest_Y16 (const VSImage * dest, const VSImage * src,
674 if (dest->height == 1)
677 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
679 if (dest->width == 1)
682 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
685 for (i = 0; i < dest->height; i++) {
689 vs_scanline_resample_nearest_Y16 (dest->pixels + i * dest->stride,
690 src->pixels + j * src->stride, src->width, dest->width, &xacc,
698 vs_image_scale_linear_Y16 (const VSImage * dest, const VSImage * src,
714 if (dest->height == 1)
717 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
719 if (dest->width == 1)
722 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
724 dest_size = 2 * dest->width;
727 tmp2 = tmpbuf + dest_size;
732 vs_scanline_resample_linear_Y16 (tmp1, src->pixels, src->width, dest->width,
735 for (i = 0; i < dest->height; i++) {
741 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
742 } else if (j == y2) {
743 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
746 vs_scanline_resample_linear_Y16 (tmp1, src->pixels + j * src->stride,
747 src->width, dest->width, &xacc, x_increment);
749 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
755 vs_scanline_resample_linear_Y16 (tmp2,
756 src->pixels + (j + 1) * src->stride, src->width, dest->width,
760 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
761 tmp1, tmp2, dest->width, x);
762 } else if (j == y2) {
765 vs_scanline_resample_linear_Y16 (tmp1,
766 src->pixels + (j + 1) * src->stride, src->width, dest->width,
770 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
771 tmp2, tmp1, dest->width, x);
774 vs_scanline_resample_linear_Y16 (tmp1, src->pixels + j * src->stride,
775 src->width, dest->width, &xacc, x_increment);
778 vs_scanline_resample_linear_Y16 (tmp2,
779 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
782 vs_scanline_merge_linear_Y16 (dest->pixels + i * dest->stride,
783 tmp1, tmp2, dest->width, x);
794 vs_image_scale_nearest_RGB565 (const VSImage * dest, const VSImage * src,
804 if (dest->height == 1)
807 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
809 if (dest->width == 1)
812 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
815 for (i = 0; i < dest->height; i++) {
819 vs_scanline_resample_nearest_RGB565 (dest->pixels + i * dest->stride,
820 src->pixels + j * src->stride, src->width, dest->width, &xacc,
828 vs_image_scale_linear_RGB565 (const VSImage * dest, const VSImage * src,
844 if (dest->height == 1)
847 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
849 if (dest->width == 1)
852 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
854 dest_size = dest->width * 2;
857 tmp2 = tmpbuf + dest_size;
862 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels, src->width,
863 dest->width, &xacc, x_increment);
865 for (i = 0; i < dest->height; i++) {
871 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
872 } else if (j == y2) {
873 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
876 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride,
877 src->width, dest->width, &xacc, x_increment);
879 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
885 vs_scanline_resample_linear_RGB565 (tmp2,
886 src->pixels + (j + 1) * src->stride, src->width, dest->width,
890 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
891 tmp1, tmp2, dest->width, x);
892 } else if (j == y2) {
895 vs_scanline_resample_linear_RGB565 (tmp1,
896 src->pixels + (j + 1) * src->stride, src->width, dest->width,
900 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
901 tmp2, tmp1, dest->width, x);
904 vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride,
905 src->width, dest->width, &xacc, x_increment);
908 vs_scanline_resample_linear_RGB565 (tmp2,
909 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
912 vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride,
913 tmp1, tmp2, dest->width, x);
924 vs_image_scale_nearest_RGB555 (const VSImage * dest, const VSImage * src,
934 if (dest->height == 1)
937 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
939 if (dest->width == 1)
942 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
945 for (i = 0; i < dest->height; i++) {
949 vs_scanline_resample_nearest_RGB555 (dest->pixels + i * dest->stride,
950 src->pixels + j * src->stride, src->width, dest->width, &xacc,
958 vs_image_scale_linear_RGB555 (const VSImage * dest, const VSImage * src,
974 if (dest->height == 1)
977 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
979 if (dest->width == 1)
982 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
984 dest_size = dest->width * 2;
987 tmp2 = tmpbuf + dest_size;
992 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels, src->width,
993 dest->width, &xacc, x_increment);
995 for (i = 0; i < dest->height; i++) {
1001 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
1002 } else if (j == y2) {
1003 memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
1006 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride,
1007 src->width, dest->width, &xacc, x_increment);
1009 memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
1015 vs_scanline_resample_linear_RGB555 (tmp2,
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 tmp1, tmp2, dest->width, x);
1022 } else if (j == y2) {
1025 vs_scanline_resample_linear_RGB555 (tmp1,
1026 src->pixels + (j + 1) * src->stride, src->width, dest->width,
1027 &xacc, x_increment);
1030 vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride,
1031 tmp2, tmp1, dest->width, x);
1034 vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride,
1035 src->width, dest->width, &xacc, x_increment);
1038 vs_scanline_resample_linear_RGB555 (tmp2,
1039 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
1042 vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride,
1043 tmp1, tmp2, dest->width, x);
1052 vs_image_scale_nearest_AYUV64 (const VSImage * dest, const VSImage * src,
1062 if (dest->height == 1)
1065 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1067 if (dest->width == 1)
1070 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1075 for (i = 0; i < dest->height; i++) {
1079 memcpy (dest->pixels + i * dest->stride,
1080 dest->pixels + (i - 1) * dest->stride, dest->width * 8);
1083 vs_scanline_resample_nearest_AYUV64 (dest->pixels + i * dest->stride,
1084 src->pixels + j * src->stride, src->width, dest->width, &xacc,
1094 vs_image_scale_linear_AYUV64 (const VSImage * dest, const VSImage * src,
1108 if (dest->height == 1)
1111 y_increment = ((src->height - 1) << 16) / (dest->height - 1);
1113 if (dest->width == 1)
1116 x_increment = ((src->width - 1) << 16) / (dest->width - 1);
1118 dest_size = dest->width * 8;
1121 #define LINE(x) ((guint16 *)((tmpbuf) + (dest_size)*((x)&1)))
1125 //gst_videoscale_orc_resample_bilinear_u64 (LINE (0), src->pixels,
1126 // 0, x_increment, dest->width);
1128 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (0),
1129 src->pixels, src->width, dest->width, &xacc, x_increment);
1131 for (i = 0; i < dest->height; i++) {
1136 memcpy (dest->pixels + i * dest->stride, LINE (j), dest_size);
1140 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (j),
1141 src->pixels + j * src->stride, src->width, dest->width, &xacc,
1143 //gst_videoscale_orc_resample_bilinear_u64 (LINE (j),
1144 // src->pixels + j * src->stride, 0, x_increment, dest->width);
1149 vs_scanline_resample_linear_AYUV64 ((guint8 *) LINE (j + 1),
1150 src->pixels + (j + 1) * src->stride, src->width, dest->width, &xacc,
1152 orc_merge_linear_u16 ((guint16 *) (dest->pixels + i * dest->stride),
1153 LINE (j), LINE (j + 1), 65536 - x, x, dest->width * 4);
1154 //gst_videoscale_orc_resample_merge_bilinear_u64 (dest->pixels +
1155 // i * dest->stride, LINE (j + 1), LINE (j),
1156 // src->pixels + (j + 1) * src->stride, (x >> 8), 0, x_increment,
1160 orc_merge_linear_u16 ((guint16 *) (dest->pixels + i * dest->stride),
1161 LINE (j), LINE (j + 1), 65536 - x, x, dest->width * 4);