1 /*
2  * @(#)SUBPICTURE.java - creates SUP file to use as DVD subtitles
3  *
4  * Copyright (c) 2003-2009 by dvb.matt, All Rights Reserved.
5  *
6  * This file is part of ProjectX, a free Java based demux utility.
7  * By the authors, ProjectX is intended for educational purposes only,
8  * as a non-commercial test project.
9  *
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 
27 /*
28  * thanx to Samuel Hocevar for his very helpful annotations of DVD subtitle RLE stuff
29  * http://sam.zoy.org/writings/dvd/subtitles/
30  */
31 /*
32  * multicolor subtitling patch (UK Freeview) by Duncan (Shannock9) UK
33  * 2008-12
34  */
35 
36 
37 package net.sourceforge.dvb.projectx.subtitle;
38 
39 //
40 import java.awt.Image;
41 
42 import java.awt.Color;
43 import java.awt.Dimension;
44 import java.awt.Font;
45 import java.awt.Graphics;
46 import java.awt.Graphics2D;
47 import java.awt.event.WindowAdapter;
48 import java.awt.event.WindowEvent;
49 import java.awt.font.FontRenderContext;
50 import java.awt.image.BufferedImage;
51 import java.awt.geom.Rectangle2D;
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.StringTokenizer;
57 
58 import net.sourceforge.dvb.projectx.common.Resource;
59 import net.sourceforge.dvb.projectx.common.Keys;
60 import net.sourceforge.dvb.projectx.common.Common;
61 
62 import net.sourceforge.dvb.projectx.parser.CommonParsing;
63 
64 
65 public class Subpicture extends Object {
66 
67 	private int w = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1920 : 720;
68 	private int h = Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_enableHDSub) ? 1088 : 576;
69 	private int x = 20;
70 	private int nibble = 0;
71 	private int val = 0;
72 	private int default_alpha = 10;
73 	private int modified_alpha = 0;
74 
75 	private BufferedImage bimg;
76 	private Graphics2D big;
77 	private Font font, font_std;
78 	private FontRenderContext frc;
79 
80 	private final int default_teletext_colors[] = {
81 		//bg = 0 = black
82 		0xFF606060, //Y 40%
83 		0xFFEB6060, //red lighter
84 		0xFF10EB10, //green
85 		0xFFEBEB10, //yellow
86 		0xFF5050EB, //blue lighter
87 		0xFFEB60EB, //magenta lighter
88 		0xFF10EBEB, //cyan
89 		0xFFEBEBEB, //Y 100%
90 
91 		//bg = 1 = red
92 		0xFF606060, //Y black
93 		0xFFE06060, //red
94 		0xFF60E060, //green
95 		0xFFE0E060, //yellow
96 		0xFF6060E0, //blue
97 		0xFFE060E0, //magenta
98 		0xFF60E0E0, //cyan
99 		0xFFE0E0E0, //white-gray
100 
101 		//bg = 2 = green
102 		0xFF707070, //Y black
103 		0xFFD07070, //red
104 		0xFF70D070, //green
105 		0xFFD0D070, //yellow
106 		0xFF7070D0, //blue
107 		0xFFD070D0, //magenta
108 		0xFF70D0D0, //cyan
109 		0xFFD0D0D0, //white-gray
110 
111 		//bg = 3 = yellow
112 		0xFF808080, //Y black
113 		0xFFC08080, //red
114 		0xFF80C080, //green
115 		0xFFC0C080, //yellow
116 		0xFF8080C0, //blue
117 		0xFFC080C0, //magenta
118 		0xFF80C0C0, //cyan
119 		0xFFC0C0C0, //white-gray
120 
121 		//bg = 4 = blue
122 		0xFF909090, //Y black
123 		0xFFC09090, //red
124 		0xFF90C090, //green
125 		0xFFC0C090, //yellow
126 		0xFF9090C0, //blue
127 		0xFFC090C0, //magenta
128 		0xFF90C0C0, //cyan
129 		0xFFB0B0B0, //white-gray
130 
131 		//bg = 5 = magenta
132 		0xFFA0A0A0, //Y black
133 		0xFFB0A0A0, //red
134 		0xFFA0B0A0, //green
135 		0xFFB0B0A0, //yellow
136 		0xFFA0A0B0, //blue
137 		0xFFB0A0B0, //magenta
138 		0xFFA0B0B0, //cyan
139 		0xFFA0A0A0, //white-gray
140 
141 		//bg = 6 = cyan
142 		0xFFB0B0B0, //Y black
143 		0xFFC0A0A0, //red
144 		0xFFA0D0A0, //green
145 		0xFFC0D0A0, //yellow
146 		0xFFA0A0D0, //blue
147 		0xFFD0A0D0, //magenta
148 		0xFFA0D0D0, //cyan
149 		0xFF909090, //white-gray
150 
151 		//bg = 7 = white
152 		0xFFD0D0D0, //Y black
153 		0xFFE09090, //red
154 		0xFF90E090, //green
155 		0xFFE0E090, //yellow
156 		0xFF9090E0, //blue
157 		0xFFE090E0, //magenta
158 		0xFF90E0E0, //cyan
159 		0xFF808080, //white-gray
160 
161 		0, // backgr black, user_transparency
162 		0x80 // backgr blue, sign for full transparency
163 	};
164 
165 	private final int default_sup_colors[] = {
166 		0xFF101010, //black
167 		0xFFA0A0A0, //Y 50%
168 		0xFFEBEBEB, //Y 100%
169 		0xFF606060, //Y 25%
170 		0xFFEB1010, //red
171 		0xFF10EB10, //green
172 		0xFFEBEB10, //yellow
173 		0xFF1010EB, //blue
174 		0xFFEB10EB, //magenta
175 		0xFF10EBEB, //cyan
176 		0xFFEB8080, //red lighter
177 		0xFF80EB80, //green lighter
178 		0xFFEBEB80, //yellow lighter
179 		0xFF8080EB, //blue lighter
180 		0xFFEB80EB, //magante lighter
181 		0xFF80EBEB, //cyan lighter
182 		0 // full transparency black bg
183 	};
184 
185 	private int[] alternative_sup_colors = new int[17];
186 
187 	private Object[] str = new Object[0];
188 
189 	private byte[] RLEheader = { 0x53,0x50,0,0,0,0,0,0,0,0,0,0,0,0 }; // startcode + later reverse 5PTS, DTS=0
190 	private byte[] sections = {
191 		0, 0,           // next contr sequ.
192 		3, 0x32, 0x10,         // color palette linkage
193 		4, (byte)0xFF, (byte)0xFA,         // color alpha channel linkage F=opaque
194 		5, 0, 0, 0, 0, 0, 0, // coordinates Xa,Ya,Xe,Ye
195 		6, 0, 0, 0, 0,     // bytepos start top_field, start bottom_field
196 		1,  // start displ.  //0 means force display
197 		(byte)0xFF,    // end of sequ.
198 		1, 0x50,  // time for next sequ,
199 		0, 0,  //next contr sequ.
200 		2,   // stop displ.
201 		(byte)0xFF     // end of sequ: timedur in pts/1100, size s.a. , add 0xFF if size is not WORD aligned
202 	};
203 
204 	private ByteArrayOutputStream out = new ByteArrayOutputStream();
205 
206 	private byte newline[] = { 0,0 };
207 
208 	private int Rect[] = new int[4];
209 	private int pos[] = new int[4];
210 	private int option[] = new int[11];
211 	private int standard_values[] = { 26, 10, 32, 80, 560, 720, 576, -1, 4, 3, 1 };
212 	private int isforced_status = 0;
213 	private int ismulticolor_status = 0;
214 	private int line_offset = 28;
215 
216 	private ArrayList user_color_table = new ArrayList();
217 	private Bitmap bitmap;
218 
219 	private boolean read_from_Image = false;
220 	private boolean global_error = false;
221 
222 	private int X_Offset = 0;
223 	private int Y_Offset = 0;
224 	private int DisplayMode = 0;
225 
226 
227 	public DVBSubpicture dvb = new DVBSubpicture();
228 
229 	public ColorAreas s9CA = new ColorAreas();                                                   //S9
230 
231 	/**
232 	 *
233 	 */
Subpicture()234 	public Subpicture()
235 	{
236 		bimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
237 		big = bimg.createGraphics();
238 
239 		set("Tahoma", ("26;10;32;80;560;720;576;-1;4;3;1"));
240 		frc = big.getFontRenderContext();
241 
242 		//   big.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
243 	}
244 
245 	/**
246 	 *
247 	 */
repaint()248 	public void repaint()
249 	{
250 		if (big == null)
251 			return;
252 
253 		Common.getGuiInterface().repaintSubpicture();
254 	}
255 
256 	/**
257 	 *
258 	 */
getImage()259 	public Image getImage()
260 	{
261 		return bimg;
262 	}
263 
264 	/**
265 	 *
266 	 */
getScaledImage(int scaled_w, int scaled_h)267 	public Image getScaledImage(int scaled_w, int scaled_h)
268 	{
269 		return bimg.getScaledInstance(scaled_w, scaled_h, Image.SCALE_FAST);
270 	}
271 
272 	/**
273 	 * paint any picture, for export it should only have 2bit depth
274 	 */
paintPicture(byte[] array, int _width, int _height, int _scansize, int _x, int _y)275 	public void paintPicture(byte[] array, int _width, int _height, int _scansize, int _x, int _y)
276 	{
277 		big.setColor(Color.gray);
278 		big.fillRect(0, 0, w, h);
279 	//	bimg.setRGB(_x, _y, _width, _height, array, 0, _scansize);
280 
281 		repaint();
282 	}
283 
284 	/**
285 	 * paint pic from ttx
286 	 */
showPicTTX(Object[] _str, Object obj)287 	public void showPicTTX(Object[] _str, Object obj)
288 	{
289 		str = _str;
290 		buildImgTTX(obj);
291 		repaint();
292 	}
293 
294 	/**
295 	 * set display time
296 	 */
setTime(byte tmp[], long out_time)297 	public byte[] setTime(byte tmp[], long out_time)
298 	{
299 		long in_time = 0;
300 
301 		for (int a = 0; a < 4; a++) // in_pts, from offs 2
302 			in_time |= (0xFF & tmp[a + 2])<<(a * 8);
303 
304 		//long difference = (long)Math.round((out_time - in_time) / 1100.0); // 900.0, should be 1024, not 1000
305 		long difference = 1L + ((out_time - in_time) / 1024);
306 
307 		int tp = (0xFF & tmp[12])<<8 | (0xFF & tmp[13]);
308 		tmp[34 + tp] = (byte)(0xFF & difference>>>8);
309 		tmp[35 + tp] = (byte)(0xFF & difference);
310 
311 		Common.getGuiInterface().setSubpictureTitle(" / " + Resource.getString("subpicture.in_time") + ": " + Common.formatTime_1(in_time / 90) + " " + Resource.getString("subpicture.duration") + ": " + Common.formatTime_1((out_time - in_time) / 90) );
312 
313 	//	if (debug)
314 	//		System.out.println("in " + in_time + "/out " + out_time + "/d1 " + (out_time - in_time) + "/90 " + ((out_time - in_time)/90) + "/d2 " + difference);
315 
316 		return tmp;
317 	}
318 
319 	/**
320 	 * build Image from text
321 	 */
buildImgTTX(Object obj)322 	private void buildImgTTX(Object obj)
323 	{
324 		int space = 6;
325 
326 		Rect[0] = option[3];
327 		Rect[3] = (2 * space) + (line_offset * str.length);
328 		Rect[1] = option[6] - option[2] - Rect[3];
329 		Rect[2] = option[4];
330 
331 		pos[0] = Rect[0];
332 		pos[1] = Rect[1];
333 		pos[2] = Rect[0] + Rect[2] - 1;
334 		pos[3] = Rect[1] + Rect[3] - 1;
335 
336 		paintVideoSize(obj);
337 
338 		big.setColor(Color.white);
339 		big.drawRect(Rect[0] - 1, Rect[1] - 1, Rect[2] + 1, Rect[3] + 1);
340 		big.setFont(font_std);
341 		big.drawString("x" + pos[0] + ", y" + pos[1] + " / " + (pos[2] - pos[0] + 1) + "*" + (pos[3] - pos[1] + 1), Rect[0] - 1, Rect[1] - 5);
342 
343 		int color_table[] = getColorTable(1);
344 
345 		big.setFont(font);
346 
347 		ArrayList list = new ArrayList();
348 		boolean antialiasing;
349 
350 		/**
351 		 * pre-check, whether we have not more than 2 'speaker-colors'
352 		 */
353 		for (int a = 0; a < str.length; a++)
354 		{
355 			int[] chars = (int[])str[a];
356 
357 			for (int b = 0; b < chars.length; b++)
358 			{
359 				//source background color
360 				int offset = (7 & chars[b]>>>4)<<3;
361 
362 				//source modified foreground color
363 				int paint_color = color_table[offset + (7 & chars[b])];
364 				String nstr = Integer.toString(paint_color);
365 				String sign = new Character((char)(chars[b]>>>8)).toString();
366 
367 				//remember new color
368 				if (list.indexOf(nstr) < 0 && !sign.equals(" "))
369 					list.add(nstr);
370 			}
371 		}
372 
373 		/**
374 		 * define background; if less than 3 front-colors, use 'simple' antialiasing with full transparency
375 		 */
376 		if (list.size() < 3 && Common.getSettings().getBooleanProperty(Keys.KEY_SubtitlePanel_useTextOutline))
377 		{
378 			big.setColor(new Color(color_table[65])); // deep blue, full transp
379 			modified_alpha = 0;
380 			antialiasing = true;
381 		}
382 		else
383 		{
384 			big.setColor(new Color(color_table[64])); // black, half transp
385 			modified_alpha = default_alpha;
386 			antialiasing = false;
387 		}
388 
389 		big.fillRect(Rect[0], Rect[1], Rect[2], Rect[3]); // background
390 
391 		Rectangle2D r;
392 
393 		// paint background of char
394 		for (int a = 0; antialiasing && a < str.length; a++)
395 		{
396 			int[] chars = (int[])str[a];
397 			String nstr = "";
398 
399 			big.setColor(new Color(color_table[64])); // black
400 
401 			/**
402 			 * concatenate string, no special colors required
403 			 */
404 			for (int i = 0; i < chars.length; i++)
405 				nstr += new Character((char)(chars[i]>>>8)).toString();
406 
407 			x = option[3];
408 			int y = Rect[1] + (line_offset * (1 + a));
409 
410 			int[] offs = new int[(option[9] * 2) + 1];
411 
412 			/**
413 			 * overhead around a pixel: x pix WEST, 1 pix MID, x pix EAST
414 			 * pix > 4 not recommended, option[9] = outline_pixels
415 			 */
416 			offs[0] = offs[offs.length - 1] = option[9] - 1;
417 			Arrays.fill(offs, 1, offs.length - 1, option[9]);
418 
419 			for (int i = 0; i < offs.length; i++) // horiz. lines
420 			{
421 				int _x = x;
422 				int _y = y - (offs.length / 2) + i;
423 
424 				for (int j = -offs[i]; j < offs[i] + 1; j++)
425 					big.drawString(nstr, _x + j, _y);
426 			}
427 		}
428 
429 
430 		// paint ascii char
431 		for (int a=0; a < str.length; a++)
432 		{
433 			int[] chars = (int[])str[a];
434 			x = option[3];
435 
436 			for (int b=0; b < chars.length; b++)
437 			{
438 				//source background color
439 				int offset = (7 & chars[b]>>>4)<<3;
440 
441 				//source foreground color
442 				big.setColor(new Color(color_table[offset + (7 & chars[b])]));
443 				big.drawString("" + (char)(chars[b]>>>8), x, Rect[1] + (line_offset * (1 + a)));
444 
445 				x += font.getStringBounds("" + (char)(chars[b]>>>8), frc).getWidth();
446 			}
447 		}
448 	}
449 
resetUserColorTable()450 	public void resetUserColorTable()
451 	{
452 		user_color_table.clear();
453 	}
454 
getUserColorTableArray()455 	public Object[] getUserColorTableArray()
456 	{
457 		return user_color_table.toArray();
458 	}
459 
getUserColorTable()460 	public ArrayList getUserColorTable()
461 	{
462 		return user_color_table;
463 	}
464 
updateUserColorTable(Bitmap new_bitmap)465 	public void updateUserColorTable(Bitmap new_bitmap)
466 	{
467 		bitmap = new_bitmap;
468 
469 		int pixel[] = bitmap.getPixel();
470 
471 		for (int a=0; a < pixel.length; a++)
472 		{
473 			String pixel_str = "" + pixel[a];
474 
475 			if (!user_color_table.contains(pixel_str))
476 				user_color_table.add(pixel_str);
477 
478 			bitmap.getColorIndex(getUserColorTableIndex(pixel[a]));
479 		}
480 	}
481 
updateUserColorTable(int pixel[])482 	private void updateUserColorTable(int pixel[])
483 	{
484 		for (int a=0; a < pixel.length; a++)
485 		{
486 			String pixel_str = "" + pixel[a];
487 
488 			if (user_color_table.contains(pixel_str))
489 				continue;
490 
491 			else
492 				user_color_table.add(pixel_str);
493 		}
494 	}
495 
getUserColorTableIndex(int color_index)496 	private int getUserColorTableIndex(int color_index)
497 	{
498 		int value;
499 
500 		if ((value = user_color_table.indexOf("" + color_index)) < 0)
501 			return 0;
502 
503 		return value;
504 	}
505 
writeRLE(long start_time, int onscreen_time)506 	public byte[] writeRLE(long start_time, int onscreen_time) throws IOException
507 	{
508 		read_from_Image = true; // use user defined alpha value for color index 0
509 
510 		bitmap = new Bitmap( Rect[0], Rect[1], Rect[2], Rect[3], bimg.getRGB(Rect[0], Rect[1], Rect[2], Rect[3], null, 0, Rect[2]), 2, 0, 1, 2, start_time, onscreen_time);
511 
512 		return buildRLE();
513 	}
514 
writeRLE(Bitmap new_bitmap)515 	public byte[] writeRLE(Bitmap new_bitmap) throws IOException
516 	{
517 		bitmap = new_bitmap;
518 		setArea();
519 
520 		return buildRLE();
521 	}
522 
buildRLE()523 	private byte[] buildRLE()
524 	{
525 		byte picture_packet[] = null;
526 
527 		try {
528 
529 			if (ColorAreas.active)  			               //multicolor DVB to SUP active        //S9
530 				resetUserColorTable();                         //so retention counterproductive      //S9
531 
532 			updateUserColorTable(bitmap.getPixel());           //base code re-ordered                //S9
533 
534 			if (ColorAreas.active)  			               //multicolor DVB to SUP active        //S9
535 				s9CA.analyse(bitmap, getUserColorTable());     //which can correct noisy pixels!!    //S9
536 
537 			int pixels[] = bitmap.getPixel();                  //base code re-ordered                //S9
538 
539 			out.reset();
540 			out.write(RLEheader);   //start picture in .sup form
541 
542 			int bottom_field_start_pos = 0;
543 			int pgc_color = 0;                                 //holds bp12 for a run of pixels      //S9
544 
545 			// read out interlaced RGB
546 			for (int i = 0, l = 0, a = 0, b = 0, color_index = 0; i < 2; i++)
547 			{
548 				// top_field first
549 				for (l = 0, color_index = 0, a = i * bitmap.getWidth(); a < pixels.length; a += (2 * bitmap.getWidth()))
550 				{
551 					for (l = 0, color_index = 0, b = 0; b < bitmap.getWidth(); b++, l++)
552 					{
553 						if (ColorAreas.active)                 //multicolor DVB to SUP active        //S9
554 							pgc_color = s9CA.bp12[a + b];      //bp12 was filled during analyse()    //S9
555 						else                                   //pre-existing approach but fewer runs//S9
556 						{
557 							pgc_color = pixels[a + b];
558 					//		pgc_color = bitmap.getColorIndex(getUserColorTableIndex(color_index));   //S9
559 					//		pgc_color = bitmap.getColorIndex(pgc_color);
560 						}
561 
562 						if (s9CA.active && s9CA.dbgline() == a / bitmap.getWidth())   //see every pixel on specific dbgline //S9dbg
563 						{
564 							int q = s9CA.getQuant(getUserColorTableIndex(pixels[a + b]));    //quant as Integer  //S9dbg
565 
566 							System.out.println("dbg line " + s9CA.d(3, a / bitmap.getWidth()) + "/x " + s9CA.d(3, b)       //S9dbg
567 							+ "/pixel " + s9CA.X(8, pixels[a + b]) + "/clr_ndx " + s9CA.X(2, color_index)                 //S9dbg
568 							+ "/pgc_clr " + s9CA.X(2, pgc_color) + "/Q " + s9CA.X(8, q) + "/run " + s9CA.d(3, l));
569 						}           //S9dbg
570 
571 						if (pgc_color != color_index)                                                //S9
572 						{
573 							// write last RLE nibbles, while color change
574 							updateRLE(l, color_index);
575 							color_index = pgc_color;                                                 //S9
576 							l = 0;
577 						}
578 						else if ( l > 254 )
579 						{
580 							// write last RLE nibbles, cannot incl. more than 255 pixels
581 							updateRLE(l, color_index);
582 							l = 0;
583 						}
584 						// std: adds l-bit to active color
585 					}
586 
587 					// when last pixel is length = 1 then it will be 0 and missing ?
588 					// see CR
589 					//l -= 1;
590 
591 					while ( l > 255 )  // never used ?!
592 					{
593 						updateRLE(255, color_index);
594 						l -= 255;
595 					}
596 
597 					updateRLE(l, color_index);   // write last RLE nibbles, line end
598 					alignRLE();
599 
600 					if (b < bitmap.getWidth()) //fix, add CR only when less pixel have been painted
601 						out.write(newline);  // new line CR, byte aligned
602 				}
603 
604 				alignRLE();
605 
606 				if (bottom_field_start_pos == 0)
607 					bottom_field_start_pos = out.size() - 10;        // save startpos of bottom_field (size-14)
608 			}
609 
610 			if (ColorAreas.active)                                     //++multicolor DVB to SUP active++    //S9
611 			{                                                                                                //S9
612 					//commands() must encapsulate command buffer design - do not patch command buffer from   //S9
613 					//here.  All delay timing fields will be set by commands() from information in bitmap    //S9
614 
615 				int command_start_pos = out.size() - 10;        //offset in subpic >including 1st delay< //S9
616 
617 				out.write(s9CA.commands(command_start_pos, bottom_field_start_pos, bitmap));//cmd buffer //S9
618 
619 				if ((out.size() & 1) == 1)
620 					out.write((byte)255);
621 
622 				out.flush();
623 
624 				//Fixups to integrate command buffer into subpic are legitimate part of this method      //S9
625 				//Note "0xFF &" is redundant - the (byte) cast does that anyway.   Mask only needed      //S9
626 				//for moving byte to int (implicitly or explicitly) to overcome any sign extension.      //S9
627 
628 				picture_packet = out.toByteArray();
629 
630 				int size = picture_packet.length - 10;
631 
632 				picture_packet[10] = (byte)(0xFF & size>>>8);
633 				picture_packet[11] = (byte)(0xFF & size);
634 				picture_packet[12] = (byte)(0xFF & command_start_pos>>>8);                               //S9
635 				picture_packet[13] = (byte)(0xFF & command_start_pos);                                   //S9
636 
637 				for (int a = 0; a < 4; a++)
638 					picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8));
639 			}                                                                                                //S9
640 			else                                                   //++original code pre multicolor DVB++    //S9
641 			{                                                                                                //S9
642 
643 				out.write(newline);  //DM26052004 081.7 int03 add , not the best solution, but need the "0,0" here
644 
645 				int pack = out.size() - 12;
646 				int control_block_pos = pack + 24;
647 				int onscreen_time_pos = out.size() + 22;
648 
649 				setScreenPosition(bitmap.getX(), bitmap.getY(), bitmap.getMaxX() - 1, bitmap.getMaxY() - 1);
650 				setControlBlockPosition(control_block_pos, bottom_field_start_pos);
651 				setPGCsection();
652 
653 				out.write(sections);  //write control_block
654 
655 				if ((out.size() & 1) == 1)
656 					out.write((byte)255);
657 
658 				out.flush();
659 
660 				picture_packet = out.toByteArray();
661 
662 				int size = picture_packet.length - 10;
663 
664 				picture_packet[10] = (byte)(0xFF & size>>>8);
665 				picture_packet[11] = (byte)(0xFF & size);
666 				picture_packet[12] = (byte)(0xFF & pack>>>8);
667 				picture_packet[13] = (byte)(0xFF & pack);
668 
669 				for (int a = 0; a < 4; a++)
670 					picture_packet[a + 2] = (byte)(0xFF & bitmap.getInTime()>>>(a * 8));
671 
672 				picture_packet[onscreen_time_pos] = (byte)(0xFF & bitmap.getPlayTime()>>>8);
673 				picture_packet[onscreen_time_pos + 1] = (byte)(0xFF & bitmap.getPlayTime());
674 			}                                                //++endif original code pre multicolor DVB++    //S9
675 
676 			if (s9CA.dbgSub(1))
677 				s9CA.dumpHdrAndCmd(picture_packet);         //so what was generated?         //S9dbg
678 
679 		} catch (IOException e) {
680 
681 			Common.setExceptionMessage(e);
682 		}
683 
684 		read_from_Image = false;
685 
686 		return picture_packet;
687 	}
688 
689 	// write last nibble, if it was not aligned
alignRLE()690 	private void alignRLE()
691 	{
692 		if (nibble == 0)
693 			return;
694 
695 		else
696 		{
697 			out.write((byte)val);
698 			val = nibble = 0;
699 		}
700 	}
701 
702 //	private void updateRLE(int l, int pgc_color)                                                 //S9
updateRLE(int l, int color_index)703 	private void updateRLE(int l, int color_index)                                                 //S9
704 	{
705 		if (l < 1)
706 			return;
707 
708 		//pgc_color shall not exceed value 3!                                                    //S9
709 		int pgc_color = getUserColorTableIndex(color_index);
710 
711 		//look-up of pgc_color refactored to caller <= it's the RESOLVED 2 bits we want runs of  //S9
712 		if (ColorAreas.active)
713 			pgc_color = color_index;
714 		else
715 			pgc_color = bitmap.getColorIndex(pgc_color);
716 
717 		l = l<<2 | pgc_color;  // combine bits + color_index
718 
719 		// new byte begin
720 		if (nibble == 0)
721 		{
722 			if (l > 0xFF) // 16
723 			{
724 				out.write((byte)(0xFF & l>>>8));
725 				out.write((byte)(0xFF & l));
726 			}
727 			else if (l > 0x3F)  // 12
728 			{
729 				out.write((byte)(0xFF & l>>>4));
730 				val = 0xF0 & l<<4;
731 				nibble = 4;
732 			}
733 			else if (l > 0xF)  // 8
734 			{
735 				out.write((byte)(0xFF & l));
736 			}
737 			else   // 4
738 			{
739 				val = 0xF0 & l<<4;
740 				nibble = 4;
741 			}
742 		}
743 		else  // middle of byte
744 		{
745 			if (l > 0xFF) // 16
746 			{
747 				out.write((byte)(val | (0xF & l>>>12)));
748 				out.write((byte)(0xFF & l>>>4));
749 				val = 0xF0 & l<<4;
750 			}
751 			else if (l > 0x3F) // 12
752 			{
753 				out.write((byte)(val | (0xF & l>>>8)));
754 				out.write((byte)(0xFF & l));
755 				val = nibble = 0;
756 			}
757 			else if (l > 0xF)  // 8
758 			{
759 				out.write((byte)(val | (0xF & l>>>4)));
760 				val = 0xF0 & l<<4;
761 			}
762 			else  // 4
763 			{
764 				out.write((byte)(val | (0xF & l)));
765 				val = nibble = 0;
766 			}
767 		}
768 	}
769 
setScreenPosition(int minX, int minY, int maxX, int maxY)770 	private void setScreenPosition(int minX, int minY, int maxX, int maxY)
771 	{
772 		// set planned pic pos. on tvscreen
773 		sections[9]  = (byte)(minX>>>4);
774 		sections[10] = (byte)(minX<<4 | maxX>>>8);
775 		sections[11] = (byte)maxX;
776 		sections[12] = (byte)(minY>>>4);
777 		sections[13] = (byte)(minY<<4 | maxY>>>8);
778 		sections[14] = (byte)maxY;
779 	}
780 
setControlBlockPosition(int control_block_pos, int bottom_field_start_pos)781 	private void setControlBlockPosition(int control_block_pos, int bottom_field_start_pos)
782 	{
783 		// top_field
784 		sections[16] = 0;
785 		sections[17] = 4;
786 
787 		// bottom_field
788 		sections[18] = (byte)(0xFF & bottom_field_start_pos>>>8);
789 		sections[19] = (byte)(0xFF & bottom_field_start_pos);
790 
791 		// control_block
792 		sections[0] = sections[24] = (byte)(0xFF & control_block_pos>>>8);
793 		sections[1] = sections[25] = (byte)(0xFF & control_block_pos);
794 	}
795 
setPGCsection()796 	private void setPGCsection()
797 	{
798 		int pgc_values = setPGClinks();
799 
800 		// color index 3,2 + 1,0
801 		sections[3] = (byte)(0xFF & pgc_values>>>8);
802 		sections[4] = (byte)(0xFF & pgc_values);
803 
804 		// alpha index 3,2 + 1,0
805 		sections[6] = (byte)(0xFF & pgc_values>>>24);
806 		sections[7] = (byte)(0xFF & pgc_values>>>16);
807 	}
808 
setPGClinks()809 	public int setPGClinks()
810 	{
811 		Object pgc_color_links[] = bitmap.getColorIndices();
812 		Object pgc_alpha_links[] = getUserColorTableArray();
813 		int pgc_colors = 0xFE10;
814 		int pgc_alphas = 0xFFF9;
815 		int pgc_color_value, pgc_alpha_value;
816 
817 		for (int a=0; a < 4; a++)
818 		{
819 			if (a < pgc_color_links.length)
820 			{
821 				pgc_color_value = 0xF & Integer.parseInt(pgc_color_links[a].toString());
822 				pgc_alpha_value = 0xF & Integer.parseInt(pgc_alpha_links[pgc_color_value].toString())>>>28;
823 				pgc_colors = (pgc_colors & ~(0xF<<(a * 4))) | pgc_color_value<<(a * 4);
824 				pgc_alphas = (pgc_alphas & ~(0xF<<(a * 4))) | pgc_alpha_value<<(a * 4);
825 			}
826 		}
827 
828 		if (read_from_Image)
829 		//	pgc_alphas &= (0xFFF0 | default_alpha);
830 			pgc_alphas &= (0xFFF0 | modified_alpha);
831 
832 		return (pgc_alphas<<16 | pgc_colors);
833 	}
834 
set2()835 	public void set2()
836 	{
837 		option[2] = option[7];
838 	}
839 
getMaximumLines()840 	public int getMaximumLines()
841 	{
842 		return option[8];
843 	}
844 
845 	/*** set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth"); **/
set(String nm, String values)846 	public int[] set(String nm, String values)
847 	{
848 		return set(nm, values, false);
849 	}
850 
851 	/*** set user packet ("Font pointsize; Backgr. Alpha value; Yoffset; Xoffset; Screenwidth"); **/
set(String nm, String values, boolean keepColourTable)852 	public int[] set(String nm, String values, boolean keepColourTable)
853 	{
854 		if (!keepColourTable)
855 			resetUserColorTable();
856 
857 		System.arraycopy(standard_values, 0, option, 0, standard_values.length);
858 
859 		StringTokenizer st = new StringTokenizer(values, ";");
860 		int a = 0;
861 
862 		while (st.hasMoreTokens() && a < option.length)
863 		{
864 			option[a] = Integer.parseInt(st.nextToken());
865 			a++;
866 		}
867 
868 		line_offset = option[0] + 2;
869 		default_alpha = 0xF & option[1];
870 
871 		font = new Font(nm, option[10] == 0 ? Font.PLAIN : Font.BOLD, option[0]);
872 		font_std = new Font("Tahoma", Font.PLAIN, 14); //DM01032004 081.6 int18 add
873 
874 		int[] ret_val = { option[2], option[7] };
875 
876 		return ret_val;
877 	}
878 
879 	/**
880 	 *
881 	 */
getColorTable(int flag)882 	public int[] getColorTable(int flag)
883 	{
884 		//define alternative color_table here
885 		if (flag == 0)
886 		{
887 			if (alternative_sup_colors[0] == 0)
888 				return default_sup_colors;
889 
890 			else
891 				return alternative_sup_colors;
892 		}
893 
894 		else
895 			return default_teletext_colors;
896 	}
897 
898 	/**
899 	 *
900 	 */
setColorTable(int[] values)901 	public void setColorTable(int[] values)
902 	{
903 		//define alternative color_table here
904 		if (values == null)
905 			Arrays.fill(alternative_sup_colors, 0);
906 
907 		else
908 			System.arraycopy(values, 0, alternative_sup_colors, 0, values.length);
909 	}
910 
911 	/**
912 	 *
913 	 */
setArea()914 	private void setArea()
915 	{
916 		Rect[0] = bitmap.getX();
917 		Rect[1] = bitmap.getY();
918 		Rect[2] = bitmap.getWidth();
919 		Rect[3] = bitmap.getHeight();
920 
921 		pos[0] = bitmap.getX();
922 		pos[1] = bitmap.getY();
923 		pos[2] = bitmap.getMaxX();
924 		pos[3] = bitmap.getMaxY();
925 	}
926 
927 	/**
928 	 *
929 	 */
getArea()930 	public String getArea()
931 	{
932 		String string = "";
933 		string += "x " + Rect[0];
934 		string += " y " + Rect[1];
935 		string += " w " + Rect[2];
936 		string += " h " + Rect[3];
937 
938 		string += " x1 " + pos[0];
939 		string += " y1 " + pos[1];
940 		string += " x2 " + pos[2];
941 		string += " y2 " + pos[3];
942 
943 		return string;
944 	}
945 
946 	/**
947 	 *
948 	 */
paintVideoSize(Object obj)949 	private int paintVideoSize(Object obj)
950 	{
951 		String[] str = (String[]) obj;
952 		int video_horizontal = w;
953 		int video_vertical = h;
954 
955 		// H
956 		video_horizontal = str[0] == null ? video_horizontal : Integer.parseInt(str[0]);
957 
958 		// V
959 		video_vertical = str[1] == null ? video_vertical : Integer.parseInt(str[1]);
960 
961 		//deep red background to verify picture rectangle with given video resolution
962 		big.setColor(new Color(0xFF550000));
963 		big.fillRect(0, 0, w, h);
964 
965 		//picture area which the subpicture must not exceed, have to adjust to the hor. middle of it
966 		big.setColor(Color.gray);
967 		big.fillRect(0, 0, video_horizontal, video_vertical);
968 
969 		return video_vertical;
970 	}
971 
972 	/**
973 	 *
974 	 */
Set_Bits(byte buf[], int BPos[], int N, int Val)975 	private void Set_Bits(byte buf[], int BPos[], int N, int Val)
976 	{
977 		int Pos = BPos[1]>>>3;
978 		int BitOffs = BPos[1] & 7;
979 
980 		if (Pos >= buf.length || BitOffs + N >= (BPos[1] & ~7) + 32)
981 		{
982 			global_error = true;
983 		}
984 
985 		else
986 		{
987 			int NoOfBytes = 1 + ((BitOffs + N - 1)>>>3);
988 			int NoOfBits = NoOfBytes<<3;
989 
990 			int tmp_value = CommonParsing.getIntValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING);
991 
992 			int mask = (-1)>>>(32 - N);
993 			int k = NoOfBits - N - BitOffs;
994 
995 			mask <<= k;
996 			Val <<= k;
997 
998 			tmp_value &= ~mask;
999 			tmp_value |= (Val & mask);
1000 
1001 			CommonParsing.setValue(buf, Pos, NoOfBytes, !CommonParsing.BYTEREORDERING, tmp_value);
1002 		}
1003 
1004 		BPos[1] += N;
1005 		BPos[0] = BPos[1]>>>3;
1006 	}
1007 
1008 	/**
1009 	 *
1010 	 */
Get_Bits(byte buf[], int BPos[], int N)1011 	private int Get_Bits(byte buf[], int BPos[], int N)
1012 	{
1013 		int Pos, Val;
1014 		Pos = BPos[1]>>>3;
1015 
1016 		if (Pos >= buf.length)
1017 		{
1018 			global_error = true;
1019 			BPos[1] += N;
1020 			BPos[0] = BPos[1]>>>3;
1021 			return 0;
1022 		}
1023 
1024 		Val =  (0xFF & buf[Pos++])<<24;
1025 
1026 		if (Pos < buf.length)
1027 			Val |= (0xFF & buf[Pos++])<<16;
1028 
1029 		if (Pos < buf.length)
1030 			Val |= (0xFF & buf[Pos++])<<8;
1031 
1032 		if (Pos < buf.length)
1033 			Val |= (0xFF & buf[Pos]);
1034 
1035 		Val <<= BPos[1] & 7;
1036 		Val >>>= 32-N;
1037 
1038 		BPos[1] += N;
1039 		BPos[0] = BPos[1]>>>3;
1040 
1041 		return Val;
1042 	}
1043 
1044 	/**
1045 	 *
1046 	 */
Show_Bits(byte buf[], int BPos[], int N)1047 	private int Show_Bits(byte buf[], int BPos[], int N)
1048 	{
1049 		int Pos, Val;
1050 		Pos = BPos[1]>>>3;
1051 
1052 		if (Pos >= buf.length)
1053 		{
1054 			global_error = true;
1055 			return 0;
1056 		}
1057 
1058 		Val =  (0xFF & buf[Pos++])<<24;
1059 
1060 		if (Pos < buf.length)
1061 			Val |= (0xFF & buf[Pos++])<<16;
1062 
1063 		if (Pos < buf.length)
1064 			Val |= (0xFF & buf[Pos++])<<8;
1065 
1066 		if (Pos < buf.length)
1067 			Val |= (0xFF & buf[Pos]);
1068 
1069 		Val <<= BPos[1] & 7;
1070 		Val >>>= 32 - N;
1071 
1072 		return Val;
1073 	}
1074 
1075 	/**
1076 	 *
1077 	 */
Flush_Bits(int BPos[], int N)1078 	private void Flush_Bits(int BPos[], int N)
1079 	{
1080 		BPos[1] += N;
1081 		BPos[0] = BPos[1]>>>3;
1082 	}
1083 
1084 	/**
1085 	 *
1086 	 */
align_Bits(int BPos[])1087 	private void align_Bits(int BPos[])
1088 	{
1089 		if ((1 & BPos[1]>>>2) != 0)
1090 			Flush_Bits( BPos, 4);
1091 	}
1092 
1093 	/**
1094 	 *
1095 	 */
isForced_Msg()1096 	public String isForced_Msg()
1097 	{
1098 		return isForced_Msg(0);
1099 	}
1100 
1101 	/**
1102 	 *
1103 	 */
isForced_Msg(int val)1104 	public String isForced_Msg(int val)
1105 	{
1106 		String str = null;
1107 
1108 		//change of status occured
1109 		if ((isforced_status & 1) == 0 || val == 1)
1110 		{
1111 			if ((isforced_status & 2) > 0)
1112 				str = Resource.getString("subpicture.msg.forced.no");
1113 
1114 			else
1115 				str = Resource.getString("subpicture.msg.forced.yes");
1116 		}
1117 
1118 		isforced_status |= 1;
1119 
1120 		return str;
1121 	}
1122 
1123 	/**
1124 	 *
1125 	 */
reset()1126 	public void reset()
1127 	{
1128 		isforced_status = 0;
1129 		ismulticolor_status = 0;
1130 		set_XY_Offset(0, 0);
1131 		setDisplayMode(0);
1132 	}
1133 
1134 	/**
1135 	 * modify X,Y Position
1136 	 */
set_XY_Offset(int x_value, int y_value)1137 	public void set_XY_Offset(int x_value, int y_value)
1138 	{
1139 		X_Offset = x_value;
1140 		Y_Offset = y_value;
1141 	}
1142 
1143 	/**
1144 	 * modify force display flag
1145 	 */
setDisplayMode(int value)1146 	public void setDisplayMode(int value)
1147 	{
1148 		DisplayMode = value;
1149 	}
1150 
1151 	/**
1152 	 *
1153 	 */
decode_picture(byte[] packet, int off, boolean decode, Object obj)1154 	public int decode_picture(byte[] packet, int off, boolean decode, Object obj)
1155 	{
1156 		return decode_picture(packet, off, decode, obj, 0, false, true);
1157 	}
1158 
1159 	/**
1160 	 *
1161 	 */
decode_picture(byte[] packet, int off, boolean decode, Object obj, Image previewImage, int previewflags)1162 	public int decode_picture(byte[] packet, int off, boolean decode, Object obj, Image previewImage, int previewflags)
1163 	{
1164 		return decode_picture(packet, off, decode, obj, 0, false, true, previewImage, previewflags);
1165 	}
1166 
1167 	/**
1168 	 *
1169 	 */
decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible)1170 	public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible)
1171 	{
1172 		return decode_picture(packet, off, decode, obj, pts, save, visible, null, 0);
1173 	}
1174 
1175 	/**
1176 	 *
1177 	 */
decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible, Image previewImage, int previewflags)1178 	public int decode_picture(byte[] packet, int off, boolean decode, Object obj, long pts, boolean save, boolean visible, Image previewImage, int previewflags)
1179 	{
1180 		read_from_Image = false;
1181 		global_error = false;
1182 
1183 		boolean simple_picture = false;
1184 		int picture_length = packet.length;
1185 
1186 		int[] BPos = { off, off<<3 }; //BytePos, BitPos
1187 		int[] position = new int[4];
1188 		int[] start_pos = new int[3];
1189 		int default_indices = 0;
1190 
1191 		ArrayList colcon = new ArrayList();
1192 
1193 		if (BPos[0] > picture_length)
1194 			return -4;
1195 
1196 		int packetlength = Get_Bits(packet, BPos, 16); // required pack length
1197 
1198 		if (Show_Bits(packet, BPos, 24) == 0xF) // DVB subpicture: 8bit padding 0x00 + 8bit subtitle_stream_id 0x00 + start of subtitle segment 0x0F
1199 		{
1200 			big.setFont(font_std);
1201 
1202 			byte[] data = new byte[picture_length + 4];
1203 			System.arraycopy(packet, 0, data, 0, picture_length);
1204 
1205 			int ret = dvb.decodeDVBSubpicture(data, BPos, big, bimg, pts, save, visible);
1206 
1207 			if (ret > -2)
1208 				repaint();
1209 
1210 			return ret;
1211 		}
1212 
1213 		if (BPos[0] + packetlength != picture_length + 2)
1214 			return -5;
1215 
1216 		start_pos[2] = Get_Bits(packet, BPos, 16) - 2;
1217 		Flush_Bits(BPos, start_pos[2]<<3); // jump to sections chunk
1218 
1219 		//fixed pos, so it must follow the 1st ctrl sequ,
1220 		//delay of 2nd ctrl sequ execution - usually stop displaying
1221 		int playtime_pos = Get_Bits(packet, BPos, 16);
1222 
1223 		if (playtime_pos == start_pos[2] + 2)
1224 		{
1225 			playtime_pos = packetlength;
1226 			simple_picture = true;
1227 			Common.setMessage(Resource.getString("subpicture.msg2"));
1228 		}
1229 		else
1230 			start_pos[2] += off + 2;
1231 
1232 		int[] color_table = getColorTable(0);
1233 
1234 		while (BPos[0] < off + playtime_pos)  // read sections chunk
1235 		{
1236 			int cmd_switch = Show_Bits(packet, BPos, 8); // show at first, to enable editing
1237 
1238 			switch(cmd_switch)
1239 			{
1240 			case 0: // force display flag
1241 				isforced_status = (isforced_status & 5) != 5 ? 4 : 5;
1242 
1243 				if (DisplayMode == 2) //set normal
1244 					Set_Bits(packet, BPos, 8, 1);
1245 
1246 				else
1247 					Flush_Bits(BPos, 8);
1248 
1249 				break;
1250 
1251 			case 1: // start display flag, normal
1252 				isforced_status = (isforced_status & 3) != 3 ? 2 : 3;
1253 
1254 				if (DisplayMode == 1) //set forced
1255 					Set_Bits(packet, BPos, 8, 0);
1256 
1257 				else
1258 					Flush_Bits(BPos, 8);
1259 
1260 				break;
1261 
1262 			case 2: // stop display flag
1263 				Flush_Bits(BPos, 8);
1264 				break;
1265 
1266 			case 3: // 4 color links
1267 				Flush_Bits(BPos, 8);
1268 				default_indices |= 0xFFFF & Get_Bits(packet, BPos, 16);
1269 				break;
1270 
1271 			case 4: // alpha blending
1272 				Flush_Bits(BPos, 8);
1273 				default_indices |= (0xFFFF & Get_Bits(packet, BPos, 16))<<16;
1274 				break;
1275 
1276 			case 5: // x,y pos.
1277 				Flush_Bits(BPos, 8);
1278 
1279 				if (X_Offset != 0) //move X-pos
1280 				{
1281 					position[0] = Show_Bits(packet, BPos, 12) + X_Offset; //X-links
1282 					Set_Bits(packet, BPos, 12, position[0]); //X-links
1283 
1284 					position[1] = Show_Bits(packet, BPos, 12) + X_Offset; //X-rechts
1285 					Set_Bits(packet, BPos, 12, position[1]); //X-rechts
1286 				}
1287 				else
1288 				{
1289 					position[0] = Get_Bits(packet, BPos, 12); //X-links
1290 					position[1] = Get_Bits(packet, BPos, 12); //X-rechts
1291 				}
1292 
1293 				if (Y_Offset != 0) //move Y-pos
1294 				{
1295 					position[2] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-oben
1296 					Set_Bits(packet, BPos, 12, position[2]); //Y-oben
1297 
1298 					position[3] = Show_Bits(packet, BPos, 12) + Y_Offset; //Y-unten
1299 					Set_Bits(packet, BPos, 12, position[3]); //Y-unten
1300 				}
1301 				else
1302 				{
1303 					position[2] = Get_Bits(packet, BPos, 12); //X-links
1304 					position[3] = Get_Bits(packet, BPos, 12); //X-rechts
1305 				}
1306 
1307 				break;
1308 
1309 			case 6: // pos. of decode_start of a field
1310 				Flush_Bits(BPos, 8);
1311 
1312 				for (int b = 0; b < 2; b++)
1313 					start_pos[b] = Get_Bits(packet, BPos, 16);
1314 
1315 				break;
1316 
1317 			case 7: // extra alpha + color area definition
1318 				Flush_Bits(BPos, 8);
1319 				int blen = Get_Bits(packet, BPos, 16); // get length
1320 
1321 				if (ismulticolor_status == 0)
1322 				{
1323 					ismulticolor_status |= 1;
1324 					Common.setMessage("-> contains extra area definitions!");
1325 				}
1326 
1327 				int area_size = 0;
1328 				int endofcmd = BPos[0] + blen;
1329 
1330 				while (BPos[0] < endofcmd)
1331 				{
1332 					area_size = Show_Bits(packet, BPos, 32);  // read 4 bytes linenumbers & def. index
1333 
1334 					if (area_size == 0x0FFFFFFF) //end marker
1335 					{
1336 						Flush_Bits(BPos, 32);
1337 						break;
1338 					}
1339 
1340 					if (Y_Offset != 0) //move Y-pos
1341 					{
1342 						area_size = (0xF000 & area_size) | ((0xFFF & area_size>>16) + Y_Offset)<<16 | ((0xFFF & area_size) + Y_Offset); //Y
1343 						Set_Bits(packet, BPos, 32, area_size);
1344 					}
1345 					else
1346 						Flush_Bits(BPos, 32);
1347 
1348 					for (int i = 0, j = 0xF & area_size>>12; i < j; i++) //parameter count
1349 					{
1350 						int[] area_defs = new int[5]; // 5 parameters
1351 
1352 						area_defs[0] = 0xFFF & area_size>>16; //from top line number
1353 						area_defs[1] = 0xFFF & area_size;  //to bottom line number
1354 
1355 						if (X_Offset != 0) //move X-pos
1356 						{
1357 							area_defs[2] = Show_Bits(packet, BPos, 16) + X_Offset; // read 2 bytes column, start of def.
1358 							Set_Bits(packet, BPos, 16, area_defs[2]); //set new
1359 						}
1360 						else
1361 							area_defs[2] = Get_Bits(packet, BPos, 16); // read 2 bytes column, start of def.
1362 
1363 						area_defs[3] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of color
1364 						area_defs[4] = Get_Bits(packet, BPos, 16); // read 2 bytes 4x new index of contrast
1365 
1366 						colcon.add(area_defs);
1367 					}
1368 				}
1369 
1370 				break;
1371 
1372 			case 0xFF: // end of ctrl sequ.
1373 				Flush_Bits(BPos, 8);
1374 				break;
1375 
1376 			default:
1377 				Common.setMessage(Resource.getString("subpicture.msg3") + ": " + cmd_switch);
1378 				Flush_Bits(BPos, 8);
1379 			}
1380 		}
1381 
1382 		if (off + playtime_pos != BPos[0])
1383 			return -6;
1384 
1385 		int playtime = 0;
1386 
1387 		if (!simple_picture)
1388 		{
1389 			playtime = Get_Bits(packet, BPos, 16);
1390 			if (playtime_pos != Get_Bits(packet, BPos, 16))
1391 				return -7;
1392 
1393 			if (Get_Bits(packet, BPos, 8) != 2)
1394 				return -8;
1395 
1396 			Flush_Bits( BPos, ((BPos[0] & 1) != 1) ? 16 : 8 );
1397 		}
1398 
1399 		if (BPos[0] != picture_length)
1400 			return -9;
1401 
1402 		if (global_error)
1403 			return -3;
1404 
1405 		if (!decode)
1406 			return (playtime * 1024); //DM26052004 081.7 int03 changed , 900, 1000
1407 
1408 
1409 		for (int b=0; b<2; b++)
1410 			start_pos[b] += off;
1411 
1412 		paintVideoSize(obj);
1413 
1414 		//paint picture at background, fixed size
1415 		if (previewImage != null)
1416 		{
1417 			int aro = Common.getMpvDecoderClass().getMpg2AspectRatioOffset();
1418 
1419 			big.setColor(new Color(0xFF505050));
1420 			big.fillRect(0, 0, w, h);
1421 
1422 			int pic_preview_width = 0xFFF & previewflags >> 20;
1423 			int pic_preview_height = 0xFFF & previewflags >> 8;
1424 
1425 			if (aro != 0) //4:3 portion of widescreen preview
1426 				big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, 64, 0, 448, 288, null);
1427 
1428 			else if ((previewflags & 2) != 0) // letterbox of widescreen
1429 			{
1430 				int blackborder = (pic_preview_height - ((pic_preview_height * 3) / 4)) / 2;
1431 				big.drawImage(previewImage, 0, blackborder, pic_preview_width, (pic_preview_height * 3) / 4, null);
1432 			}
1433 
1434 			else   // anamorph widescreen
1435 				big.drawImage(previewImage, 0, 0, pic_preview_width, pic_preview_height, null);
1436 
1437 		}
1438 
1439 		int x0 = position[0];
1440 		int y0 = position[2];
1441 
1442 		int width = position[1] - position[0] + 1;
1443 		int height = position[3] - position[2] + 1;
1444 
1445 		big.setColor(Color.white);
1446 		big.drawRect(x0 - 1, y0 - 1, width + 1, height + 1);
1447 		big.setFont(font_std);
1448 		big.drawString("x" + x0 + ", y" + y0 + " / " + width + "*" + height
1449 				+ " , C-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices).toUpperCase(), 4)
1450 				+ ", T-" + Common.adaptString(Integer.toHexString(0xFFFF & default_indices>>16).toUpperCase(), 4)
1451 				, x0 + 1, y0 - 5);
1452 
1453 //
1454 		// subarray - color index for each pixel 0xFFFFFFFF = Contrast/Color 32103210
1455 		int[] colcon_indices = new int[width * height];
1456 
1457 		// default filling, keeps default when no other def's exist
1458 		Arrays.fill(colcon_indices, default_indices);
1459 
1460 		// fill with new def's
1461 		for (int b = 0; (previewflags & 8) == 0 && b < colcon.size(); b++)
1462 		{
1463 			int[] area_defs = (int[]) colcon.get(b); // one def block
1464 
1465 			// replace indices per line from column to end
1466 			for (int i = (area_defs[0] - y0) * width, j = (area_defs[1] - y0) * width; i < j; i += width)
1467 				Arrays.fill(colcon_indices, i + area_defs[2] - x0, i + width, area_defs[3] | area_defs[4]<<16);
1468 
1469 		//	area_defs[2]  2 bytes column, start of def.
1470 		//	area_defs[3]  2 bytes 4x new index of color
1471 		//	area_defs[4]  2 bytes 4x new index of contrast
1472 		}
1473 //
1474 
1475 		for (int b = 0; b < 2; b++) // 2 fields painting
1476 		{
1477 			int Val = 0, x1 = x0, y1 = y0 + b;
1478 			BPos[1] = (BPos[0] = start_pos[b])<<3; // top_field at first
1479 
1480 			while (BPos[0] < start_pos[b + 1]) // stop at pos_marker
1481 			{
1482 				if ((Val = Get_Bits(packet, BPos, 4)) > 3) //4..F (0..3 never encodable)
1483 					x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
1484 
1485 				else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0xF) //10..3F
1486 					x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
1487 
1488 				else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 0x3F) //40..FF
1489 					x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
1490 
1491 				else if ((Val = Val<<4 | Get_Bits(packet, BPos, 4)) > 3) //100..3FF
1492 					x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
1493 
1494 				else  // 0 forced carriage return
1495 				{
1496 					if ((Val & 3) != 0)
1497 					{
1498 						Val |= (width - x1)<<2;
1499 						x1 = paintPixel(Val, x1, y1, colcon_indices, color_table, x0, y0, width, previewflags);
1500 					}
1501 
1502 					x1 = x0;
1503 					y1 += 2;
1504 					align_Bits(BPos);
1505 					continue;
1506 				}
1507 
1508 				// line end, carriage return
1509 				if (x1 > position[1])
1510 				{
1511 					x1 = position[0];
1512 					y1 += 2;
1513 					align_Bits(BPos);
1514 				}
1515 			}
1516 		}
1517 
1518 		// paint rectangles of extra col-con definitions
1519 		for (int i = colcon.size() - 1; (previewflags & 4) == 0 && i >= 0; i--)
1520 		{
1521 			int[] area_defs = (int[]) colcon.get(i);
1522 
1523 			big.setColor(Color.magenta);
1524 			big.drawRect(area_defs[2] - 1, area_defs[0] - 1, width - area_defs[2] + x0 + 1, area_defs[1] - area_defs[0]);
1525 
1526 			big.setColor(Color.yellow);
1527 			big.drawString("area: " + i + " - " + area_defs[0] + ", " + area_defs[1] + ", " + area_defs[2]
1528 							+ ", C-" + Common.adaptString(Integer.toHexString(area_defs[3]).toUpperCase(), 4)
1529 							+ ", T-" + Common.adaptString(Integer.toHexString(area_defs[4]).toUpperCase(), 4)
1530 							, position[0], y0 - 22 - (i * 16));
1531 		}
1532 
1533 		repaint();
1534 
1535 		if (global_error)
1536 			return -3;
1537 
1538 		return (playtime * 1024); //DM26052004 081.7 int03 changed, 900, 1000
1539 	}
1540 
1541 	/**
1542 	 * paint preview pixel from .sup
1543 	 */
paintPixel(int Val, int x1, int y1, int[] colcon_indices, int[] color_table, int x0, int y0, int width, int previewflags)1544 	private int paintPixel(int Val, int x1, int y1, int[] colcon_indices, int[] color_table, int x0, int y0, int width, int previewflags)
1545 	{
1546 		int table_index = Val & 3;
1547 		int line_length = Val>>>2;
1548 		int array_index;
1549 		int contrast_index = 0;
1550 		int color_index = 0;
1551 		boolean opaque = (previewflags & 0x10) != 0;
1552 
1553 		big.setColor(new Color(0));
1554 
1555 		for (int j = x1 + line_length, color, lastcolor = 0; x1 < j; x1++)
1556 		{
1557 			array_index = (y1 - y0) * width + x1 - x0;
1558 
1559 			//error condition
1560 			if (array_index >= colcon_indices.length)
1561 				break;
1562 
1563 			contrast_index = 0xF & colcon_indices[array_index]>>(16 + table_index * 4);
1564 			color_index = 0xF & colcon_indices[array_index]>>(table_index * 4);
1565 
1566 			// set ARGB color
1567 			color = (0x11 * (0xF ^ contrast_index))<<24 | (color_table[color_index] & 0xFFFFFF);
1568 
1569 			// check for a change
1570 			if (color != lastcolor)
1571 				big.setColor(new Color(color)); // needs (color, true) for alpha - but with less performance
1572 
1573 			lastcolor = color;
1574 
1575 			if (opaque || contrast_index > 0) // dont paint full transp. pixel
1576 				big.drawLine(x1, y1, x1, y1);
1577 			//	big.drawLine(x1, y1, x1 + 1, y1);
1578 		}
1579 
1580 		return x1;
1581 	}
1582 }
1583