1 /*
2  *  filter_subtitler.c
3  *
4  *  Copyright (C) Jan Panteltje  2001
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *  Font reading etc from Linux mplayer
8  *
9  *  transcode is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2, or (at your option)
12  *  any later version.
13  *
14  *  transcode is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with GNU Make; see the file COPYING.  If not, write to
21  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24 
25 
26 #include "subtitler.h"
27 
28 
29 /* for YUV to RGB in X11 */
30 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
31 int write_ppm_flag;
32 
33 int debug_flag;
34 int frame_offset;
35 font_desc_t *vo_font;
36 font_desc_t *subtitle_current_font_descriptor;
37 uint8_t *ImageData;
38 int image_width, image_height;
39 int default_font;
40 struct passwd *userinfo;
41 char *home_dir;
42 char *user_name;
43 int line_h_start, line_h_end;
44 int center_flag;
45 char *frame_memory0, *frame_memory1;
46 char *subtitle_file;
47 char *default_font_dir;
48 vob_t *vob;
49 double dmax_vector;
50 int use_pre_processing_flag;
51 char *subtitle_font_path;
52 char *default_subtitle_font_name;
53 int default_subtitle_symbols;
54 int default_subtitle_font_size;
55 int default_subtitle_iso_extention;
56 double default_subtitle_radius;
57 double default_subtitle_thickness;
58 
59 int show_output_flag;
60 int window_open_flag;
61 int window_size;
62 unsigned char *ucptrs, *ucptrd;
63 int color_depth;
64 
65 double default_font_factor;
66 double subtitle_extra_character_space;
67 
68 int border_luminance;
69 int default_border_luminance;
70 
71 double subtitle_h_factor;
72 double subtitle_v_factor;
73 double extra_character_space;
74 
75 int rgb_palette[16][3]; // rgb
76 int rgb_palette_valid_flag;
77 
78 int default_subtitle_font_symbols;
79 
80 int dcontrast, brightness;
81 double dsaturation;
82 double dhue, dhue_line_drift;
83 int u_shift, v_shift;
84 int slice_level;
85 
86 int add_objects_flag;
87 int help_flag;
88 int de_stripe_flag;
89 
90 int movie_id;
91 
92 static double acr, acg, acb, acu, acv;
93 static int use_emphasis2_for_anti_aliasing_flag;
94 
95 extern int add_objects(int);
96 extern int execute(char *);
97 
98 /*
99 subtitle 'filter',
100 it adds objects as described in a file in .ppml format,
101 */
tc_filter(frame_list_t * pfl_,char * options)102 int tc_filter(frame_list_t *pfl_, char *options)
103 {
104 vframe_list_t *pfl = (vframe_list_t *)pfl_;
105 int a, i, x;
106 double da, db;
107 int pre = 0;
108 int vid = 0;
109 static FILE *pppm_file;
110 static FILE *fptr;
111 char temp[4096];
112 static int frame_nr;
113 static uint8_t *pfm, *opfm, *pfmend, *opfmend;
114 static uint8_t *pline_start, *pline_end, *opline_start, *opline_end;
115 static int x_shift;
116 char *running;
117 char *token;
118 static int y, b;
119 uint8_t *py, *pu, *pv;
120 static int cr, cg, cb, cy, cu, cv;
121 static int have_bottom_margin_flag;
122 //aframe_list_t *afl;
123 
124 
125 if (pfl->tag & TC_FILTER_GET_CONFIG) {
126       optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Panteltje", "VRYO", "1");
127       return 0;
128 }
129 
130 /* filter init */
131 if(pfl->tag & TC_FILTER_INIT)
132 	{
133 	vob = tc_get_vob();
134 	if(! vob)
135 		{
136 		tc_log_error(MOD_NAME, "could not tc_get_vob() failed");
137 
138 		return -1;
139 		}
140 	if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
141 
142 	/* identify */
143     tc_log_info(MOD_NAME,
144         "Panteltje (c) movie composer%s (alias subtitle-filter)",
145     	SUBTITLER_VERSION);
146 
147 	/* get home directory */
148 	userinfo = getpwuid(getuid() );
149 	home_dir = strsave(userinfo -> pw_dir);
150 	user_name = strsave(userinfo -> pw_name);
151 
152 	/* set some defaults */
153 
154 	/* for subtitles */
155 
156 	/* use post processing */
157 	use_pre_processing_flag = 0;
158 
159 	/* a frame in transcode is 40 ms */
160 	frame_offset = 0;
161 
162 	/* this selects some other symbols it seems */
163 	default_font = 0;	// 1 = strange symbols like stars etc..
164 
165 	/* this sets the font outline */
166 	default_font_factor = 10.75;	// outline, was .75
167 
168 	/* this sets the horizontal space for the subtitles */
169 	subtitle_h_factor = SUBTITLE_H_FACTOR;
170 
171 	/* this sets how far the subtitles start from the bottom */
172 	subtitle_v_factor = SUBTITLE_V_FACTOR;
173 
174 	/* location where font.descr is */
175 	tc_snprintf(temp, sizeof(temp), "%s/.xste/fonts", home_dir);
176 	default_font_dir = strsave(temp);
177 	if(! default_font_dir)
178 		{
179 		tc_log_error(MOD_NAME, "subtitler(): could not allocate space for default_font_dir");
180 
181 		return -1;
182 		}
183 
184 	/*
185 	the mplayer font seems to overlap getween 'l' and 't', added some
186 	extra space between characters
187 	*/
188 	extra_character_space = EXTRA_CHAR_SPACE;
189 	subtitle_extra_character_space = EXTRA_CHAR_SPACE;
190 
191 	/* the ppml file */
192 	tc_snprintf(temp, sizeof(temp), "%s/.subtitles/demo.ppml", home_dir);
193 	subtitle_file = strsave(temp);
194 	if(! subtitle_file)
195 		{
196 		tc_log_error(MOD_NAME,
197 		"subtitler(): could not allocate space for subtitle_file");
198 
199 		return -1;
200 		}
201 
202 	/* for picture adjust */
203 	brightness = 0;			// steps
204 	dcontrast = 100.0;		// percent
205 	dsaturation = 100.0;	// percent
206 	u_shift = 0;			// steps
207 	v_shift = 0;			// steps
208 
209 	/* for color correction */
210 	dhue = 0.0;
211 	dhue_line_drift = 0.0;	// The rotation in degrees at the start and end
212 							// of a line.
213 							// This is for correcting color errors in NTSC
214 							// tapes.
215 							// Use in combination with dhue in color
216 							// correction.
217 
218 
219 	/* for show output in X11 */
220 	window_open_flag = 0;
221 	color_depth = 0; /* get from X */
222 
223 	/* module settings */
224 	add_objects_flag = 1;
225 	de_stripe_flag = 0;
226 	write_ppm_flag = 0;
227 	show_output_flag = 0;
228 	center_flag = 1;
229 
230 	/* uses when we call transcode recursive, to run a movie in a movie */
231 	movie_id = 0;
232 
233 	/* for chroma key, better do this not each pixel .. */
234 	dmax_vector = sqrt( (127.0 * 127.0) + (127.0 * 127.0) );
235 
236 	/*
237 	for rotate and shear, the level we cut the remaining parts.
238 	Note that yuv_to_ppm() also uses this, to write a modified .ppm
239 	that does NOT have this luminance in it, for use by mogrify.
240 	This ONLY happens if rotate or shear present.
241 	*/
242 	default_border_luminance = LUMINANCE_MASK;
243 
244 	tc_snprintf(temp, sizeof(temp), "%s/.xste/fonts", home_dir);
245 	subtitle_font_path = strsave(temp);
246 	if(! subtitle_font_path)
247 		{
248 		tc_log_error(MOD_NAME,
249 		"subtitler: tc_filter(): could not allocate space for subtitle_font_path, aborting");
250 
251 		exit(1);
252 		}
253 
254 	default_subtitle_font_name = strsave("arial.ttf");
255 	if(! default_subtitle_font_name)
256 		{
257 		tc_log_error(MOD_NAME,
258 		"subtitler: tc_filter(): could not allocate space for default_subtitle_font_name, aborting");
259 
260 		exit(1);
261 		}
262 
263 	default_subtitle_symbols = 0;
264 	default_subtitle_font_size = 28;
265 	default_subtitle_iso_extention = 15;
266 	default_subtitle_radius = 1.0;
267 	default_subtitle_thickness = 0.1;
268 
269 	default_subtitle_font_symbols = 0;
270 
271 	rgb_palette_valid_flag = 0;
272 
273 	/* color standard */
274 
275 	/* Y spec */
276 	acr = 0.3;
277 	acg = 0.59;
278 	acb = 0.11;
279 
280 	/* U spec */
281 	acu = .5 / (1.0 - acb);
282 
283 	/* V spec */
284 	acv = .5 / (1.0 - acr);
285 
286 	use_emphasis2_for_anti_aliasing_flag = 0;
287 
288 	debug_flag = 0;
289 
290 	/* end defaults */
291 	if(debug_flag)
292 		{
293 		tc_log_info(MOD_NAME, "options=%s", options);
294 		}
295 
296 	if(temp[0] != 0)
297 		{
298 		running = strsave(options);
299 		if(! running)
300 			{
301 			tc_log_error(MOD_NAME, "subtitler(): strsave(options) failed");
302 
303 			return -1;
304 			}
305 		while(1)
306 			{
307 			token = strsep (&running, " ");
308 			if(token == NULL) break;
309 
310 			/* avoid empty string */
311 			if(token[0] == 0) continue;
312 
313 			if(strncmp(token, "no_objects", 10) == 0)
314 				{
315 				add_objects_flag = 0;
316 				}
317 			else if(strncmp(token, "write_ppm", 9) == 0)
318 				{
319  				write_ppm_flag = 1;
320 				}
321 			else if(strncmp(token, "debug", 5) == 0)
322 				{
323 				debug_flag = 1;
324 				}
325 			else if(strncmp(token, "help", 4) == 0)
326 				{
327 				help_flag = 1;
328 				print_options();
329 
330 				/* error exit */
331 				return 0;
332 				//exit(1);
333 				}
334 			 else if(strncmp(token, "subtitle_file=", 14) == 0)
335 				{
336 				a = sscanf(token, "subtitle_file=%s", temp);
337 				if(a == 1)
338 					{
339 					free(subtitle_file);
340 					subtitle_file = strsave(temp);
341 					if(! subtitle_file)
342 						{
343 						tc_log_error(MOD_NAME,
344 			"subtitler(): could not allocate space for subtitle_file");
345 
346 						return -1;
347 						}
348 					}
349 				}
350 			else if(strncmp(token, "font_dir=", 9) == 0)
351 				{
352 				a = sscanf(token, "font_dir=%s", temp);
353 				if(a == 1)
354 					{
355 					free(default_font_dir);
356 					default_font_dir = strsave(temp);
357 					if(! default_font_dir)
358 						{
359 						tc_log_error(MOD_NAME,
360 			"subtitler(): could not allocate space for default_font_dir");
361 
362 						return -1;
363 						}
364 					}
365 				}
366 			sscanf(token, "color_depth=%d", &color_depth);
367 			sscanf(token, "font=%d", &default_font);
368 			sscanf(token, "font_factor=%lf", &default_font_factor);
369 			sscanf(token, "frame_offset=%d", &frame_offset);
370 			sscanf(token, "movie_id=%d", &movie_id);
371 
372 			if(strcmp(token, "anti_alias") == 0) use_emphasis2_for_anti_aliasing_flag = 1;
373 
374 			if(strcmp(token, "use_pre_processing") == 0)
375 				{
376 				use_pre_processing_flag = 1;
377 				}
378 			} /* end while parse options */
379 
380 		free(running);
381 		} /* end if options */
382 
383 	if(use_pre_processing_flag)
384 		{
385 		tc_log_info(MOD_NAME, "Using pre processing");
386 		}
387 	else
388 		{
389 		tc_log_info(MOD_NAME, "Using post processing");
390 		}
391 
392 	if(debug_flag)
393 		{
394 		tc_log_info(MOD_NAME, "PARSER RESULT: "
395 		"write_ppm_flag=%d add_objects_flag=%d show_output_flag=%d "
396 		"color_depth=%d frame_offset=%d movie_id=%d "
397 		"use_pre_processing_flag=%d",
398 		write_ppm_flag, add_objects_flag, show_output_flag,\
399 		color_depth, frame_offset, movie_id,\
400 		use_pre_processing_flag\
401 		);
402 		}
403 
404 	if(add_objects_flag)
405 		{
406 		/* read in font (also needed for frame counter) */
407 //		tc_snprintf(temp, sizeof(temp), "%s/font.desc", default_font_dir);
408 		tc_snprintf(temp, sizeof(temp), "arial.ttf");
409 		vo_font = add_font(temp, default_subtitle_symbols, 28, 15, 1.0, 0.1);
410 		if(! vo_font)
411 			{
412 			tc_log_error(MOD_NAME, "subtitler(): Could not load font");
413 
414 			/* return init error */
415 			return -1;
416 			}
417 
418 		subtitle_current_font_descriptor = vo_font;
419 
420 		/* load ppml file */
421 		if(! load_ppml_file(subtitle_file) )
422 			{
423 			tc_log_error(MOD_NAME, "subtitler(): could not load file %s",\
424 			subtitle_file);
425 
426 			/* return init error */
427 			return -1;
428 			}
429 		} /* end if add_objects_flag */
430 
431 	/* return init OK */
432 	return 0;
433 	} /* end if filter init */
434 
435 /* filter close */
436 if(pfl->tag & TC_FILTER_CLOSE)
437 	{
438 	/* rely on exit() */
439 
440 	/* return close OK */
441 	return 0;
442 	} /* end if filter close */
443 
444 /*
445 filter frame routine
446 tag variable indicates, if we are called before
447 transcodes internal video/audo frame processing routines
448 or after and determines video/audio context
449 */
450 if(verbose & TC_STATS)
451 	{
452 	tc_log_info(MOD_NAME, "%s/%s %s %s",\
453 	vob->mod_path, MOD_NAME, MOD_VERSION, MOD_CAP);
454 
455 	/*
456 	tag variable indicates, if we are called before
457 	transcodes internal video/audo frame processing routines
458 	or after and determines video/audio context
459    	*/
460 
461 	if(pfl->tag & TC_PRE_M_PROCESS) pre = 1;
462 	if(pfl->tag & TC_POST_M_PROCESS) pre = 0;
463 
464 	if(pfl->tag & TC_VIDEO) vid = 1;
465 	if(pfl->tag & TC_AUDIO) vid = 0;
466 
467 	tc_log_info(MOD_NAME, "frame [%06d] %s %16s call",\
468 	pfl->id, (vid)?"(video)":"(audio)",\
469 	(pre)?"pre-process filter":"post-process filter");
470 	} /* end if verbose and stats */
471 
472 /*
473 default:
474 add the subtitles, after the coding, else edges in text get bad
475 */
476 if(use_pre_processing_flag)
477 	{
478 	a = (pfl->tag & TC_PRE_M_PROCESS) && (pfl->tag & TC_VIDEO);
479 	}
480 else
481 	{
482 	a = (pfl->tag & TC_POST_M_PROCESS) && (pfl->tag & TC_VIDEO);
483 	}
484 
485 if(a)
486 	{
487 	ImageData = pfl->video_buf;
488 	image_width = pfl->v_width;
489 	image_height = pfl->v_height;
490 	frame_nr = pfl->id;
491 	if(! have_bottom_margin_flag)
492 		{
493 		window_bottom = image_height - window_bottom;
494 		have_bottom_margin_flag = 1;
495 		}
496 
497 	if(debug_flag)
498 		{
499 		tc_log_info(MOD_NAME, \
500 		"frame_nr=%d \
501 		ImageData=%lu image_width=%d image_height=%d",\
502 		frame_nr,\
503 		(unsigned long)ImageData, image_width, image_height);
504 		}
505 
506 	/*
507 	calculate where to put and how to reformat the subtitles.
508 	These are globals.
509 	*/
510 	line_h_start = subtitle_h_factor * (double)image_width;
511 	line_h_end = (double)image_width - (double)line_h_start;
512 	window_bottom = image_height - (subtitle_v_factor * (double)image_height);
513 
514 	if(de_stripe_flag)
515 		{
516 		/*
517 		create a place to save the current frame,
518 		going to use it next frame to replace the lines that are all white,
519 		as caused by severe dropouts in ancient Umatic tapes.
520 		NOTE!:
521 		This cannot be done in INIT as then pfl->v_width and pfl->v_height
522 		are not available yet (zero).
523 		*/
524 		if(! frame_memory0)
525 			{
526 			/* for RGB */
527 			frame_memory0 = malloc(pfl->v_width * pfl->v_height * 3);
528 			if(! frame_memory0)
529 				{
530 				tc_log_error(MOD_NAME, "de_striper(): could not malloc frame_memory0");
531 
532 				/* return error */
533 				return -1;
534 				}
535 			frame_memory1 = malloc(pfl->v_width * pfl->v_height * 3);
536 			if(! frame_memory1)
537 				{
538 				tc_log_error(MOD_NAME, "de_striper(): could not malloc frame_memory1");
539 
540 				/* return error */
541 				return -1;
542 				}
543 			} /* end if ! frame_memory */
544 
545 		/* save the current frame for later */
546 		for(i = 0; i < pfl->v_width * pfl->v_height * 3; i++)
547 			{
548 			frame_memory0[i] = pfl->video_buf[i];
549 			}
550 
551 		slice_level = 0;
552 		pfm = pfl->video_buf;
553 		opfm = frame_memory1;
554 		pfmend = ImageData + (pfl->v_height * pfl->v_width * 3);
555 		opfmend = frame_memory1 + (pfl->v_height * pfl->v_width * 3);
556 		for(y = 0; y < pfl->v_height; y++)
557 			{
558 			/* get line boundaries for video buffer */
559 			pline_start = pfm;
560 			pline_end = pfm + pfl->v_width * 3;
561 
562 			/* get line boundaries for frame_memory1 */
563 			opline_start = opfm;
564 			opline_end = opfm + pfl->v_width * 3;
565 			x_shift = 0;
566 			/*
567 			perhaps expand condition for more then one pixel in a line
568 			*/
569 			for(x = 0; x < pfl->v_width; x++)
570 				{
571 				if(pfm >= pfmend - 3) break;
572 
573 				/* test if white stripe */
574 				if( (pfm[0] - opfm[0] > slice_level) &&\
575 				(pfm[1] - opfm[1] > slice_level) &&\
576 				(pfm[2] - opfm[2] > slice_level) )
577 					{
578 
579 					/* test for out of range pointers due to x_shift */
580 					if( (opfm + x_shift >= (uint8_t *)frame_memory1) &&\
581 					(opfm + x_shift < opfmend) )
582 						{
583 						/* replace with data from previous frame */
584 						pfm[0] = *(opfm + x_shift);
585 						pfm[1] = *(opfm + 1 + x_shift);
586 						pfm[2] = *(opfm + 2 + x_shift);
587 						} /* end if in range */
588 					} /* end if white stripe */
589 
590 				pfm += 3;
591 				opfm += 3;
592 
593 				} /* end for all x */
594 
595 			if(pfm >= pfmend - 3) break;
596 
597 			} /* end for all y */
598 
599 		/* save the current frame for later */
600 		for(i = 0; i < pfl->v_width * pfl->v_height * 3; i++)
601 			{
602 			frame_memory1[i] = frame_memory0[i];
603 			}
604 
605 		} /* end if de_stripe_flag */
606 
607 	if\
608 	(\
609 	(dcontrast != 100.0) ||\
610 	(dsaturation != 100.0) ||\
611 	(u_shift) ||\
612 	(v_shift)\
613 	)
614 		{
615 		/*
616 		brightness, contrast, saturation, U zero shift, V zero shift.
617 		*/
618 		ucptrs = ImageData;
619 		/* set pointers */
620 	    py = ImageData;
621 	    pv = ImageData + image_width * image_height;
622 	    pu = ImageData + (image_width * image_height * 5) / 4;
623 
624 		if(vob->im_v_codec == CODEC_RGB)
625 			{
626 			for(y = 0; y < pfl->v_height; y++)
627 				{
628 				for(x = 0; x < pfl->v_width * 3; x++)
629 					{
630 					/* brightness */
631 					if( (brightness + *py) > 255) *py = 255;
632 					else if ( (brightness + *py) < 0) *py = 0;
633 					else *py += brightness;
634 
635 					/* contrast */
636 					da = *py;
637 					da *= dcontrast / 100.0;
638 					*py = (int)da;
639 
640 					} /* end for all x */
641 
642 				} /* end for y */
643 			} /* end if color_depth 32 */
644 		else if(vob->im_v_codec == CODEC_YUV)
645 			{
646 			for(y = 0; y < pfl->v_height; y++)
647 				{
648 				for(x = 0; x < pfl->v_width; x++)
649 					{
650 					/* brightness */
651 					if( (brightness + *py) > 255) *py = 255;
652 					else if ( (brightness + *py) < 0) *py = 0;
653 					else *py += brightness;
654 
655 					/* contrast */
656 					da = *py;
657 					da *= dcontrast / 100.0;
658 					*py = (int)da;
659 
660 					/* saturation */
661 					a = (int)*pu - 128;
662 					b = (int)*pv - 128;
663 
664 					a *= dsaturation / 100.0;
665 					b *= dsaturation / 100.0;
666 
667 					*pu = (uint8_t)a + 128;
668 					*pv = (uint8_t)b + 128;
669 
670 					/* u_shift */
671 					*pu += u_shift;
672 					*pu &= 0xff;
673 
674 					/* v_shift */
675 					*pv += v_shift;
676 					*pv &= 255;
677 
678 					/* increment Y pointer */
679 					py++;
680 
681 					/* increment U and V vector pointers */
682 					if(x % 2)
683 						{
684 						pu++;
685 						pv++;
686 						}
687 					} /* end for all x */
688 
689 				if( (y + 1) % 2)
690 					{
691 					pu -= pfl->v_width / 2;
692 					pv -= pfl->v_width / 2;
693 					}
694 
695 				} /* end for y */
696 			} /* end if buffer is YUV */
697 		} /* end if contrast, saturation, u_shift, v_shift */
698 
699 	if( dhue || dhue_line_drift)
700 		{
701 		/*
702 		UV vector rotation.
703 		Dynamic UV vector rotation (NTSC line phase error correction).
704 		*/
705 		if(vob->im_v_codec == CODEC_RGB)
706 			{
707 			tc_log_error(MOD_NAME, \
708 			"hue operations only available in YUV 420");
709             return(-1);
710 			} /* end if CODEC_RGB */
711 		else if(vob->im_v_codec == CODEC_YUV)
712 			{
713 			/* set pointers */
714 		    py = ImageData;
715 		    pv = ImageData + image_width * image_height;
716 		    pu = ImageData + (image_width * image_height * 5) / 4;
717 
718 			for(y = 0; y < pfl->v_height; y++)
719 				{
720 				for(x = 0; x < pfl->v_width; x++)
721 					{
722 					/*
723 					NTSC color correction at start and end of line
724 					Assuming middle to be correct, most users would have
725 					adjusted on face color somewhere in the middle.
726 					*/
727 
728 					/* the phase drift over one horizontal line */
729 					da = (double)x / (double)pfl->v_width; // 0 to 1
730 
731 					/* go for middle, now -.5 to +.5 */
732 					da -= .5;
733 
734 					/* multiply by specified dynamic correction factor */
735 					db = dhue_line_drift * da;
736 
737 					/* add the static hue correction specified */
738 					db += (double)dhue;
739 
740 					/* hue and saturation*/
741 					a = (int)*pu - 128;
742 					b = (int)*pv - 128;
743 					adjust_color(&a, &b, db, dsaturation);
744 					*pu = (uint8_t)a + 128;
745 					*pv = (uint8_t)b + 128;
746 
747 					/* increment Y pointer */
748 					py++;
749 
750 					/* increment U and V vector pointers */
751 					if(x % 2)
752 						{
753 						pu++;
754 						pv++;
755 						}
756 					} /* end for all x */
757 
758 				/*
759 				2 x 2 color pixels on screen for each Y value,
760 				repeat each line twice.
761 
762 				Orientation on screen Y (*) and U V (o)
763 				* o
764 				o o
765 				drop shadow :-) color less area below char looks better.
766 				sink a line.
767 				*/
768 				if( (y + 1) % 2)
769 					{
770 					pu -= pfl->v_width / 2;
771 					pv -= pfl->v_width / 2;
772 					}
773 
774 				} /* end for y */
775 			} /* end if buffer is YUV */
776 
777 		} /* end if some sort of hue */
778 
779 	if(add_objects_flag)
780 		{
781 		/*
782 		collect any objects from database for this frame
783 		and add to object list.
784 		*/
785 		process_frame_number(frame_nr);
786 
787 		/* add objects in object list to display, and update params */
788 		add_objects(frame_nr);
789 
790 		} /* end if add_objects_flag */
791 
792 	if(write_ppm_flag)
793 		{
794 		if(vob->im_v_codec == CODEC_RGB)
795 			{
796 			tc_log_error(MOD_NAME, \
797 			"subtitler(): write_ppm only available in YUV 420\n");
798 			return(-1);
799 			} /* end if CODEC_RGB */
800 		else if(vob->im_v_codec == CODEC_YUV)
801 			{
802 			/* set pointers */
803 		    py = ImageData;
804 		    pv = ImageData + image_width * image_height;
805 		    pu = ImageData + (image_width * image_height * 5) / 4;
806 
807 			/* open the ppm file for write */
808 			tc_snprintf(temp, sizeof(temp), "%s/.subtitles/%d.ppm", home_dir, movie_id);
809 			pppm_file = fopen(temp, "w");
810 			if(! pppm_file)
811 				{
812 				tc_log_error(MOD_NAME,
813 				"could not open file %s for write, aborting",\
814 				 temp);
815 				return(-1);
816 				}
817 
818 			/* write the ppm header */
819 			fprintf(pppm_file,\
820 			"P6\n%i %i\n255\n", pfl->v_width, pfl->v_height);
821 
822 			for(y = 0; y < pfl->v_height; y++)
823 				{
824 				/* get a line from buffer start, to file in RGB */
825 				for(x = 0; x < pfl->v_width; x++)
826 					{
827 					cy = ( (0xff & *py) - 16);
828 					cy  *= 76310;
829 
830 					cu = (0xff & *pu) - 128;
831 					cv = (0xff & *pv) - 128;
832 
833 					cr = 104635 * cv;
834 					cg = -25690 * cu + -53294 * cv;
835 					cb = 132278 * cu;
836 
837 					fprintf(pppm_file, "%c%c%c",\
838 					LIMIT(cr + cy), LIMIT(cg + cy), LIMIT(cb + cy) );
839 
840 					/* increment Y pointer */
841 					py++;
842 
843 					/* increment U and V vector pointers */
844 					if(x % 2)
845 						{
846 						pu++;
847 						pv++;
848 						}
849 					} /* end for all x */
850 
851 				if( (y + 1) % 2)
852 					{
853 					pu -= pfl->v_width / 2;
854 					pv -= pfl->v_width / 2;
855 					}
856 
857 				} /* end for y (all lines) */
858 			} /* end if buffer is YUV */
859 		fclose(pppm_file);
860 
861 		/* set the semaphore indicating the .ppm file is ready */
862 		tc_snprintf(temp, sizeof(temp), "touch %s/.subtitles/%d.sem", home_dir, movie_id);
863 		execute(temp);
864 
865 		/* now wait for the semaphore to be removed, by calling */
866 		tc_snprintf(temp, sizeof(temp), "%s/.subtitles/%d.sem", home_dir, movie_id);
867 		while(1)
868 			{
869 			fptr = fopen(temp, "r");
870 			if(! fptr) break;
871 
872 			fclose(fptr);
873 
874 			/* reduce processor load */
875 			usleep(10000); // 10 ms
876 			} /* end while wait for handshake */
877 
878 		} /* end if write_ppm_flag */
879 
880 	if(show_output_flag)
881 		{
882 		/* create an xwindows display */
883 		if(! window_open_flag)
884 			{
885 			if(debug_flag)
886 				{
887 				tc_log_info(MOD_NAME, "opening window");
888 				}
889 
890 //			openwin(argc, argv, width, height);
891 			openwin(0, NULL, pfl->v_width, pfl->v_height);
892 
893 			window_size = pfl->v_width * pfl->v_height;
894 			window_open_flag = 1;
895 
896 			if(color_depth == 0) color_depth = get_x11_bpp();
897 
898 			} /* end if ! window_open_flag */
899 		else /* have window */
900 			{
901 			if( (pfl->v_width * pfl->v_height) != window_size)
902 				{
903 				/* close window and open a new one */
904 //				closewin(); //crashes
905 //				resize_window(xsize, ysize); // problem ?
906 // no problem, now we have 2 windows, use window manager to kill one
907 
908 //				openwin(argc, argv, xsize, ysize);
909 				openwin(0, NULL, pfl->v_width, pfl->v_height);
910 
911 				window_size = pfl->v_width * pfl->v_height;
912 				} /* end if different window size */
913 
914 			/* get X11 buffer */
915 			ucptrd = (unsigned char *)getbuf();
916 
917 			/* copy data to X11 buffer */
918 			ucptrs = ImageData;
919 
920 			if(vob->im_v_codec == CODEC_RGB)
921 				{
922 				/* need vertical flip, but not horizontal flip */
923 				if(color_depth == 32)
924 					{
925 					/* ucptrs points to start buffer, ucptrd to X buffer */
926 					ucptrd += (window_size - pfl->v_width) * 4;
927 					for(y = 0; y < pfl->v_height; y++)
928 						{
929 						/*
930 						get a line from buffer start, copy to xbuffer end
931 						*/
932 						for(x = 0; x < pfl->v_width; x++)
933 							{
934 							*ucptrd++ = *ucptrs++;
935 							*ucptrd++ = *ucptrs++;
936 							*ucptrd++ = *ucptrs++;
937 
938 							ucptrd++; /* nothing in byte 4 */
939 							}
940 
941 						/* move back a line, so we V flip */
942 						ucptrd -= pfl->v_width * 8;
943 						} /* end for y (all lines) */
944 					} /* end if color_depth 32 */
945 				else if(color_depth == 24) // NOT TESTED!!!!!!!!
946 					{
947 					/* ucptrs points to start buffer, ucptrd to X buffer */
948 					ucptrd += (window_size - pfl->v_width) * 3;
949 					for(y = 0; y < pfl->v_height; y++)
950 						{
951 						/*
952 						get a line from buffer start, copy to xbuffer end
953 						*/
954 						for(x = 0; x < pfl->v_width; x++)
955 							{
956 							*ucptrd++ = *ucptrs++;
957 							*ucptrd++ = *ucptrs++;
958 							*ucptrd++ = *ucptrs++;
959 							}
960 
961 						/* move back a line, so we V flip */
962 						ucptrd -= pfl->v_width * 6;
963 						} /* end for y (all lines) */
964 					} /* end if color_depth 32 */
965 				} /* end if buffer is RGB */
966 			else if(vob->im_v_codec == CODEC_YUV)
967 				{
968 				/* set pointers */
969 			    py = ImageData;
970 			    pv = ImageData + image_width * image_height;
971 			    pu = ImageData + (image_width * image_height * 5) / 4;
972 				/* ucptrd is pointer to xbuffer BGR */
973 
974 				for(y = 0; y < pfl->v_height; y++)
975 					{
976 					/* get a line from buffer start, copy to xbuffer BGR */
977 					for(x = 0; x < pfl->v_width; x++)
978 						{
979 						cy = ( (0xff & *py) - 16);
980 						cy  *= 76310;
981 
982 						cu = (0xff & *pu) - 128;
983 						cv = (0xff & *pv) - 128;
984 
985 						cr = 104635 * cv;
986 						cg = -25690 * cu + -53294 * cv;
987 						cb = 132278 * cu;
988 
989 						if(color_depth == 32) // 4 bytes per pixel
990 							{
991 							*ucptrd++ = LIMIT(cb + cy); // B
992 							*ucptrd++ = LIMIT(cg + cy); // G
993 							*ucptrd++ = LIMIT(cr + cy); // R
994 
995 							/* one more byte */
996 							*ucptrd++ = 0; // last byte is empty.
997 							} /* end if color depth 32 */
998 
999 						/* 24 bpp not tested */
1000 						else if(color_depth == 24) // 3 bytes per pixel
1001 							{
1002 							*ucptrd++ = LIMIT(cb + cy); // B
1003 							*ucptrd++ = LIMIT(cg + cy); // G
1004 							*ucptrd++ = LIMIT(cr + cy); // R
1005 							}
1006 
1007 						/* increment Y pointer */
1008 						py++;
1009 
1010 						/* increment U and V vector pointers */
1011 						if(x % 2)
1012 							{
1013 							pu++;
1014 							pv++;
1015 							}
1016 						} /* end for all x */
1017 
1018 					/*
1019 					2 x 2 color pixels on screen for each Y value,
1020 					repeat each line twice.
1021 
1022 					Orientation on screen Y (*) and U V (o)
1023 					* o
1024 					o o
1025 					drop shadow :-) color less area below char looks better.
1026 					sink a line.
1027 					*/
1028 					if( (y + 1) % 2)
1029 						{
1030 						pu -= pfl->v_width / 2;
1031 						pv -= pfl->v_width / 2;
1032  						}
1033 
1034 					} /* end for y (all lines) */
1035 				} /* end if buffer is YUV */
1036 
1037 			/* show X11 buffer */
1038 			putimage(pfl->v_width, pfl->v_height);
1039 			} /* end if window_open_flag */
1040 
1041 		} /* end if show_output_flag */
1042 
1043 	} /* end if TC_VIDEO && TC_POST_M_PROCESS */
1044 
1045 /* return OK */
1046 return 0;
1047 } /* end function tc_filter */
1048 
1049 
add_text(int x,int y,char * text,struct object * pa,int u,int v,double contrast,double transparency,font_desc_t * pfd,int espace)1050 int add_text(\
1051 int x, int y,\
1052 char *text,
1053 struct object *pa,\
1054 int u, int v,\
1055 double contrast, double transparency, font_desc_t *pfd, int espace)
1056 {
1057 int a;
1058 char *ptr;
1059 
1060 if(debug_flag)
1061 	{
1062 	tc_log_info(MOD_NAME, "add_text(): x=%d y=%d text=%s \
1063 	pa=%p u=%d v=%d contrast=%.2f transparency=%.2f \
1064 	font_desc_t=%lu espace=%d",\
1065 	x, y, (const char *)pa, text, u, v, contrast, transparency, (unsigned long)pfd, espace);
1066 	}
1067 
1068 ptr = text;
1069 while(*ptr)
1070 	{
1071 	/* convert to signed */
1072 	a = *ptr;
1073 	if(*ptr < 0) a += 256;
1074 
1075 	if(a == ' ')
1076 		{
1077         /* want to print background only here, not '_' */
1078         draw_char(x, y, a, pa, u, v, contrast, transparency, pfd, 1);
1079 		}
1080 	else
1081 		{
1082 		draw_char(x, y, a, pa, u, v, contrast, transparency, pfd, 0);
1083 		}
1084 
1085 	x += pfd->width[a] + pfd->charspace;
1086 
1087 
1088 	x += espace; //extra_character_space;
1089 	ptr++;
1090 	}
1091 
1092 return 1;
1093 } /* end function add_text */
1094 
1095 
draw_char(int x,int y,int c,struct object * pa,int u,int v,double contrast,double transparency,font_desc_t * pfd,int is_space)1096 int draw_char(\
1097 int x, int y, int c,\
1098 struct object *pa,\
1099 int u, int v,\
1100 double contrast, double transparency, font_desc_t *pfd, int is_space)
1101 {
1102 if(debug_flag)
1103 	{
1104 	tc_log_info(MOD_NAME, "draw_char(): arg \
1105 	x=%d y=%d c=%d pa=%p u=%d v=%d contrast=%.2f transparency=%.2f \
1106 	pfd=%lu is_space=%d",\
1107 	x, y, c, pa, u, v, contrast, transparency, (unsigned long)pfd, is_space);
1108 	}
1109 
1110 draw_alpha(\
1111 	x,\
1112 	y,\
1113 	pa,\
1114 	pfd->width[c],\
1115 	pfd->pic_a[pa -> font_symbols]->h,\
1116 	pfd->pic_b[pa -> font_symbols]->bmp + pfd->start[c],\
1117 	pfd->pic_a[pa -> font_symbols]->bmp + pfd->start[c],\
1118 	pfd->pic_a[pa -> font_symbols]->w,\
1119 	u, v, contrast, transparency, is_space);
1120 
1121 return 1;
1122 } /* end function draw_char */
1123 
1124 
draw_alpha(int x0,int y0,struct object * pa,int w,int h,uint8_t * src,uint8_t * srca,int stride,int u,int v,double contrast,double transparency,int is_space)1125 void draw_alpha(\
1126 	int x0, int y0,\
1127 	struct object *pa,\
1128 	int w, int h,\
1129 	uint8_t *src, uint8_t *srca, int stride,\
1130 	int u, int v, double contrast, double transparency, int is_space)
1131 {
1132 int a, b, c, x, y, sx, cd;
1133 uint8_t *py, *pu, *pv;
1134 uint8_t *sc, *sa;
1135 double dmto = 0, dmti = 0;
1136 uint8_t uy, ur, ug, ub, ua, uc;
1137 int iu, iv;
1138 int iy;
1139 unsigned char *dst;
1140 double dir, dig, dib, dor, dog, dob;
1141 double diy, diu, div, doy, dou, dov;
1142 double da, db;
1143 double opaqueness_p, opaqueness_e1, opaqueness_e2;
1144 double dmci;
1145 double dmti_p = 0, dmti_e1 = 0, dmti_e2 = 0;
1146 double dmto_p = 0, dmto_e1 = 0, dmto_e2 = 0;
1147 double dy, dblur;
1148 double dmulto, dmulti;
1149 
1150 
1151 if(debug_flag)
1152 	{
1153 	tc_log_info(MOD_NAME, \
1154 	"draw_alpha(): x0=%d y0=%d pa=%p w=%d h=%d \
1155 	src=%lu srca=%lu stride=%d u=%d v=%d \
1156 	contrast=%.2f transparency=%.2f is_space=%d",\
1157 	x0, y0, pa, w, h,\
1158 	(unsigned long)src, (unsigned long)srca, stride, u, v,\
1159 	contrast, transparency, is_space);
1160 
1161 	tc_log_info(MOD_NAME, "vob->im_v_codec=%d", vob -> im_v_codec);
1162 	tc_log_info(MOD_NAME, "image_width=%d image_height=%d", image_width, image_height);
1163 	tc_log_info(MOD_NAME, "ImageData=%lu", (unsigned long)ImageData);
1164 	}
1165 
1166 /* all */
1167 db = (1.0 - (double)pa -> transparency / 100.0);
1168 dmci = (pa -> contrast / 100.0);
1169 
1170 if(rgb_palette_valid_flag)
1171 	{
1172 	/* pattern */
1173 	/* calculate 'visibility' insert */
1174 	da = (double) pa -> pattern_contrast / 15.0;
1175 	opaqueness_p = da * db;
1176 
1177 	/* combine subtitler and DVD transparency */
1178 	dmto_p = 1.0 - opaqueness_p;
1179 	dmti_p = 1.0 - dmto_p;
1180 
1181 	dmti_p *= dmci;
1182 
1183 
1184 	/* emphasis1 */
1185 	/* calculate 'visibility' insert */
1186 	da = (double) pa -> emphasis1_contrast / 15.0;
1187 	opaqueness_e1 = da * db;
1188 
1189 	/* combine subtitler and DVD transparency */
1190 	dmto_e1 = 1.0 - opaqueness_e1;
1191 	dmti_e1 = 1.0 - dmto_e1;
1192 
1193 	dmti_e1 *= dmci;
1194 
1195 
1196 	/* emphasis2 */
1197 	/* calculate 'visibility' insert */
1198 	da = (double) pa -> emphasis2_contrast / 15.0;
1199 	opaqueness_e2 = da * db;
1200 
1201 	/* combine subtitler and DVD transparency */
1202 	dmto_e2 = 1.0 - opaqueness_e2;
1203 	dmti_e2 = 1.0 - dmto_e2;
1204 
1205 	dmti_e2 *= dmci;
1206 
1207 	}
1208 else
1209 	{
1210 	/* calculate multiplier for transparency ouside loops */
1211 	dmti = db;
1212 	dmto = 1.0 - dmti;
1213 
1214 	dmti *= dmci;
1215 	}
1216 
1217 sc = src;
1218 sa = srca;
1219 
1220 if(vob->im_v_codec == CODEC_RGB)
1221 	{
1222 	a = 3 * (image_height * image_width); // size of a picture
1223 
1224 	for(y = 0; y < h; y++)
1225 		{
1226 		b = 3 * ( (y + y0) * image_width);
1227 
1228 		for(x = 0; x < w; x++)
1229 			{
1230 			c = 3 * (image_width - (x + x0) );
1231 
1232 			dst = ImageData + a - (b + c);
1233 
1234 			/* clip right scroll */
1235 			if( (x + x0) > image_width - 1) continue;
1236 
1237 			/* clip left scroll */
1238 			if( (x + x0 ) < 0) continue;
1239 
1240 			/* clip top scroll */
1241 			if( (y + y0) > image_height - 1) continue;
1242 
1243 			/* clip bottom scroll */
1244 			if( (y + y0) < 0) continue;
1245 
1246 			if(! rgb_palette_valid_flag)
1247 				{
1248 				if(sa[x] && !is_space)
1249 					{
1250 
1251 					/* get original */
1252 					dob = (double) dst[0];
1253 					dog = (double) dst[1];
1254 					dor = (double) dst[2];
1255 
1256 					/* get insert (character) original is BW */
1257 					diy = (double) (sa[x] >> 8) + sc[x];
1258 
1259 					/* transparency */
1260 					diy *= dmti;
1261 
1262 					dob *= dmto;
1263 					dog *= dmto;
1264 					dor *= dmto;
1265 
1266 					if(sa[x])
1267 						{
1268 						dst[0] = (int) (dob + diy);
1269 						dst[1] = (int) (dog + diy);
1270 						dst[2] = (int) (dor + diy);
1271 						}
1272 					else /* border */
1273 						{
1274 						dst[0] = (int) (dob);
1275 						dst[1] = (int) (dog);
1276 						dst[2] = (int) (dor);
1277 						}
1278 
1279 					}
1280 				} /* end if ! rgb_palette_valid_flag */
1281 			else /* DVD like subs */
1282 				{
1283 				/* some temp vars */
1284 				ub = dst[0];
1285 				ug = dst[1];
1286 				ur = dst[2];
1287 
1288 				ua = sa[x];
1289 				uc = sc[x];
1290 
1291 				/* get original */
1292 				dob = (double)dst[0];
1293 				dog = (double)dst[1];
1294 				dor = (double)dst[2];
1295 
1296 				/* blur factor y * sa[x] */
1297 				dy = .3* dor + .59 * dog + .11 * dob;
1298 				dblur = (double) ( ((int)dy * ua) >> 8) + uc;
1299 				dblur /= 255.0;
1300 
1301 				if(sa[x] && !is_space)
1302 					{
1303 					if(sc[x] > 5)
1304 						{
1305 						dir = (double)rgb_palette[pa -> pattern][0];
1306 						dig = (double)rgb_palette[pa -> pattern][1];
1307 						dib = (double)rgb_palette[pa -> pattern][2];
1308 
1309 						dir *= dblur;
1310 						dig *= dblur;
1311 						dib *= dblur;
1312 
1313 						/* transparency */
1314 						dir *= dmti_p;
1315 						dig *= dmti_p;
1316 						dib *= dmti_p;
1317 
1318 						dor *= dmto_p;
1319 						dog *= dmto_p;
1320 						dob *= dmto_p;
1321 
1322 						}
1323 					else /* emphasis1 */
1324 						{
1325 						dir = (double)rgb_palette[pa -> emphasis1][0];
1326 						dig = (double)rgb_palette[pa -> emphasis1][1];
1327 						dib = (double)rgb_palette[pa -> emphasis1][2];
1328 
1329 						/* transparency */
1330 						dir *= dmti_e1;
1331 						dig *= dmti_e1;
1332 						dib *= dmti_e1;
1333 
1334 						dor *= dmto_e1;
1335 						dog *= dmto_e1;
1336 						dob *= dmto_e1;
1337 
1338 						}
1339 					} /* end if sc[x] */
1340 				else /* emphasis2 */
1341 					{
1342 					/* get new part */
1343 					dir = (double)rgb_palette[pa -> emphasis2][0];
1344 					dig = (double)rgb_palette[pa -> emphasis2][1];
1345 					dib = (double)rgb_palette[pa -> emphasis2][2];
1346 
1347 					/* transparency */
1348 					dir *= dmti_e2;
1349 					dig *= dmti_e2;
1350 					dib *= dmti_e2;
1351 
1352 					dor *= dmto_e2;
1353 					dog *= dmto_e2;
1354 					dob *= dmto_e2;
1355 					}
1356 
1357 				/* combine old and new parts in output */
1358 				dst[0] = (int) (dob + dib);
1359 				dst[1] = (int) (dog + dig);
1360 				dst[2] = (int) (dor + dir);
1361 				} /* end if DVD like subs */
1362 
1363 			} /* end for all x */
1364 
1365 		sc += stride;
1366 		sa += stride;
1367 
1368 		} /* end for all y */
1369 
1370 	} /* end if RGB */
1371 else if(vob->im_v_codec == CODEC_YUV)
1372 	{
1373 	/*
1374 	We seem to be in this format I420:
1375     y = dest;
1376     v = dest + width * height;
1377     u = dest + width * height * 5 / 4;
1378 
1379 	Orientation of Y (*) relative to chroma U and V (o)
1380 	* o
1381 	o o
1382 	So, an array of 2x2 chroma pixels exists for each luminance pixel
1383 	The consequence of this is that there will be a color-less area
1384 	of one line on the right and on the bottom of each character.
1385 	Dropshadow :-)
1386 	*/
1387 
1388 	py = ImageData;
1389 	pv = ImageData + image_width * image_height;
1390 	pu = ImageData + (image_width * image_height * 5) / 4;
1391 
1392 	a = y0 * image_width;
1393 	b = image_width / 4;
1394 	c = image_width / 2;
1395 
1396 	py += x0 + a;
1397 	a /= 4;
1398 
1399 	pu += (x0 / 2) + a;
1400 	pv += (x0 / 2) + a;
1401 
1402 	/* on odd lines, need to go a quarter of a 'line' back */
1403 	if(y0 % 2)
1404 		{
1405 		pu -= b;
1406 		pv -= b;
1407 		}
1408 
1409 	for(y = 0; y < h; y++)
1410 		{
1411 		for(x = 0; x < w; x++)
1412 			{
1413 
1414 			/* clip right scroll */
1415 			if( (x + x0) > image_width - 1) continue;
1416 
1417 			/* clip left scroll */
1418 			if( (x + x0 ) < 0) continue;
1419 
1420 			/* clip top scroll */
1421 			if( (y + y0) > image_height - 1) continue;
1422 
1423 			/* clip bottom scroll */
1424 			if( (y + y0) < 0) continue;
1425 
1426 			if(! rgb_palette_valid_flag)
1427 				{
1428 				if(sa[x] && !is_space)
1429 					{
1430 					/* trailing shadow no */
1431 					sx = 1;
1432 					if( (x + x0) % 2) sx = 0;
1433 
1434 //					if(x  < (w - 4) ) sx = 1; // hack, looks better :-)
1435 //					else sx = 0;
1436 
1437 					/* some temp vars */
1438 					uy = py[x];
1439 					ua = sa[x];
1440 					uc = sc[x];
1441 
1442 					/* get decision factor before we change anything */
1443 //					cd = ( (py[x] * sa[x]) >> 8) < 5;
1444 					cd = ( (uy * ua) >> 8) < 5;
1445 
1446 					/* get original */
1447 					doy = (double) py[x];
1448 					dou = (double) (pu[x / 2 + sx] - 128);
1449 					dov = (double) (pv[x / 2 + sx] - 128);
1450 
1451 					/* blur factor y * sa[x] */
1452 					dblur = (double) ( ((int)doy * ua) >> 8) + uc;
1453 					dblur /= 255.0;
1454 
1455 					/* calculate value insert (character) */
1456 					diy = (double) ( (uy * ua) >> 8) + uc;
1457 
1458 					/* transparency */
1459 					diy *= dmti;
1460 					doy *= dmto;
1461 
1462 					/* add what is left of the insert (character) */
1463 					py[x] = (int) (doy + diy);
1464 
1465 					if(cd)
1466 						{
1467 						diu *= dblur;
1468 						div *= dblur;
1469 
1470 						/* change color too */
1471 						diu = u * dmti;
1472 						div = v * dmti;
1473 
1474 						dou *= dmto;
1475 						dov *= dmto;
1476 
1477 						if(sc[x]) /* white part of char */
1478 							{
1479 							/* set U vector */
1480 							pu[x / 2 + sx] = (int) (128.0 + dou + diu);
1481 
1482 							/* set V vector */
1483 							pv[x / 2 + sx] = (int) (128.0 + dov + div);
1484 							}
1485 						else /* keep border around character colorless */
1486 							{
1487 							/* set U vector */
1488 							pu[x / 2 + sx] = (int) (128.0 + dou); // + diu);
1489 
1490 							/* set V vector */
1491 							pv[x / 2 + sx] = (int) (128.0 + dov); // + div);
1492 							}
1493 
1494 						} /* end if sa[x] */
1495 					} /* end if cd */
1496 
1497 				} /* end if ! rgb_palette_valid_flag */
1498 			else
1499 				{
1500 				/*
1501 				OK lets get this straight:
1502 				I do not understand character anti-aliasing, but looked at the variables with
1503 				printf().
1504 				Here I see that:
1505 				sa[x] > 0 for character space, it varies from 255 to 0
1506 				sc[x] > 0 for character body (pattern), it varies from 0 to 255;
1507 
1508 				sa[x] seems to be the aliasing or blur? multiplier, and is used to attenuate
1509                 the original! Not my idea of anti alias, but OK.
1510 				sc[x] is the multiplier for the insert (character).
1511 
1512 				sa[x] is 1 within the body of a character.
1513 				sa[x] increases as you go from center character outwards (fade in background)
1514 				sa[x] is zero outside the character space.
1515 
1516 
1517 				so:
1518 				sa[x] = 0 is not in character space.
1519 				sa[x] = 1 is character body
1520 				sa[x] > 1 is outline1
1521 
1522 
1523 				Variable names used:
1524 				dxxxxo for double (format) referring to original data
1525 				dxxxxi for double (format) referring to insert data
1526 
1527 				*/
1528 
1529 				/*
1530 				test for in character space, and something to print
1531 				These character sets seem to have '_' in place of a real space, so that is why is_space,
1532 				to prevent a '_' from appearing where a space is intended.
1533 				*/
1534 
1535 				/* some color trick */
1536 				sx = 1;
1537 				if( (x + x0) % 2) sx = 0;
1538 
1539 				/* trailing shadow no */
1540 //				if(x  < (w - 4) ) sx = 1; // hack, looks better :-)
1541 //				else sx = 0;
1542 
1543 				if(sa[x] && !is_space)
1544 					{
1545 
1546 					/* get multiplier as double */
1547 					dmulto = (double) sa[x] / 256.0;
1548 
1549 					/* multiplier to range 0 to 1.0 */
1550 					dmulti = (double) sc[x] / 256.0;
1551 
1552 					if(use_emphasis2_for_anti_aliasing_flag)
1553 						{
1554 						/* multiplier to range 0 to 1.0 */
1555 						dmulti = (double) sc[x] / 256.0;
1556 						}
1557 					else
1558 						{
1559 						if(sc[x]) dmulti = 1.0;
1560 						else dmulti = 0.0;
1561 						}
1562 
1563 					/* test for character body */
1564 					if(dmulti > .5)
1565 						{
1566 						/* get original */
1567 						doy = (double) py[x];
1568 						dou = (double) pu[x / 2 + sx] - 128;
1569 						dov = (double) pv[x / 2 + sx] - 128;
1570 
1571 						rgb_to_yuv(\
1572 						rgb_palette[pa -> pattern][0],\
1573 						rgb_palette[pa -> pattern][1],\
1574 						rgb_palette[pa -> pattern][2],\
1575 						&iy, &iu, &iv);
1576 
1577 						/*
1578 						better to multiply AFTER rgb_to_uuv(),
1579 						as strange values may happen for u and v if low values of rgb.
1580 						*/
1581 
1582 						/* NOTE: what we call 'contrast' in DVD is actually transparency */
1583 
1584 						/* insert to double */
1585 						diy = (double) iy;
1586 						diu = (double) iu;
1587 						div = (double) iv;
1588 
1589 						/* transparency */
1590 						diy *= dmti_p;
1591 /* u and v here for color change */
1592 						diu *= dmti_p;
1593 						div *= dmti_p;
1594 
1595 						doy *= dmto_p;
1596 						dou *= dmto_p;
1597 						dov *= dmto_p;
1598 
1599 						da = (doy * dmulto) + (diy * dmulti);
1600 						py[x] = (int) da;
1601 
1602 						/* set U vector */
1603 						da = (dou * dmulto) + (diu * dmulti);
1604 						pu[x / 2 + sx] = 128 + (int)da;
1605 
1606 						/* set V vector */
1607 						da = (dov * dmulto) + (div * dmulti);
1608 						pv[x / 2 + sx] = 128 + (int)da;
1609 						} /* end if body */
1610 					else
1611 						{
1612 						if(use_emphasis2_for_anti_aliasing_flag)
1613 							{
1614 							/* use outline2 for anti aliasing, set to grey 50 % */
1615                             if( (dmulti > 0) && (dmulti < .5) )
1616 								{
1617 								/* get original */
1618 								doy = (double) py[x];
1619 								dou = (double) pu[x / 2 + sx] - 128;
1620 								dov = (double) pv[x / 2 + sx] - 128;
1621 
1622 								/* draw outline2 */
1623 								rgb_to_yuv(\
1624 								rgb_palette[pa -> emphasis2][0],\
1625 								rgb_palette[pa -> emphasis2][1],\
1626 								rgb_palette[pa -> emphasis2][2],\
1627 								&iy, &iu, &iv);
1628 
1629 								/* insert to double */
1630 								diy = (double) iy;
1631 								diu = (double) iu;
1632 								div = (double) iv;
1633 
1634 								/* transparency */
1635 								diy *= dmti_e2;
1636 								diu *= dmti_e2;
1637 								div *= dmti_e2;
1638 
1639 								doy *= dmto_e2;
1640 								dou *= dmto_e2;
1641 								dov *= dmto_e2;
1642 
1643 								/* add what is left of the insert (character) */
1644 								py[x] = (int) (doy + diy);
1645 
1646 								/* set U vector */
1647 								pu[x / 2 + sx] = 128 + (int) (dou + diu);
1648 
1649 								/* set V vector */
1650 								pv[x / 2 + sx] = 128 + (int) (dov + div);
1651 								} /* end emphasis2 for anti-aliasing */
1652 							else
1653 								{
1654 								/* get original */
1655 								doy = (double) py[x];
1656 								dou = (double) pu[x / 2 + sx] - 128;
1657 								dov = (double) pv[x / 2 + sx] - 128;
1658 
1659 								rgb_to_yuv(\
1660 								rgb_palette[pa -> emphasis1][0],\
1661 								rgb_palette[pa -> emphasis1][1],\
1662 								rgb_palette[pa -> emphasis1][2],\
1663 								&iy, &iu, &iv);
1664 
1665 								/* insert to double */
1666 								diy = (double) iy;
1667 								diu = (double) iu;
1668 								div = (double) iv;
1669 
1670 								/* transparency */
1671 								diy *= dmti_e1;
1672 								diu *= dmti_e1;
1673 								div *= dmti_e1;
1674 
1675 								doy *= dmto_e1;
1676 								dou *= dmto_e1;
1677 								dov *= dmto_e1;
1678 
1679 								da = doy + diy;
1680 								py[x] = (int) da;
1681 
1682 								/* set U vector */
1683 								da = dou  + diu;
1684 								pu[x / 2 + sx] = 128 + (int)da;
1685 
1686 								/* set V vector */
1687 								da = dov + div;
1688 								pv[x / 2 + sx] = 128 + (int)da;
1689 								} /* end emphasis1 */
1690 							} /* end if use_emphasis2_for_anti_aliasing_flag */
1691 						else /* outline1 */
1692 							{
1693 							/* get original */
1694 							doy = (double) py[x];
1695 							dou = (double) pu[x / 2 + sx] - 128;
1696 							dov = (double) pv[x / 2 + sx] - 128;
1697 
1698 							rgb_to_yuv(\
1699 							rgb_palette[pa -> emphasis1][0],\
1700 							rgb_palette[pa -> emphasis1][1],\
1701 							rgb_palette[pa -> emphasis1][2],\
1702 							&iy, &iu, &iv);
1703 
1704 							/* insert to double */
1705 							diy = (double) iy;
1706 							diu = (double) iu;
1707 							div = (double) iv;
1708 
1709 							/* transparency */
1710 							diy *= dmti_e1;
1711 							diu *= dmti_e1;
1712 							div *= dmti_e1;
1713 
1714 							doy *= dmto_e1;
1715 							dou *= dmto_e1;
1716 							dov *= dmto_e1;
1717 
1718 							da = doy + diy;
1719 							py[x] = (int) da;
1720 
1721 							/* set U vector */
1722 							da = dou  + diu;
1723 							pu[x / 2 + sx] = 128 + (int)da;
1724 
1725 							/* set V vector */
1726 							da = dov + div;
1727 							pv[x / 2 + sx] = 128 + (int)da;
1728 							} /* end no anti-alias */
1729 						} /* end dmulti < 0.5 */
1730 					} /* end if sa[x] && ! is_space */
1731 				else /* outline2 */
1732 					{
1733 					if(! use_emphasis2_for_anti_aliasing_flag ) /* use emphasis2 for  character space */
1734 						{
1735 						/* get original */
1736 						doy = (double) py[x];
1737 						dou = (double) pu[x / 2 + sx] - 128;
1738 						dov = (double) pv[x / 2 + sx] - 128;
1739 
1740 						/* draw outline2 */
1741 						rgb_to_yuv(\
1742 						rgb_palette[pa -> emphasis2][0],\
1743 						rgb_palette[pa -> emphasis2][1],\
1744 						rgb_palette[pa -> emphasis2][2],\
1745 						&iy, &iu, &iv);
1746 
1747 						/* insert to double */
1748 						diy = (double) iy;
1749 						diu = (double) iu;
1750 						div = (double) iv;
1751 
1752 						/* transparency */
1753 						diy *= dmti_e2;
1754 						diu *= dmti_e2;
1755 						div *= dmti_e2;
1756 
1757 						doy *= dmto_e2;
1758 						dou *= dmto_e2;
1759 						dov *= dmto_e2;
1760 
1761 						/* add what is left of the insert (character) */
1762 						py[x] = (int) (doy + diy);
1763 
1764 						/* set U vector */
1765 						pu[x / 2 + sx] = 128 + (int) (dou + diu);
1766 
1767 						/* set V vector */
1768 						pv[x / 2 + sx] = 128 + (int) (dov + div);
1769 						} /* end if outline2 */
1770 					} /* end if ! use_emphasis2_for_anti_aliasing_flag */
1771 				} /* end if rgb_palette_valid_flag */
1772 			} /* end for all x */
1773 
1774 		sc += stride;
1775 		sa += stride;
1776 
1777 		py += image_width;
1778 
1779 		if( (y + y0) % 2)
1780 			{
1781 			pu += c;
1782 			pv += c;
1783 			}
1784 
1785 		} /* end for all y */
1786 
1787 	} /* end if YUV */
1788 } /* end function draw_alpha */
1789 
1790 
add_background(struct object * pa)1791 int add_background(struct object *pa)
1792 {
1793 int a, b, c, x, y, sx;
1794 uint8_t *py, *pu, *pv;
1795 double da;
1796 int iu, iv;
1797 double dr, dg, db;
1798 int iy;
1799 double dmci, dmti, dmto;
1800 double dir, dig, dib, diy, diu, div;
1801 double dor, dog, dob, doy, dou, dov;
1802 unsigned char *dst;
1803 int width, height;
1804 double opaqueness;
1805 
1806 if(debug_flag)
1807 	{
1808 	tc_log_info(MOD_NAME, "add_background(): arg pa=%p", pa);
1809 
1810 	tc_log_info(MOD_NAME,\
1811 	"pa->line_number=%d pa->bg_y_start=%d pa->bg_y_end=%d pa->bg_x_start=%d pa->bg_x_end=%d",\
1812 	pa -> line_number, pa -> bg_y_start, pa -> bg_y_end, pa -> bg_x_start, pa -> bg_x_end);
1813 
1814 	tc_log_info(MOD_NAME,\
1815 	"pa->background=%d pa->background_contrast=%d",\
1816 	pa -> background, pa -> background_contrast);
1817 
1818 	tc_log_info(MOD_NAME,\
1819 	"pa->contrast=%.2f, pa->transparency=%.2f",\
1820 	pa -> contrast, pa -> transparency);
1821 	}
1822 
1823 /* only background if palette specified */
1824 if(! rgb_palette_valid_flag) return 1;
1825 
1826 /* parameter check */
1827 if(pa -> bg_y_start < 0) return 0;
1828 if(pa -> bg_y_start > image_height - 1) return 0;
1829 
1830 if(pa -> bg_x_start < 0) return 0;
1831 if(pa -> bg_x_start > image_width - 1) return 0;
1832 
1833 if(pa -> bg_y_end < pa -> bg_y_start) return 0;
1834 if(pa -> bg_y_end > image_height - 1) return 0;
1835 
1836 if(pa -> bg_x_end < pa -> bg_x_start) return 0;
1837 if(pa -> bg_x_end > image_width - 1) return 0;
1838 
1839 /* calculate 'visibility' insert */
1840 da = (double) pa -> background_contrast / 15.0; // DVD background request, 1.0 for 100 % opaque
1841 db = (1.0 - (double)pa -> transparency / 100.0); // subtitler background request, 1.0 for 100 % opaque
1842 opaqueness = da * db;
1843 
1844 /* combine subtitler and DVD transparency */
1845 dmto = 1.0 - opaqueness; // background, 1.0 for 100 % transparent
1846 dmti = 1.0 - dmto; // insert, 0.0 for 100 % transparent
1847 
1848 /*
1849 do not multiply color (saturation) with contrast,
1850 saturation could be done in adjust color, but done here for speed
1851 */
1852 dmci = (pa -> contrast / 100.0); // contrast insert, 1.0 for 100 % contrast
1853 
1854 dmti *= dmci;
1855 
1856 if(vob->im_v_codec == CODEC_RGB)
1857 	{
1858 	a = 3 * (image_height * image_width); // size of a picture
1859 
1860 	for(y = pa -> bg_y_start; y < pa -> bg_y_end; y++)
1861 		{
1862 		b = 3 * (y * image_width);
1863 
1864 		for(x = pa -> bg_x_start; x < pa -> bg_x_end; x++)
1865 			{
1866 			c = 3 * (image_width - x);
1867 
1868 			dst = ImageData + a - (b + c);
1869 
1870 			/* get original */
1871 			dob = (double)dst[0];
1872 			dog = (double)dst[1];
1873 			dor = (double)dst[2];
1874 
1875 			/* get new part */
1876 			dir = (double)rgb_palette[pa -> background][0];
1877 			dig = (double)rgb_palette[pa -> background][1];
1878 			dib = (double)rgb_palette[pa -> background][2];
1879 
1880 			/* transparency */
1881 			dir *= dmti;
1882 			dig *= dmti;
1883 			dib *= dmti;
1884 
1885 			dor *= dmto;
1886 			dog *= dmto;
1887 			dob *= dmto;
1888 
1889 			/* combine old and new parts in output */
1890 			dst[0] = (int) (dib + dob);
1891 			dst[1] = (int) (dig + dog);
1892 			dst[2] = (int) (dir + dor);
1893 
1894 			} /* end for all x */
1895 
1896 		} /* end for all y */
1897 
1898 	} /* end if RGB */
1899 else if(vob->im_v_codec == CODEC_YUV)
1900 	{
1901 	/*
1902 	We seem to be in this format I420:
1903     y = dest;
1904     v = dest + width * height;
1905     u = dest + width * height * 5 / 4;
1906 
1907 	Orientation of Y (*) relative to chroma U and V (o)
1908 	* o
1909 	o o
1910 	So, an array of 2x2 chroma pixels exists for each luminance pixel
1911 	The consequence of this is that there will be a color-less area
1912 	of one line on the right and on the bottom of each character.
1913 	Dropshadow :-)
1914 	*/
1915 
1916 	height = pa -> bg_y_end - pa -> bg_y_start;
1917 	width = pa -> bg_x_end - pa -> bg_x_start;
1918 
1919 	py = ImageData;
1920 	pv = ImageData + image_width * image_height;
1921 	pu = ImageData + (image_width * image_height * 5) / 4;
1922 
1923 	a = pa -> bg_y_start * image_width;
1924 	b = image_width / 4;
1925 	c = image_width / 2;
1926 
1927 	py += pa -> bg_x_start + a;
1928 	a /= 4;
1929 
1930 	pu += (pa -> bg_x_start / 2) + a;
1931 	pv += (pa -> bg_x_start / 2) + a;
1932 
1933 	/* on odd lines, need to go a quarter of a 'line' back */
1934 	if(pa -> bg_y_start % 2)
1935 		{
1936 		pu -= b;
1937 		pv -= b;
1938 		}
1939 
1940 	for(y = 0; y < height; y++)
1941 		{
1942 		for(x = 0; x < width; x++)
1943 			{
1944 			sx = 1;
1945 			if( (x + pa -> bg_x_start) % 2) sx = 0;
1946 
1947 			/* get old part */
1948 			doy = (double)py[x];
1949 			dou = (double)pu[x / 2 + sx] - 128;
1950 			dov = (double)pv[x / 2 + sx] - 128;
1951 
1952 			/* get new part */
1953 			dr = (double)rgb_palette[pa -> background][0];
1954 			dg = (double)rgb_palette[pa -> background][1];
1955 			db = (double)rgb_palette[pa -> background][2];
1956 
1957 			rgb_to_yuv(dr, dg, db, &iy, &iu, &iv);
1958 			/*
1959 			better to multiply AFTER rgb_to_uuv(),
1960 			as strange values may happen for u and v if low values of rgb.
1961 			*/
1962 
1963 			diy = (double)iy;
1964 			diu = (double)iu;
1965 			div = (double)iv;
1966 
1967 			/* transparency */
1968 			diy *= dmti;
1969 			diu *= dmti;
1970 			div *= dmti;
1971 
1972 			doy *= dmto;
1973 			dou *= dmto;
1974 			dov *= dmto;
1975 
1976 			/* add what is left of the insert (character) */
1977 			py[x] = (int) (doy + diy);
1978 
1979 			/* set U vector */
1980 			pu[x / 2 + sx] = 128 + (int) (dou + diu);
1981 
1982 			/* set V vector */
1983 			pv[x / 2 + sx] = 128 + (int) (dov + div);
1984 
1985 			} /* end for all x */
1986 
1987 		py += image_width;
1988 
1989 		if( (y + pa -> bg_y_start) % 2)
1990 			{
1991 			pu += c;
1992 			pv += c;
1993 			}
1994 
1995 		} /* end for all y */
1996 
1997 	} /* end if YUV */
1998 
1999 return 1;
2000 } /* end function add_background */
2001 
2002 
print_options(void)2003 int print_options(void)
2004 {
2005 if(debug_flag)
2006 	{
2007 	tc_log_info(MOD_NAME, "print options(): arg none");
2008 	}
2009 /*
2010 From transcode -0.5.1 ChangeLog:
2011 Example: -J my_filter="fonts=3 position=55 -v"
2012 */
2013 
2014  tc_log_info(MOD_NAME, "(%s) help\n"
2015 "Usage -J subtitler=\"[no_objects] [subtitle_file=s]\n\
2016 [color_depth=n]\n\
2017 [font_dir=s] [font=n] [font_factor=f\n\
2018 [frame_offset=n]\n\
2019 [debug] [help] [use_pre_processing]\"\n\
2020 \n\
2021 f is float, h is hex, n is integer, s is string.\n\
2022 \n\
2023 no_objects           disables subtitles and other objects (off).\n\
2024 color_depth=         32 or 24 (overrides X auto) (32).\n\
2025 font=                0 or 1, 1 gives strange symbols... (0).\n\
2026 font_dir=            place where font.desc is (%s).\n\
2027 font_factor=         .1 to 100 outline characters (10.75).\n\
2028 frame_offset=        positive (text later) or negative (earlier) integer (0).\n\
2029 subtitle_file=       pathfilename.ppml location of ppml file (%s).\n\
2030 debug                prints debug messages (off).\n\
2031 help                 prints this list and exits.\n\
2032 use_pre_processing   uses pre_processing.\n",
2033 MOD_CAP, default_font_dir, subtitle_file);
2034 
2035 return 1;
2036 } /* end function print_options */
2037 
2038 
add_picture(struct object * pa)2039 int add_picture(struct object *pa)
2040 {
2041 /*
2042 reads yuyv in pa -> data into the YUV 420 ImageData buffer.
2043 */
2044 uint8_t *py, *pu, *pv;
2045 int a, b, c, x, y;
2046 char *ps;
2047 char ca;
2048 int u_time;
2049 int in_range;
2050 double dc, dd, dm, ds;
2051 int ck_flag = 0;
2052 int odd_line;
2053 
2054 if(debug_flag)
2055 	{
2056 	tc_log_info(MOD_NAME, "add_picture(): arg pa=%lu\
2057 	pa->xsize=%.2f pa->ysize=%.2f pa->ck_color=%.2f",\
2058 	(unsigned long)pa,\
2059 	pa -> xsize, pa -> ysize,\
2060 	pa -> chroma_key_color);
2061 	}
2062 
2063 /* argument check */
2064 if(! ImageData) return 0;
2065 if(! pa) return 0;
2066 if( (int)pa -> xsize == 0) return 1;
2067 if( (int)pa -> ysize == 0) return 1;
2068 
2069 /* calculate multiplier for transparency ouside loops */
2070 dm = (100.0 - pa -> transparency) / 100.0;
2071 dd = 1.0 - dm;
2072 
2073 dc = dm * (pa -> contrast / 100.0);
2074 ds = (pa -> saturation / 100.0);
2075 
2076 /* saturation could be done in adjust color, but done here for speed */
2077 //ds = 1.0;
2078 
2079 if(vob->im_v_codec == CODEC_RGB)
2080 	{
2081 	/* ImageData, image_width, image_height */
2082 
2083 	tc_log_error(MOD_NAME, \
2084 	"subtitler ONLY works with YUV 420");
2085 
2086 	return(-1);
2087 	} /* end if RGB */
2088 else if(vob->im_v_codec == CODEC_YUV)
2089 	{
2090 	b = image_width / 4;
2091 	c = image_width / 2;
2092 
2093 	py = ImageData;
2094 	pu = ImageData + (image_width * image_height * 5) / 4;
2095 	pv = ImageData + (image_width * image_height);
2096 
2097 	a = (int)pa -> ypos * image_width;
2098 	py += (int)pa -> xpos + a;
2099 	a /= 4;
2100 	pu += ( (int)pa -> xpos / 2) + a;
2101 	pv += ( (int)pa -> xpos / 2) + a;
2102 
2103 	ps = pa -> data;
2104 
2105 	if( (int)pa -> ypos % 2 )
2106 		{
2107 		pu -= b;
2108 		pv -= b;
2109 		}
2110 
2111 	// reading sequence is YUYV, so U is first.
2112 	u_time = 1;
2113 	for(y = 0; y < (int)pa -> ysize; y++)
2114 		{
2115 		odd_line = (y + (int)pa -> ypos) % 2;
2116 
2117 		for(x = 0; x < (int)pa -> xsize; x++)
2118 			{
2119 			/* find out if OK to display */
2120 			in_range = 1;
2121 			/* clip right scroll */
2122 			if( (x + (int)pa -> xpos) > image_width) in_range = 0;
2123 
2124 			/* clip left scroll */
2125 			if( (x + (int)pa -> xpos ) < 0) in_range = 0;
2126 
2127 			/* clip top scroll */
2128 			if( (y + (int)pa -> ypos) > image_height) in_range = 0;
2129 
2130 			/* clip bottom scroll */
2131 			if( (y + (int)pa -> ypos) < 0) in_range = 0;
2132 
2133 			/* slice level */
2134 			a = *ps;
2135 			if(a < 0) a += 256;
2136 			if( a < ( (int)pa -> slice_level) ) in_range = 0;
2137 
2138 			if(\
2139 			(pa -> zrotation != 0) ||\
2140 			(pa -> xshear != 0) || (pa -> yshear != 0)\
2141 			)
2142 				{
2143 				/*
2144 				for rotate and shear, the luminance value of the border
2145 				to cut away.
2146 				Since this would remove picture data, for this not to
2147 				happen, we add 1 step to the luminance if it happens to
2148 				be the same as border_luminanc in yuv_to_ppm().
2149 				With this trick it is guaranteed border_luminance never happens
2150 				in the .ppm file that mogrify processes.
2151 				*/
2152 				if(pa -> mask_level)
2153 					{
2154 					if(a == pa -> mask_level) in_range = 0;
2155 					}
2156 				else
2157 					{
2158 					if(a == default_border_luminance) in_range = 0;
2159 					}
2160 				} /* end if rotate or shear */
2161 
2162 			/* test for chroma key match if color specified */
2163 			if(pa -> chroma_key_saturation)
2164 				{
2165 				if(u_time)
2166 					{
2167 					if(! odd_line)
2168 						{
2169 						a = (int)pu[x / 2] - 128;
2170 						b = (int)pv[x / 2] - 128;
2171 						ck_flag =\
2172 						chroma_key(\
2173 						a, b,\
2174 						pa -> chroma_key_color,\
2175 						pa -> chroma_key_window,\
2176 						pa -> chroma_key_saturation);
2177 						} /* end if even line */
2178 					else
2179 						{
2180 						a = (int)pu[(x / 2) + c] - 128;
2181 						b = (int)pv[(x / 2) + c] - 128;
2182 						ck_flag =\
2183 						chroma_key(\
2184 						a, b,\
2185 						pa -> chroma_key_color,\
2186 						pa -> chroma_key_window,\
2187 						pa -> chroma_key_saturation);
2188 						} /* end if odd line */
2189 					} /* end if u_time */
2190 
2191 				/* transport to next time here ! */
2192 				if(! ck_flag) in_range = 0;
2193 				} /* end if chroma key */
2194 
2195 			if(in_range)
2196 				{
2197 				py[x] *= dd;
2198 				py[x] += dc * (uint8_t)*ps;
2199 				} /* end if in_range */
2200 
2201 			ps++;
2202 
2203 			if(in_range)
2204 				{
2205 				if(u_time)
2206 					{
2207 					ca = *ps;
2208 					ca = 128 + ( ( (uint8_t)*ps - 128 ) * ds);
2209 
2210 					pu[x / 2] *= dd;
2211 					pu[x / 2] += dm * (uint8_t)ca;
2212 					}
2213 				else
2214 					{
2215 					ca = *ps;
2216 					ca = 128 + ( ( (uint8_t)*ps - 128 ) * ds);
2217 
2218 					pv[x / 2] *= dd;
2219 					pv[x / 2] += dm * (uint8_t)ca;
2220 					}
2221 
2222 				/* apply hue correction if both U and V set */
2223 
2224 //				if(! u_time)
2225 					{
2226 					if(pa -> hue)
2227 						{
2228 						/*
2229 						hue,
2230 						saturation done outside adjust_color() for speed
2231 						*/
2232 
2233 						a = (int)pu[x / 2] - 128;
2234 						b = (int)pv[x / 2] - 128;
2235 						adjust_color(&a, &b, pa -> hue, 100.0);
2236 						pu[x / 2] = (uint8_t)a + 128;
2237 						pv[x / 2] = (uint8_t)b + 128;
2238 
2239 						} /* end if hue */
2240 
2241 					} /* end if ! u_time */
2242 				} /* end if in range */
2243 
2244 			ps++;
2245 			u_time = 1 - u_time;
2246 
2247 			} /* end for all x */
2248 
2249 		if( (int) pa -> xsize % 2) u_time = 1 - u_time;
2250 
2251 		py += image_width;
2252 
2253 		if(odd_line)
2254 			{
2255 			pu += c;
2256 			pv += c;
2257 			}
2258 
2259 		} /* end for all y */
2260 
2261 	} /* end if YUV 420 */
2262 
2263 return 1;
2264 }/* end function add_picture */
2265 
2266 
set_main_movie_properties(struct object * pa)2267 int set_main_movie_properties(struct object *pa)
2268 {
2269 if(debug_flag)
2270 	{
2271 	tc_log_info(MOD_NAME, "set_main_movie_properties(): arg pa=%lu", (unsigned long)pa);
2272 	}
2273 
2274 if(! pa) return 0;
2275 
2276 dcontrast = pa -> contrast;
2277 brightness = (int)pa -> brightness;
2278 dsaturation = pa -> saturation;
2279 dhue = pa -> hue;
2280 dhue_line_drift = pa -> hue_line_drift;
2281 u_shift = (int)pa -> u_shift;
2282 v_shift = (int)pa -> v_shift;
2283 de_stripe_flag = (int)pa -> de_stripe;
2284 show_output_flag = (int)pa -> show_output;
2285 
2286 return 1;
2287 } /* end function set_main_movie_properties */
2288 
2289 
rgb_to_yuv(int r,int g,int b,int * y,int * u,int * v)2290 int rgb_to_yuv(int r, int g, int b, int *y, int *u, int *v)
2291 {
2292 double dr, dg, db, dy, du, dv;
2293 
2294 if(debug_flag)
2295 	{
2296 	tc_log_info(MOD_NAME, "rgb_to_yuv(): arg r=%d g=%d b=%d", r, g, b);
2297 	}
2298 
2299 dr = (double) r;
2300 dg = (double) g;
2301 db = (double) b;
2302 
2303 /* acy, acu, acv pre-calculated in init */
2304 /* convert to YUV */
2305 
2306 /* test yuv coding here */
2307 dy = acr * dr + acg * dg + acb * db;
2308 
2309 dy = (219.0 / 256.0) * dy + 16.5;  /* nominal range: 16..235 */
2310 
2311 du = acu * (db - dy);
2312 du = (224.0 / 256.0) * du; // + 128.5; /* 16..240 */
2313 
2314 dv = acv * (dr - dy);
2315 dv = (224.0 / 256.0) * dv; // + 128.5; /* 16..240 */
2316 
2317 *y = (int) dy;
2318 *u = (int) du;
2319 *v = (int) dv;
2320 
2321 return 1;
2322 } /* end function rgb_to_yuv */
2323 
2324