1 /*
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
6 
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 GNU General Public License for more details.
11 
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16 
17 #include "subtitler.h"
18 
19 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
20 
21 
ppm_to_yuv_in_char(char * pathfilename,int * xsize,int * ysize)22 char *ppm_to_yuv_in_char(char *pathfilename, int *xsize, int *ysize)
23 {
24 /*
25 reads ppm file into buffer in yuyv format.
26 */
27 char *out_ptr;
28 int c, i, j;
29 int r, g, b;
30 int width = 0, height = 0, maxval = 0;
31 double y, u, v;
32 double cr, cg, cb, cu, cv;
33 char temp[4096];
34 FILE *fptr;
35 int u_time;
36 char *buffer;
37 int comment_flag;
38 
39 /* color standard */
40 /* Y spec */
41 cr = 0.3;
42 cg = 0.59;
43 cb = 0.11;
44 
45 /* U spec */
46 cu = .5 / (1.0 - cb);
47 
48 /* V spec */
49 cv = .5 / (1.0 - cr);
50 
51 /* open the ppm format file */
52 fptr = fopen(pathfilename, "rb");
53 if(!fptr)
54 	{
55 	tc_log_msg(MOD_NAME, "subtitler(): ppm_to_yuv_in_char(): could not open file %s for read\n", pathfilename);
56 
57 	strerror(errno);
58 	return 0;
59 	}
60 
61 /*
62 cjpeg writes like this:
63  "P6\n%ld %ld\n%d\n"
64 */
65 
66 /*
67 display writes like this:
68 P6
69 # CREATOR: XV Version 3.10a  Rev: 12/29/94
70 
71 125 107
72 255
73 */
74 
75 /*
76 using fscanf here swallows control M after \n,
77 resulting in wrong color, perhaps a libc bug?
78 */
79 
80 /* parse the header */
81 i = 0;
82 j = 0;
83 comment_flag = 0;
84 while(1)
85 	{
86 	while(1)
87 		{
88 		errno = 0;
89 		c = getc(fptr);
90 		if(errno == EAGAIN) continue;
91 		if(errno == EINTR) continue;
92 		break;
93 		}
94 	if(c == EOF)
95 		{
96 		fclose(fptr);
97 		tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): early EOF in header\n");
98 		return 0;
99 		}
100 
101 	if(c == '#') comment_flag = 1;
102 
103 	if( (c == '\n') || (c == '\r') ) comment_flag = 0;
104 
105 	if(comment_flag) continue;
106 
107 	temp[i] = c;
108 	if( (c == '\n') || (c == '\t') || (c == '\r') || (c == ' ') )
109 		{
110 		temp[i] = 0;
111 //tc_log_msg(MOD_NAME, "j=%d i=%d temp=%s\n", j, i, temp);
112 
113 		/* test if a field present in line */
114 		if(i != 0)
115 			{
116 			if(j == 0) {}; /* scip the P6 */
117 			if(j == 1) width = atoi(temp);
118 			if(j == 2) height = atoi(temp);
119 			if(j == 3) maxval = atoi(temp);
120 			j++;
121 			}
122 		i = 0;
123 		}/* end if white space */
124 	else i++;
125 	if(j == 4) break;
126 	}/* end for all chars in header */
127 
128 if(debug_flag)
129 	{
130 	tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): width=%d height=%d maxval=%d\n",\
131 	width, height, maxval);
132 	}
133 
134 *xsize = width;
135 *ysize = height;
136 
137 buffer = (char *) malloc(width * height * 3); // should be 2 ?
138 if(! buffer)
139 	{
140 	tc_log_msg(MOD_NAME, "subtitler(): ppm_to_yuv_in_char(): malloc buffer failed\n");
141 
142 	return 0;
143 	}
144 
145 out_ptr = buffer;
146 
147 for (i = 0; i < height; i++)
148 	{
149 	/* write Y, U, Y, V */
150 	if(debug_flag)
151 		{
152 		tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): i=%d j=%d\n", i, j);
153 		}
154 
155 	u_time = 1;
156 	for(j = 0; j < width; j++)
157 		{
158 		/* red */
159 		while(1)
160 			{
161 			errno = 0;
162 			r = getc(fptr);
163 			if(errno == EAGAIN) continue;
164 			if(errno == EINTR) continue;
165 			break;
166 			}
167 
168 		if(r == EOF)
169 			{
170 			tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): early EOF r\n");
171 			/*
172 			this is a hack to fix early EOF in the output from cjpeg
173 			Substitute black.
174 			*/
175 			r = 0;
176 /*			break;*/
177 
178 			}
179 
180 		/* green */
181 		while(1)
182 			{
183 			errno = 0;
184 			g = getc(fptr);
185 			if(errno == EAGAIN) continue;
186 			if(errno == EINTR) continue;
187 			break;
188 			}
189 		if(g == EOF)
190 			{
191 			tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): early EOF g\n");
192 			g = 0;
193 /*			break;*/
194 			}
195 
196 		/* blue */
197 		while(1)
198 			{
199 			errno = 0;
200 			b = getc(fptr);
201 			if(errno == EAGAIN) continue;
202 			if(errno == EINTR) continue;
203 			break;
204 			}
205 		if(b == EOF)
206 			{
207 			tc_log_msg(MOD_NAME, "ppm_to_yuv_in_char(): early EOF b\n");
208 			b = 0;
209 /*			break;*/
210 			}
211 
212 		/* convert to YUV */
213 
214 		/* test yuv coding here */
215 		y = cr * r + cg * g + cb * b;
216 
217 		y = (219.0 / 256.0) * y + 16.5;  /* nominal range: 16..235 */
218 
219 		*out_ptr = y;
220 		out_ptr++;
221 
222 		if(u_time)
223 			{
224 			u = cu * (b - y);
225 			u = (224.0 / 256.0) * u + 128.5; /* 16..240 */
226 
227 			*out_ptr = u;
228 			}
229 		else
230 			{
231 			v = cv * (r - y);
232 			v = (224.0 / 256.0) * v + 128.5; /* 16..240 */
233 
234 			*out_ptr = v;
235 			}
236 
237 		out_ptr++;
238 		u_time = 1 - u_time;
239 		}/* end for j horizontal */
240 
241 	}/* end for i vertical */
242 
243 /* close the input file */
244 fclose(fptr);
245 
246 return buffer;
247 }/* end function ppm_to_yuv_in_char */
248 
249 
yuv_to_ppm(char * data,int xsize,int ysize,char * filename)250 int yuv_to_ppm(char *data, int xsize, int ysize, char *filename)
251 {
252 /*
253 creates a .ppm format file from a YUYV character buffer.
254 */
255 int x, y;
256 FILE *fptr;
257 char *py, *pu, *pv;
258 int cr, cg, cb, cy, cu = 0, cv = 0;
259 int r, g, b;
260 int u_time;
261 int odd_line;
262 int odd_xsize;
263 
264 if(debug_flag)
265 	{
266 	tc_log_msg(MOD_NAME, "subtitler(): yuv_to_ppm(): arg data=%lu\n\
267 	xsize=%d ysize=%d filename=%s\n",\
268 	(unsigned long)data, xsize, ysize, filename);
269 	}
270 
271 /* open ppm file */
272 fptr = fopen(filename, "w");
273 if(! fptr)
274 	{
275 	tc_log_msg(MOD_NAME, "subtitler(): yuv_to_ppm(): could not open %s for write\n",\
276 	filename);
277 
278 	return 0;
279 	}
280 
281 /* write a ppm header */
282 fprintf(fptr, "P6\n%i %i\n255\n", xsize, ysize);
283 
284 /* YUYVYUYV */
285 py = data;
286 pu = data + 1;
287 pv = data + 3;
288 u_time = 1;
289 odd_xsize = xsize % 2;
290 
291 for(y = 0; y < ysize; y++)
292 	{
293 	odd_line = y % 2;
294 
295 	/* get a line from buffer start */
296 	for(x = 0; x < xsize; x++)
297 		{
298 		/* calculate RGB */
299 		cy = ( (0xff & *py) - 16);
300 
301 		/*
302 		prevent data to be cut away, by replacing it with the nearest.
303 		Normally the variable border_luminance is set to greater then 255,
304 		(so a value that will never happen) except in rotate and shear,
305 		where we use this luminance level to cut away the left over edges
306 		of the picture after mogrify processes it.
307 		*/
308 		/* do not use top white or greater for mask */
309 		if(cy != 255)
310 			{
311 			if(cy == YUV_MASK) cy += 1;
312 			}
313 
314 		cy  *= 76310;
315 
316 		/* increment Y pointer */
317 		py += 2;
318 
319 		if(u_time)
320 			{
321 			if(odd_xsize)
322 				{
323 				if(! odd_line)
324 					{
325 					cu = (0xff & *pu) - 128;
326 					cv = (0xff & *pv) - 128;
327 					}
328 				else /* even line */
329 					{
330 					cu = (0xff & *pv) - 128;
331 					cv = (0xff & *pu) - 128;
332 					}
333 				}
334 			else /* even xsize */
335 				{
336 				cu = (0xff & *pu) - 128;
337 				cv = (0xff & *pv) - 128;
338 				}
339 
340 			pu += 4;
341 			pv += 4;
342 			}
343 
344 		cr = 104635 * cv;
345 		cg = -25690 * cu + -53294 * cv;
346 		cb = 132278 * cu;
347 
348 		r = LIMIT(cr + cy);
349 		g = LIMIT(cg + cy);
350 		b = LIMIT(cb + cy);
351 
352 		/* RGB to file */
353 		fprintf(fptr,\
354 		"%c%c%c", r, g, b);
355 
356 		u_time = 1 - u_time;
357 		} /* end for all x */
358 	} /* end for all y */
359 
360 /* close output file */
361 fclose(fptr);
362 
363 return 1;
364 } /* end function yuv_to_ppm */
365 
366