• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 #             (C) 2010 Hans de Goede <hdegoede@redhat.com>
3 
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU Lesser General Public License as published by
6 # the Free Software Foundation; either version 2.1 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
17  */
18 
19 #include "libv4lconvert-priv.h"
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #define MAGIC_0		0x19
24 #define MAGIC_1		0x68
25 #define SUBSAMPLE_420	0
26 #define SUBSAMPLE_422	1
27 #define YUVORDER_YUYV	0
28 #define YUVORDER_UYVY	1
29 #define NOT_COMPRESSED	0
30 #define COMPRESSED	1
31 #define NO_DECIMATION	0
32 #define DECIMATION_ENAB	1
33 #define EOI		0xff	/* End Of Image */
34 #define EOL		0xfd	/* End Of Line */
35 #define FRAME_HEADER_SIZE	64
36 
37 /* CPIA YUYV (sometimes sort of compressed) */
v4lconvert_cpia1_to_yuv420(struct v4lconvert_data * data,const unsigned char * src,int src_size,unsigned char * dest,int width,int height,int yvu)38 int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data,
39 		const unsigned char *src, int src_size,
40 		unsigned char *dest, int width, int height, int yvu)
41 {
42 	int x, y, ll, compressed;
43 	unsigned char *udest, *vdest;
44 
45 	if (width > 352 || height > 288) {
46 		fprintf(stderr, "FATAL ERROR CPIA1 size > 352x288, please report!\n");
47 		return -1;
48 	}
49 
50 	if (data->previous_frame == NULL) {
51 		data->previous_frame = malloc(352 * 288 * 3 / 2);
52 		if (data->previous_frame == NULL) {
53 			fprintf(stderr, "cpia1 decode error: could not allocate buffer!\n");
54 			return -1;
55 		}
56 	}
57 
58 	if (yvu) {
59 		vdest = dest + width * height;
60 		udest = vdest + width * height / 4;
61 	} else {
62 		udest = dest + width * height;
63 		vdest = udest + width * height / 4;
64 	}
65 
66 	/* Verify header */
67 	if (src_size < FRAME_HEADER_SIZE ||
68 			src[0] != MAGIC_0 || src[1] != MAGIC_1 ||
69 			src[17] != SUBSAMPLE_420 ||
70 			src[18] != YUVORDER_YUYV ||
71 			(src[25] - src[24]) * 8 != width ||
72 			(src[27] - src[26]) * 4 != height ||
73 			(src[28] != NOT_COMPRESSED && src[28] != COMPRESSED) ||
74 			(src[29] != NO_DECIMATION && src[29] != DECIMATION_ENAB)) {
75 		fprintf(stderr, "cpia1 decode error: invalid header\n");
76 		return -1;
77 	}
78 
79 	if (src[29] == DECIMATION_ENAB) {
80 		fprintf(stderr, "cpia1 decode error: decimation is not supported\n");
81 		return -1;
82 	}
83 
84 	compressed = src[28] == COMPRESSED;
85 
86 	src += FRAME_HEADER_SIZE;
87 	src_size -= FRAME_HEADER_SIZE;
88 
89 	if (!compressed) {
90 		for (y = 0; y < height && src_size > 2; y++) {
91 			ll = src[0] | (src[1] << 8);
92 			src += 2;
93 			src_size -= 2;
94 			if (src_size < ll) {
95 				fprintf(stderr, "cpia1 decode error: short frame\n");
96 				return -1;
97 			}
98 			if (src[ll - 1] != EOL) {
99 				fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
100 				return -1;
101 			}
102 
103 			if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
104 				if (ll != 2 * width + 1) {
105 					fprintf(stderr, "cpia1 decode error: invalid uncompressed even ll\n");
106 					return -1;
107 				}
108 
109 				/* copy the Y values */
110 				for (x = 0; x < width; x += 2) {
111 					*dest++ = src[0];
112 					*dest++ = src[2];
113 					src += 4;
114 				}
115 
116 				/* copy the UV values */
117 				src -= 2 * width;
118 				for (x = 0; x < width; x += 2) {
119 					*udest++ = src[1];
120 					*vdest++ = src[3];
121 					src += 4;
122 				}
123 			} else { /* Odd line only Y values */
124 				if (ll != width + 1) {
125 					fprintf(stderr, "cpia1 decode error: invalid uncompressed odd ll\n");
126 					return -1;
127 				}
128 
129 				memcpy(dest, src, width);
130 				dest += width;
131 				src += width;
132 			}
133 			src++; /* Skip EOL */
134 			src_size -= ll;
135 		}
136 	} else { /* compressed */
137 		/* Pre-fill dest with previous frame, as the cpia1 "compression" consists
138 		   of simply ommitting certain pixels */
139 		memcpy(dest, data->previous_frame, width * height * 3 / 2);
140 
141 		for (y = 0; y < height && src_size > 2; y++) {
142 			ll = src[0] | (src[1] << 8);
143 			src += 2;
144 			src_size -= 2;
145 			if (src_size < ll) {
146 				fprintf(stderr, "cpia1 decode error: short frame\n");
147 				return -1;
148 			}
149 			if (src[ll - 1] != EOL) {
150 				fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
151 				return -1;
152 			}
153 
154 			/* Do this now as we use ll as loop variable below */
155 			src_size -= ll;
156 			for (x = 0; x < width && ll > 1; ) {
157 				if (*src & 1) { /* skip N pixels */
158 					int skip = *src >> 1;
159 
160 					if (skip & 1) {
161 						fprintf(stderr, "cpia1 decode error: odd number of pixels to skip");
162 						return -1;
163 					}
164 
165 					if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
166 						dest += skip;
167 						udest += skip / 2;
168 						vdest += skip / 2;
169 					} else { /* Odd line only Y values */
170 						dest += skip;
171 					}
172 					x += skip;
173 					src++;
174 					ll--;
175 				} else {
176 					if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
177 						*dest++ = *src++;
178 						*udest++ = *src++;
179 						*dest++ = *src++;
180 						*vdest++ = *src++;
181 						ll -= 4;
182 					} else { /* Odd line only Y values */
183 						*dest++ = *src++;
184 						*dest++ = *src++;
185 						ll -= 2;
186 					}
187 					x += 2;
188 				}
189 			}
190 			if (ll != 1 || x != width) {
191 				fprintf(stderr, "cpia1 decode error: line length mismatch\n");
192 				return -1;
193 			}
194 			src++; /* Skip EOL */
195 		}
196 	}
197 
198 	if (y != height) {
199 		fprintf(stderr, "cpia1 decode error: frame height mismatch\n");
200 		return -1;
201 	}
202 
203 	if (src_size < 4 || src[src_size - 4] != EOI || src[src_size - 3] != EOI ||
204 			    src[src_size - 2] != EOI || src[src_size - 1] != EOI) {
205 		fprintf(stderr, "cpia1 decode error: invaled EOI marker\n");
206 		return -1;
207 	}
208 
209 	/* Safe frame for decompression of the next frame */
210 	dest -= width * height;
211 	memcpy(data->previous_frame, dest, width * height * 3 / 2);
212 
213 	return 0;
214 }
215