1 /*
2  * @(#)VBI.java - carries various stuff
3  *
4  * Copyright (c) 2005 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 package net.sourceforge.dvb.projectx.parser;
28 
29 import net.sourceforge.dvb.projectx.common.Common;
30 import net.sourceforge.dvb.projectx.common.Resource;
31 import net.sourceforge.dvb.projectx.common.Keys;
32 
33 import net.sourceforge.dvb.projectx.video.Video;
34 
35 public final class VBI extends Object {
36 
37 	private static long source_pts = 0;
38 
39 	private static String vps_str = "";
40 	private static String vps_sound_mode[] = { "n/a", "mono", "stereo", "dual" };
41 
42 	private static byte[] wss = new byte[3];
43 
44 	/**
45 	 *
46 	 */
VBI()47 	private VBI()
48 	{}
49 
50 
51 	/**
52 	 *
53 	 */
reset()54 	public static void reset()
55 	{
56 		source_pts = 0;
57 		vps_str = "";
58 		wss = new byte[3];
59 	}
60 
61 	/**
62 	 *
63 	 */
64 	// mpg2 pes expected
parsePES(byte[] pes_packet, int pes_packetoffset)65 	public static void parsePES(byte[] pes_packet, int pes_packetoffset) throws ArrayIndexOutOfBoundsException
66 	{
67 		if (pes_packet[pes_packetoffset] != 0 || pes_packet[1 + pes_packetoffset] != 0 || pes_packet[2 + pes_packetoffset] != 1)
68 			return;
69 
70 		int pes_id = 0xFF & pes_packet[3 + pes_packetoffset];
71 		int pes_packetlength = (0xFF & pes_packet[4 + pes_packetoffset])<<8 | (0xFF & pes_packet[5 + pes_packetoffset]);
72 		int pes_mpeg_flag = 0xC0 & pes_packet[6 + pes_packetoffset];
73 
74 		if (pes_mpeg_flag != 0x80 && pes_mpeg_flag != 0x40) // neither mpeg2 nor mpeg1
75 			return;
76 
77 		int pes_extensionlength = 0xFF & pes_packet[8 + pes_packetoffset];
78 		boolean pts_flag = (0x80 & pes_packet[7 + pes_packetoffset]) != 0;
79 
80 		source_pts = pts_flag ? CommonParsing.getPTSfromBytes(pes_packet, 9 + pes_packetoffset) : 0;
81 
82 		decodeVBI(pes_packet, 9 + pes_extensionlength + pes_packetoffset);
83 	}
84 
85 	/**
86 	 *
87 	 */
decodeVBI(byte[] packet, int offs)88 	private static void decodeVBI(byte[] packet, int offs) throws ArrayIndexOutOfBoundsException
89 	{
90 		String str;
91 
92 		boolean wss_online = false;
93 
94 		/**
95 		 * 0x99..0x9B -> PES contains one or multiple VBI Data definitions
96 		 */
97 		if ((0xFC & packet[offs]) != 0x98 || (3 & packet[offs]) == 0)
98 			return;
99 
100 		for (int i = offs + 1, data_unit_id, len; i < packet.length - 1; )
101 		{
102 			data_unit_id = 0xFF & packet[i++];
103 			len = 0xFF & packet[i++];
104 
105 			/**
106 			 * VPS
107 			 */
108 			if (data_unit_id == 0xC3)
109 			{
110 				str = decodeVPS(packet, i);
111 
112 				if (str != null && !str.equals(vps_str))
113 				{
114 					vps_str = str;
115 					Common.setMessage(Resource.getString("teletext.msg.vps", str) + " " + Common.formatTime_1(source_pts / 90));
116 				}
117 			}
118 
119 			/**
120 			 * WSS
121 			 */
122 			else if (data_unit_id == 0xC4)
123 			{
124 				str = decodeWSS(packet, i);
125 
126 				if (str != null)
127 				{
128 					wss_online = true;
129 
130 					if (str.length() > 0)
131 					{
132 						Common.setMessage("-> WSS Status - changed @ PTS " + Common.formatTime_1(source_pts / 90));
133 						Common.setMessage(str);
134 					}
135 
136 					else if (wss[2] == 0)
137 					{
138 						Common.setMessage("-> WSS Status - no change @ PTS " + Common.formatTime_1(source_pts / 90));
139 						wss[2] = -2;
140 					}
141 				}
142 			}
143 
144 			else if (data_unit_id == 0xFF)
145 			{}
146 
147 			i += len;
148 		}
149 
150 		if (!wss_online && wss[2] == -1)
151 		{
152 			wss[2] = 0;
153 
154 			Common.setMessage("-> WSS Status - offline @ PTS " + Common.formatTime_1(source_pts / 90));
155 		}
156 	}
157 
158 	/**
159 	 *
160 	 */
decodeVPS(byte[] packet, int offs)161 	public static String decodeVPS(byte[] packet, int offs)
162 	{
163 		if (!Common.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg6))
164 			return null;
165 
166 		String vps_status = "";
167 
168 		if (packet.length - 1 < offs + 12)
169 			return null;
170 
171 		int vps_data = (0x3F & packet[offs + 9])<<24 |
172 				(0xFF & packet[offs + 10])<<16 |
173 				(0xFF & packet[offs + 11])<<8 |
174 				(0xFF & packet[offs + 12]);
175 
176 		switch (0x1F & vps_data>>>16)
177 		{
178 			case 0x1C:
179 				vps_status = "Contin.";
180 				break;
181 
182 			case 0x1D:
183 				vps_status = "Pause  ";
184 				break;
185 
186 			case 0x1E:
187 				vps_status = "Stop   ";
188 				break;
189 
190 			case 0x1F:
191 				vps_status = "Timer  ";
192 				break;
193 
194 			default:
195 				vps_status = "" + formatString(0x1F & (vps_data>>>25)) + "." +
196 						formatString(0xF & (vps_data>>>21)) + ".  " +
197 						formatString(0x1F & (vps_data>>>16)) + ":" +
198 						formatString(0x3F & (vps_data>>>10)) + "  ";
199 		}
200 
201 		vps_status += vps_sound_mode[(3 & packet[offs + 3]>>>6)] + " " +
202 				Integer.toHexString(0xF & vps_data>>>6).toUpperCase() + " " +
203 				Integer.toHexString(0x3F & vps_data).toUpperCase();
204 
205 		return vps_status;
206 	}
207 
208 	/**
209 	 *
210 	 */
formatString(int value)211 	private static String formatString(int value)
212 	{
213 		String str = "00" + String.valueOf(value);
214 
215 		return str.substring(str.length() - 2);
216 	}
217 
218 
219 	/**
220 	 *
221 	 */
decodeWSS(byte[] packet, int offs)222 	public static String decodeWSS(byte[] packet, int offs)
223 	{
224 		if (!Common.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg5))
225 			return null;
226 
227 		if (packet.length - 1 < offs + 2)
228 			return null;
229 
230 		if (packet[offs + 1] == wss[0] && packet[offs + 2] == wss[1])
231 			return "";
232 
233 		System.arraycopy(packet, offs + 1, wss, 0, 2);
234 		wss[2] = -1;
235 
236 		// read PAL-625line WSS
237 		String str = getGroup1(wss);
238 		str += getGroup2(wss);
239 		str += getGroup3(wss);
240 		str += getGroup4(wss);
241 
242 		return str;
243 	}
244 
245 	/**
246 	 *
247 	 */
getGroup1(byte[] packet)248 	private static String getGroup1(byte[] packet)
249 	{
250 		String str = "";
251 
252 		switch (0xF & packet[0]>>4)
253 		{
254 		case 1: // 0001  Biphase 01010110
255 			str = "  " + Resource.getString("wss.group_1.0001");
256 			break;
257 
258 		case 8: // 1000  Biphase 10010101
259 			str = "  " + Resource.getString("wss.group_1.1000");
260 			break;
261 
262 		case 4: // 0100  Biphase 01100101
263 			str = "  " + Resource.getString("wss.group_1.0100");
264 			break;
265 
266 		case 0xD: // 1101  Biphase 10100110
267 			str = "  " + Resource.getString("wss.group_1.1101");
268 			break;
269 
270 		case 2: // 0010  Biphase 01011001
271 			str = "  " + Resource.getString("wss.group_1.0010");
272 			break;
273 
274 		case 7: // 0111  Biphase 01101010
275 			str = "  " + Resource.getString("wss.group_1.0111");
276 			break;
277 
278 		case 0xE: // 1110  Biphase 10101001
279 			str = "  " + Resource.getString("wss.group_1.1110");
280 			break;
281 
282 		default:
283 			str = "  " + Resource.getString("wss.group_1.error");
284 		}
285 
286 		str += "\n";
287 
288 		return str;
289 	}
290 
291 	/**
292 	 *
293 	 */
getGroup2(byte[] packet)294 	private static String getGroup2(byte[] packet)
295 	{
296 		String str = "";
297 
298 		switch (1 & packet[0]>>3)
299 		{
300 		case 0: // 0  Biphase 01
301 			str += "  " + Resource.getString("wss.group_2.0.01");
302 			break;
303 
304 		case 1: // 1  Biphase 10
305 			str += "  " + Resource.getString("wss.group_2.0.10");
306 		}
307 
308 		str += ",";
309 
310 		switch (1 & packet[0]>>2)
311 		{
312 		case 0: // 0  Biphase 01
313 			str += "  " + Resource.getString("wss.group_2.1.01");
314 			break;
315 
316 		case 1: // 1  Biphase 10
317 			str += "  " + Resource.getString("wss.group_2.1.10");
318 		}
319 
320 		str += ",";
321 
322 		switch (1 & packet[0]>>1)
323 		{
324 		case 0:  // 0  Biphase 01
325 			str += "  " + Resource.getString("wss.group_2.2.01");
326 			break;
327 
328 		case 1:  // 1  Biphase 10
329 			str += "  " + Resource.getString("wss.group_2.2.10");
330 		}
331 
332 		str += ",";
333 
334 		switch (1 & packet[0])
335 		{
336 		case 0: // 0  Biphase 01
337 			str += "  " + Resource.getString("wss.group_2.3.01");
338 			break;
339 
340 		case 1:  // 1  Biphase 10
341 			str += "  " + Resource.getString("wss.group_2.3.10");
342 		}
343 
344 		str += "\n";
345 
346 		return str;
347 	}
348 
349 	/**
350 	 *
351 	 */
getGroup3(byte[] packet)352 	private static String getGroup3(byte[] packet)
353 	{
354 		String str = "";
355 
356 		switch (1 & packet[1]>>7)
357 		{
358 		case 0: // 0  Biphase 01
359 			str += "  " + Resource.getString("wss.group_3.0.01");
360 			break;
361 
362 		case 1: // 1  Biphase 10
363 			str += "  " + Resource.getString("wss.group_3.0.10");
364 		}
365 
366 		str += ",";
367 
368 		switch (3 & packet[1]>>5)
369 		{
370 		case 0:  // 00  Biphase 0101
371 			str += "  " + Resource.getString("wss.group_3.1.00");
372 			break;
373 
374 		case 1:  // 01  Biphase 0110
375 			str += "  " + Resource.getString("wss.group_3.1.01");
376 			break;
377 
378 		case 2:  // 10  Biphase 1001
379 			str += "  " + Resource.getString("wss.group_3.1.10");
380 			break;
381 
382 		case 3:  // 11  Biphase 1010
383 			str += "  " + Resource.getString("wss.group_3.1.11");
384 		}
385 
386 		str += "\n";
387 
388 		return str;
389 	}
390 
391 	/**
392 	 *
393 	 */
getGroup4(byte[] packet)394 	private static String getGroup4(byte[] packet)
395 	{
396 		String str = "";
397 
398 		switch (1 & packet[1]>>4)
399 		{
400 		case 0:  // 0  Biphase 01
401 			str += "  " + Resource.getString("wss.group_4.0.01");
402 			break;
403 
404 		case 1:  // 1  Biphase 10
405 			str += "  " + Resource.getString("wss.group_4.0.10");
406 		}
407 
408 		str += ",";
409 
410 		switch (1 & packet[1]>>3)
411 		{
412 		case 0:  // 0  Biphase 01
413 			str += "  " + Resource.getString("wss.group_4.1.01");
414 			break;
415 
416 		case 1:  // 1  Biphase 10
417 			str += "  " + Resource.getString("wss.group_4.1.10");
418 		}
419 
420 		str += ",";
421 
422 		switch (1 & packet[1]>>2)
423 		{
424 		case 0:  // 0  Biphase 01
425 			str += "  " + Resource.getString("wss.group_4.2.01");
426 			break;
427 
428 		case 1:  // 1  Biphase 10
429 			str += "  " + Resource.getString("wss.group_4.2.10");
430 		}
431 
432 		return str;
433 	}
434 
435 }