1 /*
2 
3 # RGB / YUV flip/rotate routines
4 
5 #             (C) 2008 Hans de Goede <hdegoede@redhat.com>
6 
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as published by
9 # the Free Software Foundation; either version 2.1 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
20 
21  */
22 
23 #include <string.h>
24 #include "libv4lconvert-priv.h"
25 
v4lconvert_vflip_rgbbgr24(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt)26 static void v4lconvert_vflip_rgbbgr24(unsigned char *src, unsigned char *dest,
27 		struct v4l2_format *fmt)
28 {
29 	int y;
30 
31 	src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
32 	for (y = 0; y < fmt->fmt.pix.height; y++) {
33 		src -= fmt->fmt.pix.bytesperline;
34 		memcpy(dest, src, fmt->fmt.pix.width * 3);
35 		dest += fmt->fmt.pix.width * 3;
36 	}
37 }
38 
v4lconvert_vflip_yuv420(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt)39 static void v4lconvert_vflip_yuv420(unsigned char *src, unsigned char *dest,
40 		struct v4l2_format *fmt)
41 {
42 	int y;
43 
44 	/* First flip the Y plane */
45 	src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline;
46 	for (y = 0; y < fmt->fmt.pix.height; y++) {
47 		src -= fmt->fmt.pix.bytesperline;
48 		memcpy(dest, src, fmt->fmt.pix.width);
49 		dest += fmt->fmt.pix.width;
50 	}
51 
52 	/* Now flip the U plane */
53 	src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline * 5 / 4;
54 	for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
55 		src -= fmt->fmt.pix.bytesperline / 2;
56 		memcpy(dest, src, fmt->fmt.pix.width / 2);
57 		dest += fmt->fmt.pix.width / 2;
58 	}
59 
60 	/* Last flip the V plane */
61 	src += fmt->fmt.pix.height * fmt->fmt.pix.bytesperline / 2;
62 	for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
63 		src -= fmt->fmt.pix.bytesperline / 2;
64 		memcpy(dest, src, fmt->fmt.pix.width / 2);
65 		dest += fmt->fmt.pix.width / 2;
66 	}
67 }
68 
v4lconvert_hflip_rgbbgr24(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt)69 static void v4lconvert_hflip_rgbbgr24(unsigned char *src, unsigned char *dest,
70 		struct v4l2_format *fmt)
71 {
72 	int x, y;
73 
74 	for (y = 0; y < fmt->fmt.pix.height; y++) {
75 		src += fmt->fmt.pix.width * 3;
76 		for (x = 0; x < fmt->fmt.pix.width; x++) {
77 			src -= 3;
78 			dest[0] = src[0];
79 			dest[1] = src[1];
80 			dest[2] = src[2];
81 			dest += 3;
82 		}
83 		src += fmt->fmt.pix.bytesperline;
84 	}
85 }
86 
v4lconvert_hflip_yuv420(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt)87 static void v4lconvert_hflip_yuv420(unsigned char *src, unsigned char *dest,
88 		struct v4l2_format *fmt)
89 {
90 	int x, y;
91 
92 	/* First flip the Y plane */
93 	for (y = 0; y < fmt->fmt.pix.height; y++) {
94 		src += fmt->fmt.pix.width;
95 		for (x = 0; x < fmt->fmt.pix.width; x++)
96 			*dest++ = *--src;
97 		src += fmt->fmt.pix.bytesperline;
98 	}
99 
100 	/* Now flip the U plane */
101 	for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
102 		src += fmt->fmt.pix.width / 2;
103 		for (x = 0; x < fmt->fmt.pix.width / 2; x++)
104 			*dest++ = *--src;
105 		src += fmt->fmt.pix.bytesperline / 2;
106 	}
107 
108 	/* Last flip the V plane */
109 	for (y = 0; y < fmt->fmt.pix.height / 2; y++) {
110 		src += fmt->fmt.pix.width / 2;
111 		for (x = 0; x < fmt->fmt.pix.width / 2; x++)
112 			*dest++ = *--src;
113 		src += fmt->fmt.pix.bytesperline / 2;
114 	}
115 }
116 
v4lconvert_rotate180_rgbbgr24(const unsigned char * src,unsigned char * dst,int width,int height)117 static void v4lconvert_rotate180_rgbbgr24(const unsigned char *src,
118 		unsigned char *dst, int width, int height)
119 {
120 	int i;
121 
122 	src += 3 * width * height - 3;
123 
124 	for (i = 0; i < width * height; i++) {
125 		dst[0] = src[0];
126 		dst[1] = src[1];
127 		dst[2] = src[2];
128 		dst += 3;
129 		src -= 3;
130 	}
131 }
132 
v4lconvert_rotate180_yuv420(const unsigned char * src,unsigned char * dst,int width,int height)133 static void v4lconvert_rotate180_yuv420(const unsigned char *src,
134 		unsigned char *dst, int width, int height)
135 {
136 	int i;
137 
138 	/* First flip x and y of the Y plane */
139 	src += width * height - 1;
140 	for (i = 0; i < width * height; i++)
141 		*dst++ = *src--;
142 
143 	/* Now flip the U plane */
144 	src += width * height * 5 / 4;
145 	for (i = 0; i < width * height / 4; i++)
146 		*dst++ = *src--;
147 
148 	/* Last flip the V plane */
149 	src += width * height / 2;
150 	for (i = 0; i < width * height / 4; i++)
151 		*dst++ = *src--;
152 }
153 
v4lconvert_rotate90_rgbbgr24(const unsigned char * src,unsigned char * dst,int destwidth,int destheight)154 static void v4lconvert_rotate90_rgbbgr24(const unsigned char *src,
155 		unsigned char *dst, int destwidth, int destheight)
156 {
157 	int x, y;
158 #define srcwidth destheight
159 #define srcheight destwidth
160 
161 	for (y = 0; y < destheight; y++)
162 		for (x = 0; x < destwidth; x++) {
163 			int offset = ((srcheight - x - 1) * srcwidth + y) * 3;
164 			*dst++ = src[offset++];
165 			*dst++ = src[offset++];
166 			*dst++ = src[offset];
167 		}
168 }
169 
v4lconvert_rotate90_yuv420(const unsigned char * src,unsigned char * dst,int destwidth,int destheight)170 static void v4lconvert_rotate90_yuv420(const unsigned char *src,
171 		unsigned char *dst, int destwidth, int destheight)
172 {
173 	int x, y;
174 
175 	/* Y-plane */
176 	for (y = 0; y < destheight; y++)
177 		for (x = 0; x < destwidth; x++) {
178 			int offset = (srcheight - x - 1) * srcwidth + y;
179 			*dst++ = src[offset];
180 		}
181 
182 	/* U-plane */
183 	src += srcwidth * srcheight;
184 	destwidth /= 2;
185 	destheight /= 2;
186 	for (y = 0; y < destheight; y++)
187 		for (x = 0; x < destwidth; x++) {
188 			int offset = (srcheight - x - 1) * srcwidth + y;
189 			*dst++ = src[offset];
190 		}
191 
192 	/* V-plane */
193 	src += srcwidth * srcheight;
194 	for (y = 0; y < destheight; y++)
195 		for (x = 0; x < destwidth; x++) {
196 			int offset = (srcheight - x - 1) * srcwidth + y;
197 			*dst++ = src[offset];
198 		}
199 }
200 
v4lconvert_rotate90(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt)201 void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
202 		struct v4l2_format *fmt)
203 {
204 	int tmp;
205 
206 	tmp = fmt->fmt.pix.width;
207 	fmt->fmt.pix.width = fmt->fmt.pix.height;
208 	fmt->fmt.pix.height = tmp;
209 
210 	switch (fmt->fmt.pix.pixelformat) {
211 	case V4L2_PIX_FMT_RGB24:
212 	case V4L2_PIX_FMT_BGR24:
213 		v4lconvert_rotate90_rgbbgr24(src, dest, fmt->fmt.pix.width,
214 				fmt->fmt.pix.height);
215 		break;
216 	case V4L2_PIX_FMT_YUV420:
217 	case V4L2_PIX_FMT_YVU420:
218 		v4lconvert_rotate90_yuv420(src, dest, fmt->fmt.pix.width,
219 				fmt->fmt.pix.height);
220 		break;
221 	}
222 	v4lconvert_fixup_fmt(fmt);
223 }
224 
v4lconvert_flip(unsigned char * src,unsigned char * dest,struct v4l2_format * fmt,int hflip,int vflip)225 void v4lconvert_flip(unsigned char *src, unsigned char *dest,
226 		struct v4l2_format *fmt, int hflip, int vflip)
227 {
228 	if (vflip && hflip) {
229 		switch (fmt->fmt.pix.pixelformat) {
230 		case V4L2_PIX_FMT_RGB24:
231 		case V4L2_PIX_FMT_BGR24:
232 			v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
233 					fmt->fmt.pix.height);
234 			break;
235 		case V4L2_PIX_FMT_YUV420:
236 		case V4L2_PIX_FMT_YVU420:
237 			v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
238 					fmt->fmt.pix.height);
239 			break;
240 		}
241 	} else if (hflip) {
242 		switch (fmt->fmt.pix.pixelformat) {
243 		case V4L2_PIX_FMT_RGB24:
244 		case V4L2_PIX_FMT_BGR24:
245 			v4lconvert_hflip_rgbbgr24(src, dest, fmt);
246 			break;
247 		case V4L2_PIX_FMT_YUV420:
248 		case V4L2_PIX_FMT_YVU420:
249 			v4lconvert_hflip_yuv420(src, dest, fmt);
250 			break;
251 		}
252 	} else if (vflip) {
253 		switch (fmt->fmt.pix.pixelformat) {
254 		case V4L2_PIX_FMT_RGB24:
255 		case V4L2_PIX_FMT_BGR24:
256 			v4lconvert_vflip_rgbbgr24(src, dest, fmt);
257 			break;
258 		case V4L2_PIX_FMT_YUV420:
259 		case V4L2_PIX_FMT_YVU420:
260 			v4lconvert_vflip_yuv420(src, dest, fmt);
261 			break;
262 		}
263 	}
264 
265 	/* Our newly written data has no padding */
266 	v4lconvert_fixup_fmt(fmt);
267 }
268