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