1 /*
2  * @(#)CommonParsing
3  *
4  * Copyright (c) 2005-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 package net.sourceforge.dvb.projectx.parser;
28 
29 import java.io.IOException;
30 import java.io.File;
31 import java.io.RandomAccessFile;
32 import java.io.PrintWriter;
33 import java.io.FileOutputStream;
34 
35 import java.util.Calendar;
36 import java.util.TimeZone;
37 import java.util.Date;
38 import java.util.StringTokenizer;
39 import java.util.ArrayList;
40 import java.util.List;
41 
42 import java.text.DateFormat;
43 import java.text.SimpleDateFormat;
44 
45 import net.sourceforge.dvb.projectx.common.Resource;
46 import net.sourceforge.dvb.projectx.common.Settings;
47 import net.sourceforge.dvb.projectx.common.Common;
48 import net.sourceforge.dvb.projectx.common.Keys;
49 import net.sourceforge.dvb.projectx.common.JobProcessing;
50 
51 
52 /**
53  * common stuff for parsing functions
54  */
55 public class CommonParsing extends Object {
56 
57 	public final static boolean BYTEREORDERING = true;
58 
59 	public final static int SECONDARY_PES_PARSER = 0;
60 	public final static int PRIMARY_PES_PARSER   = 1;
61 	public final static int TS_PARSER            = 2;
62 	public final static int PVA_PARSER           = 3;
63 	public final static int ES_VIDEO_PARSER      = 4;
64 	public final static int ES_AUDIO_PARSER      = 5;
65 	public final static int ES_SUBPICTURE_PARSER = 6;
66 
67 	//max 31, more defined by a subtype
68 	public final static int Unsupported   = 0;	//	"unsupported"
69 	public final static int PES_AV_TYPE   = 1;	//	"PES (Video/Audio/TTX)"
70 	public final static int MPEG1PS_TYPE  = 2;	//	"MPEG-1 PS/SS (Video/Audio PES)"
71 	public final static int MPEG2PS_TYPE  = 3;	//	"MPEG-2 PS/SS (Video/Audio PES)"
72 	public final static int PVA_TYPE      = 4;	//	"PVA (Video/Audio PES)"
73 	public final static int TS_TYPE       = 5;	//	"DVB/MPEG2 TS"
74 	public final static int PES_MPA_TYPE  = 6;	//	"PES (MPEG Audio)"
75 	public final static int PES_PS1_TYPE  = 7;	//	"PES (private stream 1)"
76 	public final static int ES_MPV_TYPE   = 8;	//	"ES (MPEG Video)"
77 	public final static int ES_MPA_TYPE   = 9;	//	"ES (MPEG Audio)"
78 	public final static int ES_AC3_TYPE   = 10;	//	"ES (AC-3 Audio)"
79 	public final static int ES_AC3_A_TYPE = 11;	//	"ES (AC-3 Audio) (psb. SMPTE)"
80 	public final static int ES_DTS_TYPE   = 12;	//	"ES (DTS Audio)"
81 	public final static int ES_DTS_A_TYPE = 13;	//	"ES (DTS Audio) (psb. SMPTE)"
82 	public final static int ES_RIFF_TYPE  = 14;	//	"ES (RIFF Audio)"
83 	public final static int ES_cRIFF_TYPE = 15;	//	"ES (compressed RIFF Audio)"
84 	public final static int ES_SUP_TYPE   = 16;	//	"ES (Subpicture 2-bit RLE)"
85 	public final static int PJX_PTS_TYPE  = 31;	//	"PjX PTS File"
86 
87 	public final static int ES_TYPE   = 1;	//	"ElementaryStream"
88 
89 	public final static int TS_TYPE_TF5X00    = TS_TYPE | 1<<8;	//	"DVB/MPEG2 TS  TF5X00"
90 	public final static int TS_TYPE_TF5X00C   = TS_TYPE | 2<<8;	//	"DVB/MPEG2 TS  TF5X00C"
91 	public final static int TS_TYPE_TF4000    = TS_TYPE | 3<<8;	//	"DVB/MPEG2 TS  TF4000"
92 	public final static int TS_TYPE_HANDAN    = TS_TYPE | 4<<8;	//	"DVB/MPEG2 TS  HANDAN"
93 	public final static int TS_TYPE_192BYTE   = TS_TYPE | 5<<8;	//	"DVB/MPEG2 TS  192b"
94 	public final static int TS_TYPE_COMAG     = TS_TYPE | 6<<8;	//	"DVB/MPEG2 TS  COMAG"
95 
96 
97 	//	"ElementaryStream"
98 	public final static int UNKNOWN   = -1;
99 	public final static int AC3_AUDIO  = 0;
100 	public final static int TELETEXT   = 1;
101 	public final static int MPEG_AUDIO = 2;
102 	public final static int MPEG_VIDEO = 3;
103 	public final static int LPCM_AUDIO = 4;
104 	public final static int SUBPICTURE = 5;
105 	public final static int DTS_AUDIO  = 6;	//handled with in AC3_AUDIO so far
106 	public final static int WAV_AUDIO  = 7;
107 	public final static int AAC_AUDIO  = 8;
108 
109 	public final static int ACTION_UNDEFINED = -1;
110 	public final static int ACTION_DEMUX  = 0;
111 	public final static int ACTION_TO_VDR = 1;
112 	public final static int ACTION_TO_M2P = 2;
113 	public final static int ACTION_TO_PVA = 3;
114 	public final static int ACTION_TO_TS  = 4;
115 	public final static int ACTION_FILTER = 5;
116 	public final static int ACTION_COPY   = 6;
117 
118 	public final static int CUTMODE_BYTE  = 0;
119 	public final static int CUTMODE_GOP   = 1;
120 	public final static int CUTMODE_FRAME = 2;
121 	public final static int CUTMODE_PTS   = 3;
122 	public final static int CUTMODE_TIME  = 4;
123 
124 	public final static int PICTURE_START_CODE     =    0;
125 	public final static int SLICE_START_CODE_MIN   =    1;
126 	public final static int SLICE_START_CODE_MAX   = 0xAF;
127 	public final static int USER_DATA_START_CODE   = 0xB2;
128 	public final static int SEQUENCE_HEADER_CODE   = 0xB3;
129 	public final static int EXTENSION_START_CODE   = 0xB5;
130 	public final static int SEQUENCE_END_CODE      = 0xB7;
131 	public final static int GROUP_START_CODE       = 0xB8;
132 	public final static int SYSTEM_END_CODE        = 0xB9;
133 	public final static int PACK_START_CODE        = 0xBA;
134 	public final static int SYSTEM_START_CODE      = 0xBB;
135 	public final static int PROGRAM_STREAM_MAP_CODE= 0xBC;
136 	public final static int PRIVATE_STREAM_1_CODE  = 0xBD;
137 	public final static int PADDING_STREAM_CODE    = 0xBE;
138 	public final static int PRIVATE_STREAM_2_CODE  = 0xBF;
139 	public final static int ECM_STREAM_CODE        = 0xF0;
140 	public final static int EMM_STREAM_CODE        = 0xF1;
141 	public final static int DSM_CC_STREAM_CODE     = 0xF2;
142 
143 	public final static int FRAME_I_TYPE = 1;
144 	public final static int FRAME_P_TYPE = 2;
145 	public final static int FRAME_B_TYPE = 3;
146 	public final static int FRAME_D_TYPE = 4;
147 
148 	public final static int MAX_BITRATE_VALUE = 262143; //3FFFF *400 = 104857200 bps
149 	public final static int MAX_SD_BITRATE_VALUE = 37500; // *400 = 15000000 bps
150 
151 	public static byte[] PTSVideoHeader = { 0x50, 0x4A, 0x58, 0x5F, 0x50, 0x54, 0x53, 0x56, 0x49, 0x44, 0x31, 0x30, 0x30, 0, 0, 0 }; //'PJX_PTSVID100'
152 
153 	private static int Pva_PidToExtract = -1;
154 
155 	private static boolean Pva_PidExtraction = false;
156 
157 	private static boolean InfoScan = false;
158 	private static boolean qbreak = false;
159 	private static boolean qpause = false;
160 
161 	private static boolean _bool = false;
162 
163 	private static int _cutcount = 0;
164 
165 	private static double _videoframerate = 3600.0;
166 
167 	private static long AudioProcessingFlags = 0;
168 
CommonParsing()169 	private CommonParsing()
170 	{}
171 
172 	/**
173 	 *
174 	 */
isInfoScan()175 	public static boolean isInfoScan()
176 	{
177 		return InfoScan;
178 	}
179 
180 	/**
181 	 *
182 	 */
setInfoScan(boolean b)183 	public static void setInfoScan(boolean b)
184 	{
185 		InfoScan = b;
186 	}
187 
188 	/**
189 	 *
190 	 */
isProcessCancelled()191 	public static boolean isProcessCancelled()
192 	{
193 		return qbreak;
194 	}
195 
196 	/**
197 	 *
198 	 */
setProcessCancelled(boolean b)199 	public static void setProcessCancelled(boolean b)
200 	{
201 		qbreak = b;
202 	}
203 
204 	/**
205 	 *
206 	 */
isProcessPausing()207 	public static boolean isProcessPausing()
208 	{
209 		return qpause;
210 	}
211 
212 	/**
213 	 *
214 	 */
setProcessPausing(boolean b)215 	public static void setProcessPausing(boolean b)
216 	{
217 		qpause = b;
218 	}
219 
220 	/**
221 	 *
222 	 */
getAudioProcessingFlags()223 	public static long getAudioProcessingFlags()
224 	{
225 		return AudioProcessingFlags;
226 	}
227 
228 	/**
229 	 *
230 	 */
setAudioProcessingFlags(long val)231 	public static void setAudioProcessingFlags(long val)
232 	{
233 		AudioProcessingFlags = val;
234 	}
235 
236 	/**
237 	 *
238 	 */
getVideoFramerate()239 	public static double getVideoFramerate()
240 	{
241 		return _videoframerate;
242 	}
243 
244 	/**
245 	 *
246 	 */
setVideoFramerate(double val)247 	public static void setVideoFramerate(double val)
248 	{
249 		_videoframerate = val;
250 	}
251 
252 	/**
253 	 *
254 	 */
getCutCounter()255 	public static int getCutCounter()
256 	{
257 		return _cutcount;
258 	}
259 
260 	/**
261 	 *
262 	 */
setCutCounter(int val)263 	public static void setCutCounter(int val)
264 	{
265 		_cutcount = val;
266 	}
267 
268 	/**
269 	 *
270 	 */
getCutStatus()271 	public static boolean getCutStatus()
272 	{
273 		return _bool;
274 	}
275 
276 	/**
277 	 *
278 	 */
setCutStatus(boolean b)279 	public static void setCutStatus(boolean b)
280 	{
281 		_bool = b;
282 	}
283 
284 	/**
285 	 *
286 	 */
getPvaPidExtraction()287 	public static boolean getPvaPidExtraction()
288 	{
289 		return Pva_PidExtraction;
290 	}
291 
292 	/**
293 	 *
294 	 */
setPvaPidExtraction(boolean b)295 	public static void setPvaPidExtraction(boolean b)
296 	{
297 		Pva_PidExtraction = b;
298 	}
299 
300 	/**
301 	 *
302 	 */
getPvaPidToExtract()303 	public static int getPvaPidToExtract()
304 	{
305 		return Pva_PidToExtract;
306 	}
307 
308 	/**
309 	 *
310 	 */
setPvaPidToExtract(int val)311 	public static void setPvaPidToExtract(int val)
312 	{
313 		Pva_PidToExtract = val;
314 	}
315 
316 
317 	/**
318 	 * returns pts value from pes_extension
319 	 *
320 	 * @param1 - source array
321 	 * @param2 - array offset
322 	 * @return - pts
323 	 */
getPTSfromBytes(byte[] array, int offset)324 	public static long getPTSfromBytes(byte[] array, int offset)
325 	{
326 		return getPTSfromBytes(array, offset, true);
327 	}
328 
329 	/**
330 	 * returns pts value from pes_extension
331 	 *
332 	 * @param1 - source array
333 	 * @param2 - array offset
334 	 * @param3 - trim to positive 32bit value
335 	 * @return - pts
336 	 */
getPTSfromBytes(byte[] array, int offset, boolean trim)337 	public static long getPTSfromBytes(byte[] array, int offset, boolean trim)
338 	{
339 		long pts = (6 & array[offset])<<29 |
340 			(0xFF & array[offset + 1])<<22 |
341 			(0xFE & array[offset + 2])<<14 |
342 			(0xFF & array[offset + 3])<<7 |
343 			(0xFE & array[offset + 4])>>>1;
344 
345 		if (trim)
346 			pts &= 0xFFFFFFFFL;
347 
348 		return pts;
349 	}
350 
351 	/**
352 	 * returns pts value from pes_extension
353 	 *
354 	 * @param1 - source array
355 	 * @param2 - array offset
356 	 * @param3 - trim to positive 32bit value
357 	 * @return - pts
358 	 */
readPTS(byte[] array, int offset, int length, boolean bytereordering, boolean trim)359 	public static long readPTS(byte[] array, int offset, int length, boolean bytereordering, boolean trim)
360 	{
361 		long value = getValue(array, offset, length, bytereordering);
362 
363 		if (trim)
364 			value &= 0xFFFFFFFFL;
365 
366 		return value;
367 	}
368 
369 	/**
370 	 *
371 	 */
setValue(byte[] array, int offset, int length, boolean bytereordering, long value)372 	public static void setValue(byte[] array, int offset, int length, boolean bytereordering, long value)
373 	{
374 		for (int i = 0; bytereordering && i < length; i++)
375 			array[i + offset] = (byte)(0xFFL & (value>>>(i * 8)));
376 
377 		for (int i = 0, j = length - 1; !bytereordering && i < length; i++, j--)
378 			array[i + offset] = (byte)(0xFFL & (value>>>(j * 8)));
379 	}
380 
381 	/**
382 	 * returns value
383 	 *
384 	 * @param1 - source array
385 	 * @param2 - array offset
386 	 * @param3 -
387 	 * @return -
388 	 */
getValue(byte[] array, int offset, int length, boolean bytereordering)389 	public static long getValue(byte[] array, int offset, int length, boolean bytereordering)
390 	{
391 		long value = 0;
392 
393 		try {
394 
395 			for (int i = 0; bytereordering && i < length; i++)
396 				value |= (0xFFL & array[i + offset])<<(i * 8);
397 
398 			for (int i = 0, j = length - 1; !bytereordering && i < length; i++, j--)
399 				value |= (0xFFL & array[i + offset])<<(j * 8);
400 
401 		} catch (Exception e) {
402 
403 			Common.setMessage("!> array index error (" + offset + "/" + length + "/" + array.length + ")");
404 			return 0;
405 		}
406 
407 		return value;
408 	}
409 
getIntValue(byte[] array, int offset, int length, boolean bytereordering)410 	public static int getIntValue(byte[] array, int offset, int length, boolean bytereordering)
411 	{
412 		return ((int) getValue(array, offset, length, bytereordering));
413 	}
414 
415 	/**
416 	 *
417 	 */
setPES_PTSField(byte[] array, int offset, long value)418 	public static void setPES_PTSField(byte[] array, int offset, long value)
419 	{
420 		array[9 + offset]  = (byte)(0x21 | (0xE & (value>>>29)));
421 		array[10 + offset] = (byte)(0xFF & (value>>>22));
422 		array[11 + offset] = (byte)(1 | (0xFE & (value>>>14)));
423 		array[12 + offset] = (byte)(0xFF & (value>>>7));
424 		array[13 + offset] = (byte)(1 | (0xFE & (value<<1)));
425 	}
426 
427 	/**
428 	 *
429 	 */
setPES_LengthField(byte[] array, int offset, int value)430 	public static void setPES_LengthField(byte[] array, int offset, int value)
431 	{
432 		array[4 + offset] = (byte)(0xFF & value>>>8);
433 		array[5 + offset] = (byte)(0xFF & value);
434 	}
435 
436 	/**
437 	 *
438 	 */
setPES_IdField(byte[] array, int offset, int value)439 	public static void setPES_IdField(byte[] array, int offset, int value)
440 	{
441 		array[3 + offset] = (byte)(0xFF & value);
442 	}
443 
444 	/**
445 	 *
446 	 */
setPES_SubIdField(byte[] array, int offset, int pes_headerlength, int pes_extensionlength, int value)447 	public static void setPES_SubIdField(byte[] array, int offset, int pes_headerlength, int pes_extensionlength, int value)
448 	{
449 		array[pes_headerlength + pes_extensionlength + offset] = (byte)(0xFF & value);
450 	}
451 
452 	/**
453 	 *
454 	 */
getPES_LengthField(byte[] array, int offset)455 	public static int getPES_LengthField(byte[] array, int offset)
456 	{
457 		int value = (0xFF & array[4 + offset])<<8 | (0xFF & array[5 + offset]);
458 
459 		return value;
460 	}
461 
462 	/**
463 	 *
464 	 */
getPES_IdField(byte[] array, int offset)465 	public static int getPES_IdField(byte[] array, int offset)
466 	{
467 		int value = 0xFF & array[3 + offset];
468 
469 		return value;
470 	}
471 
472 	/**
473 	 *
474 	 */
getPES_ExtensionLengthField(byte[] array, int offset)475 	public static int getPES_ExtensionLengthField(byte[] array, int offset)
476 	{
477 		int value = 0xFF & array[8 + offset];
478 
479 		return value;
480 	}
481 
482 	/**
483 	 *
484 	 */
clearBit33ofPTS(byte[] array, int offset)485 	public static boolean clearBit33ofPTS(byte[] array, int offset)
486 	{
487 		if ((0x80 & array[7 + offset]) != 0)
488 		{
489 			array[9 + offset] &= ~8;
490 			return true;
491 		}
492 
493 		return false;
494 	}
495 
496 	/**
497 	 *
498 	 */
clearBit33ofDTS(byte[] array, int offset)499 	public static boolean clearBit33ofDTS(byte[] array, int offset)
500 	{
501 		if ((0x40 & array[7 + offset]) != 0)
502 		{
503 			array[9 + 5 + offset] &= ~8;
504 			return true;
505 		}
506 
507 		return false;
508 	}
509 
510 	/**
511 	 *
512 	 */
nextBits(byte buffer[], int BitPos, int N)513 	public static int nextBits(byte buffer[], int BitPos, int N)
514 	{
515 		int Pos, Val;
516 
517 		Pos = BitPos>>>3;
518 
519 		Val =   (0xFF & buffer[Pos])<<24 |
520 			(0xFF & buffer[Pos + 1])<<16 |
521 			(0xFF & buffer[Pos + 2])<<8 |
522 			(0xFF & buffer[Pos + 3]);
523 
524 		Val <<= BitPos & 7;
525 		Val >>>= 32-N;
526 
527 		return Val;
528 	}
529 
530 	/**
531 	 * check startcode
532 	 * return int of skip'able data (negative)
533 	 */
validateStartcode(byte[] pes_packet, int offset)534 	public static int validateStartcode(byte[] pes_packet, int offset)
535 	{
536 		if (pes_packet[2 + offset] == 1)
537 		{
538 			if (pes_packet[1 + offset] == 0)
539 				if (pes_packet[offset] == 0)
540 					return 0;
541 		}
542 
543 		else if (pes_packet[2 + offset] == 0)
544 		{
545 			if (pes_packet[1 + offset] == 0)
546 				return -1;
547 			else
548 				return -2;
549 		}
550 
551 		return -3;
552 	}
553 
554 
555 	/**
556 	 * check startcode
557 	 * return int of skip'able data (negative)
558 	 */
validateMp4Startcode(byte[] pes_packet, int offset)559 	public static int validateMp4Startcode(byte[] pes_packet, int offset)
560 	{
561 		if (pes_packet[3 + offset] == 1)
562 		{
563 			if (pes_packet[2 + offset] == 0)
564 				if (pes_packet[1 + offset] == 0)
565 					if (pes_packet[offset] == 0)
566 						return 0;
567 		}
568 
569 		else if (pes_packet[3 + offset] == 0)
570 		{
571 			if (pes_packet[2 + offset] == 0)
572 			{
573 				if (pes_packet[1 + offset] == 0)
574 					return -1;
575 				else
576 					return -2;
577 			}
578 			else
579 				return -3;
580 		}
581 
582 		return -4;
583 	}
584 
585 	/**
586 	 * skip leading bytes before first valid startcodes and return fixed array
587 	 */
alignSyncword(byte[] pes_packet, int pes_offset, int es_streamtype)588 	public static boolean alignSyncword(byte[] pes_packet, int pes_offset, int es_streamtype)
589 	{
590 		int pes_payloadlength = getPES_LengthField(pes_packet, pes_offset);
591 		int pes_headerlength = 9;
592 		int pes_packetlength = pes_headerlength - 3 + pes_payloadlength;
593 		int pes_extensionlength = getPES_ExtensionLengthField(pes_packet, pes_offset);
594 
595 		int offset = pes_headerlength + pes_extensionlength;
596 		int i, j, k;
597 
598 		boolean found = false;
599 
600 		packloop:
601 		for (i = offset, j = pes_packetlength - 3, k = offset + pes_offset; i < j; i++, k++)
602 		{
603 			switch (es_streamtype)
604 			{
605 			case MPEG_VIDEO:
606 				if (pes_packet[k] != 0 || pes_packet[1 + k] != 0  || pes_packet[2 + k] != 1 || pes_packet[3 + k] != (byte)SEQUENCE_HEADER_CODE)
607 					continue packloop;
608 
609 				found = true;
610 				break packloop;
611 
612 			case AC3_AUDIO:
613 			case DTS_AUDIO:
614 				if ((pes_packet[k] != 0xB || pes_packet[1 + k] != 0x77) && (pes_packet[k] != 0x7F || pes_packet[1 + k] != (byte)0xFE || pes_packet[2 + k] != (byte)0x80 || pes_packet[3 + k] != 1))
615 					continue packloop;
616 
617 				found = true;
618 				break packloop;
619 
620 			case MPEG_AUDIO:
621 				if ( pes_packet[k] != (byte)0xFF || (0xF0 & pes_packet[1 + k]) != 0xF0)
622 					continue packloop;
623 
624 				found = true;
625 				break packloop;
626 			}
627 		}
628 
629 		if (found)
630 		{
631 			System.arraycopy(pes_packet, i + pes_offset, pes_packet, offset + pes_offset, pes_packetlength - i);
632 
633 			pes_payloadlength -= (i - offset);
634 
635 			setPES_LengthField(pes_packet, pes_offset, pes_payloadlength);
636 		}
637 
638 		return found;
639 	}
640 
641 	/**
642 	 * create PTS alias
643 	 */
logAlias(JobProcessing job_processing, String _vptslog, String _datalog)644 	public static void logAlias(JobProcessing job_processing, String _vptslog, String _datalog)
645 	{
646 		File vpts = new File(_vptslog);
647 
648 		try {
649 			RandomAccessFile log = new RandomAccessFile(_datalog, "rw");
650 
651 			log.seek(0);
652 
653 			if (vpts.exists() && vpts.length() > 0)
654 			{
655 				RandomAccessFile vlog = new RandomAccessFile(_vptslog, "r");
656 				long p = vlog.readLong();
657 
658 				if (!job_processing.hasElementaryVideoStream() && job_processing.getSplitPart() == 0)
659 					job_processing.setFirstAudioPts(p);
660 
661 				log.writeLong(job_processing.getFirstAudioPts() + (Common.getSettings().getBooleanProperty(Keys.KEY_additionalOffset) ? 90L * Common.getSettings().getIntProperty(Keys.KEY_ExportPanel_additionalOffset_Value) : 0));
662 
663 				vlog.close();
664 			}
665 			else
666 				log.writeLong(0L + (Common.getSettings().getBooleanProperty(Keys.KEY_additionalOffset) ? Common.getSettings().getIntProperty(Keys.KEY_ExportPanel_additionalOffset_Value) : 0));
667 
668 			log.writeLong(0L);
669 			log.close();
670 
671 			Common.setMessage("");
672 			Common.setMessage(Resource.getString("all.msg.pts.faked"));
673 
674 		} catch (IOException e) {
675 
676 			Common.setExceptionMessage(e);
677 		}
678 	}
679 
680 	/**
681 	 * split reset
682 	 */
resetSplitMode(JobProcessing job_processing, String vptslog)683 	public static void resetSplitMode(JobProcessing job_processing, String vptslog)
684 	{
685 		if ( vptslog.equals("-1") && job_processing.getSplitSize() > 0 )
686 		{
687 			job_processing.setSplitSize(0);
688 			Common.setMessage(Resource.getString("splitreset.novideo"));
689 		}
690 	}
691 
692 
693 	/**
694 	 * parse cut long value
695 	 */
parseCutValue(long value)696 	public static String parseCutValue(long value)
697 	{
698 		if (Common.getSettings().getIntProperty(Keys.KEY_CutMode) != CUTMODE_TIME)
699 			return String.valueOf(value);
700 
701 		String str = "";
702 		long frametime = 1;
703 		value /= 90;
704 
705 		DateFormat time = new SimpleDateFormat("H:mm:ss:");
706 		time.setTimeZone(TimeZone.getTimeZone("GMT+0:00"));
707 
708 		Calendar cal = Calendar.getInstance();
709 		cal.setTimeZone(TimeZone.getTimeZone("GMT+0:00"));
710 		cal.setTime(new Date(value));
711 
712 		int frame = (cal.get(14) / ((int)frametime));
713 		str = time.format(new Date(value)) + (frame < 10 ? "0" : "") + frame;
714 
715 		return str;
716 	}
717 
718 	/**
719 	 * parse cut field value
720 	 */
parseCutValue(String value, boolean demux)721 	public static long parseCutValue(String value, boolean demux)
722 	{
723 		if (value == null)
724 			return 0;
725 
726 		value = value.trim();
727 
728 		try {
729 			if (Common.getSettings().getIntProperty(Keys.KEY_CutMode) != CUTMODE_TIME)
730 				return Long.parseLong(value);
731 
732 		} catch (Exception e) {
733 			return -1L;
734 		}
735 
736 		int i;
737 		if ( (i = value.indexOf(" ")) > -1)
738 			value = value.substring(0, i);
739 
740 		value = value.replace('.',':');
741 
742 		if (value.indexOf(":") < 0)
743 			return Long.parseLong(value);
744 
745 		StringTokenizer st = new StringTokenizer(value, ":");
746 		String str = null;
747 		long val = 0;
748 		long frametime = !demux ? 90 : (long)_videoframerate;
749 		long mp[] = { 324000000L, 5400000L, 90000L, frametime }; //h,m,s,f
750 
751 		for (int a=0; st.hasMoreTokens() && a < 4; a++)
752 		{
753 			str = st.nextToken();
754 			val += (mp[a] * Long.parseLong(str));
755 		}
756 
757 		return val;
758 	}
759 
760 
761 	/**
762 	 * video timelength read from ptslogfile
763 	 */
calcVideoTime(String logfile)764 	public static long calcVideoTime(String logfile)
765 	{
766 		long vtime = 0;
767 
768 		try {
769 			long vlogsize = new File(logfile).length();
770 			RandomAccessFile vlog = new RandomAccessFile(logfile, "r");
771 
772 			vlog.seek(vlogsize - 8);
773 
774 			vtime = vlog.readLong();
775 
776 			vlog.close();
777 		}
778 
779 		catch (IOException e) {
780 
781 			Common.setExceptionMessage(e);
782 		}
783 
784 		return vtime;
785 	}
786 
787 
788 	/**
789 	 * make cut
790 	 */
makecut(JobProcessing job_processing, long comparePoint, List ctemp)791 	public static boolean makecut(JobProcessing job_processing, long comparePoint, List ctemp)
792 	{
793 		return makecut(job_processing, null, 0, comparePoint, new ArrayList(), 0, ctemp, 0, new ArrayList());
794 	}
795 
796 	/**
797 	 * make cut
798 	 */
makecut(JobProcessing job_processing, String cuts_filename, long startPTS, long comparePoint, List newcut, int lastframes, List ctemp, int gopnumber, List cell)799 	public static boolean makecut(JobProcessing job_processing, String cuts_filename, long startPTS, long comparePoint, List newcut, int lastframes, List ctemp, int gopnumber, List cell)
800 	{
801 		if (ctemp.isEmpty())
802 			return true;
803 
804 		long[] abc;
805 
806 		if ( _cutcount < ctemp.size() )
807 		{
808 			if ( comparePoint > parseCutValue(ctemp.get(_cutcount).toString(), true) )
809 			{
810 				/**
811 				 * ungerade == cutout
812 				 */
813 				if ((_cutcount & 1) == 1)
814 				{
815 					_bool = false;
816 					for (int c = newcut.size() - 1; c >- 1; c--)
817 					{
818 						abc = (long[])newcut.get(c);
819 
820 						if ( abc[0] < parseCutValue(ctemp.get(_cutcount).toString(), true) )
821 						{
822 							_bool = true;
823 
824 							Common.setMessage(Resource.getString("msg.cuts.cutin", "" + gopnumber, "" + lastframes, "" + Common.formatTime_1((long)(lastframes * (double)(_videoframerate / 90.0f)) )) + " (" + comparePoint + ")");
825 
826 							saveCuts(comparePoint, startPTS, lastframes, cuts_filename);
827 
828 						//	if (lastframes > 0)
829 						//		cell.add("" + lastframes); // celltimes for cutin
830 
831 							break;
832 						}
833 					}
834 
835 					if (!_bool)
836 					{
837 						Common.setMessage(Resource.getString("msg.cuts.cutout", "" + gopnumber) + " (" + comparePoint + ")");
838 
839 						saveCuts(comparePoint, startPTS, lastframes, cuts_filename);
840 					}
841 
842 					_cutcount++;
843 
844 					return _bool;
845 				}
846 
847 				/**
848 				 * gerade == cutin
849 				 */
850 				else
851 				{
852 
853 					_bool = true;
854 					_cutcount++;
855 
856 					Common.setMessage(Resource.getString("msg.cuts.cutin", "" + gopnumber, "" + lastframes, "" + Common.formatTime_1((long)(lastframes * (double)(_videoframerate / 90.0f)) )) + " (" + comparePoint + ")");
857 
858 					saveCuts(comparePoint, startPTS, lastframes, cuts_filename);
859 
860 				//	if (lastframes > 0)
861 				//		cell.add("" + lastframes); // celltimes for cutin
862 
863 					if (_cutcount >= ctemp.size())
864 						return _bool;
865 
866 					for (int c = newcut.size() - 1; c >- 1; c--)
867 					{
868 						abc = (long[])newcut.get(c);
869 
870 						if ( abc[0] < parseCutValue(ctemp.get(_cutcount).toString(), true) )
871 						{
872 							_cutcount++;
873 
874 							break;
875 						}
876 					}
877 
878 					return _bool;
879 				}
880 			}
881 		}
882 
883 		else
884 		{
885 			if (!_bool && job_processing.getCutComparePoint() == 10000000)
886 				job_processing.setCutComparePoint(comparePoint);
887 		}
888 
889 		return _bool;
890 	}
891 
892 	/**
893 	 * saves the cutpoint list from coll specials
894 	 */
saveCuts(long cutposition, long startPTS, long lastframes, String cuts_filename)895 	private static void saveCuts(long cutposition, long startPTS, long lastframes, String cuts_filename)
896 	{
897 		if ( Common.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_exportPts) && cuts_filename != null)
898 		{
899 			try {
900 				cuts_filename += ".Xpl";
901 
902 				PrintWriter pts_writer = new PrintWriter(new FileOutputStream(cuts_filename, lastframes > 0));
903 
904 				if (new File(cuts_filename).length() == 0)
905 					pts_writer.println(Keys.KEY_CutMode[0] + "=3"); // PTS cut mode fixed for file
906 
907 				pts_writer.println(startPTS);
908 				pts_writer.close();
909 
910 				Common.setMessage(Resource.getString("msg.savecut", "" + startPTS));
911 
912 			} catch (IOException e) {
913 
914 				Common.setExceptionMessage(e);
915 			}
916 		}
917 	}
918 
919 
920 	/**
921 	 * set 1. videoheader
922 	 */
setVideoHeader(JobProcessing job_processing, String videofile, String logfile, int[] clv, int[] MPGVideotype)923 	public static void setVideoHeader(JobProcessing job_processing, String videofile, String logfile, int[] clv, int[] MPGVideotype)
924 	{
925 		long time = 0;
926 		String videotype[] = { "(m1v)", "(m2v)", "(h264)" };
927 
928 		String frames_used[] = {
929 			Resource.getString("video.msg.io.non"),
930 			Resource.getString("video.msg.io.int"),
931 			Resource.getString("video.msg.io.pro"),
932 			Resource.getString("video.msg.io.int_pro")
933 		};
934 
935 		if (new File(logfile).exists())
936 		{
937 			time = (calcVideoTime(logfile) / 90);
938 			String vt = Common.formatTime_1( time / 10 * 10 );
939 
940 			Common.setMessage(Resource.getString("video.msg.length", "" + job_processing.getExportedVideoFrameNumber()) + " " + vt);
941 			Common.setMessage(Resource.getString("video.msg.gop.summary", "" + (0x7FFF & clv[9]>>>15), "" + (0x7FFF & clv[9]), "" + frames_used[clv[9]>>>30]));
942 
943 			if (clv[8] > 0)
944 				Common.setMessage(Resource.getString("video.error.pts.same", "" + clv[8]));
945 
946 			job_processing.getSummaryInfo().add(Resource.getString("video.summary", videotype[MPGVideotype[0]], "" + job_processing.getExportedVideoFrameNumber(), "" + vt) + "'" + videofile + "'");
947 		}
948 
949 		if (MPGVideotype[0] > 1) // h264 without modif.
950 		{
951 			Common.setMessage(Resource.getString("video.msg.bitrate.avg", "" + ((job_processing.getMinBitrate() + job_processing.getMaxBitrate()) / 2 * 400), "" + (job_processing.getMinBitrate() * 400) + "/" + (job_processing.getMaxBitrate() * 400)));
952 			Common.setMessage(Resource.getString("msg.newfile") + " " + videofile);
953 			return;
954 		}
955 
956 		try {
957 
958 			RandomAccessFile pv2 = new RandomAccessFile(videofile, "rw");
959 
960 			if (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInAllSequences) > 0)
961 			{
962 				if (time == 0)
963 					Common.setMessage(Resource.getString("video.msg.bitrate.avg", "" + ((job_processing.getMinBitrate() + job_processing.getMaxBitrate()) / 2 * 400), "" + (job_processing.getMinBitrate() * 400) + "/" + (job_processing.getMaxBitrate() * 400)));
964 
965 				else
966 					Common.setMessage(Resource.getString("video.msg.bitrate.avgnom", "" + ((pv2.length() * 8000L) / time), "" + (job_processing.getMinBitrate() * 400) + "/" + (job_processing.getMaxBitrate() * 400)));
967 
968 			}
969 
970 			else if (Common.getSettings().getBooleanProperty(Keys.KEY_DebugLog))
971 				System.out.println();
972 
973 			if (!Common.getSettings().getBooleanProperty(Keys.KEY_WriteOptions_writeVideo))
974 			{
975 				pv2.close();
976 
977 				return;
978 			}
979 
980 			int max_bitrate_value = 22500; // 9.0Mbit, (video only)
981 
982 			/**
983 			 * bitraten
984 			 */
985 			if (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInFirstSequence) > 0)
986 			{
987 				int newmux = (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInFirstSequence) == 3) ? job_processing.getMaxBitrate() : max_bitrate_value;
988 
989 				if (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInFirstSequence) == 2 && job_processing.getMaxBitrate() < max_bitrate_value)
990 					newmux = job_processing.getMaxBitrate();
991 
992 				if (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInFirstSequence) == 1)
993 				{
994 					if (time == 0)
995 						newmux = (job_processing.getMinBitrate() + job_processing.getMaxBitrate()) / 2;   // old calcul. avg.
996 
997 					else
998 					{
999 						newmux = (int)(((pv2.length() * 8000L) / time) / 400);
1000 
1001 						if (newmux < 0 || newmux > max_bitrate_value)
1002 							newmux = (job_processing.getMinBitrate() + job_processing.getMaxBitrate()) / 2;   // old calcul. avg.
1003 					}
1004 				}
1005 
1006 				if (Common.getSettings().getIntProperty(Keys.KEY_ChangeBitrateInFirstSequence) == 4)
1007 				{
1008 					newmux = 0x3FFFF;
1009 
1010 					Common.setMessage(Resource.getString("video.msg.bitrate.vbr"));
1011 				}
1012 
1013 				else
1014 					Common.setMessage(Resource.getString("video.msg.bitrate.val", "" + (newmux*400)));
1015 
1016 				pv2.seek(8);
1017 				newmux = (newmux<<14) | ((pv2.readInt()<<18)>>>18);
1018 
1019 				pv2.seek(8);
1020 				pv2.writeInt(newmux);
1021 			}
1022 
1023 			/**
1024 			 * patch resolution DVD-conform
1025 			 */
1026 			//JLA14082003+
1027 			//0: no patch, 1:patch unconditionally, 2:patch if <>720|352, 3:pach if <>720|704|352
1028 			if (Common.getSettings().getIntProperty(Keys.KEY_ConditionalHorizontalPatch) != 0)
1029 			{
1030 				pv2.seek(4);
1031 
1032 				int resolutionOrig = pv2.readInt();
1033 				int hresOrg = (resolutionOrig>>>20);
1034 				int resolution = (0xFFFFF & resolutionOrig) | Common.getSettings().getIntProperty(Keys.KEY_ConditionalHorizontalResolution)<<20;
1035 				boolean doPatch;
1036 
1037 				switch (Common.getSettings().getIntProperty(Keys.KEY_ConditionalHorizontalPatch))
1038 				{
1039 				case 2:
1040 					doPatch = hresOrg != 720 && hresOrg != 352;
1041 					break;
1042 
1043 				case 3:
1044 					doPatch = hresOrg != 720 && hresOrg != 704 && hresOrg != 352;
1045 					break;
1046 
1047 				default:
1048 					doPatch = true;
1049 				}
1050 
1051 				if(doPatch)
1052 				{
1053 					pv2.seek(4);
1054 					pv2.writeInt(resolution);
1055 
1056 					Common.setMessage(Resource.getString("video.msg.resolution", "" + (resolutionOrig>>>20)+"*"+((0xFFF00&resolutionOrig)>>>8)) + " " + (resolution>>>20)+"*"+((0xFFF00&resolution)>>>8));
1057 				}
1058 			}
1059 			//JLA14082003-
1060 
1061 			pv2.close();
1062 
1063 			Common.setMessage(Resource.getString("msg.newfile") + " " + videofile);
1064 
1065 		} catch (IOException e) {
1066 
1067 			Common.setExceptionMessage(e);
1068 		}
1069 	}
1070 
1071 	/**
1072 	 * vdr_dvbsub determination
1073 	 */
getExtension2_Id(byte[] pes_packet, int pes_headerlength, int pes_payloadlength, int pesID, boolean pes_isMpeg2, long file_position)1074 	public static int getExtension2_Id(byte[] pes_packet, int pes_headerlength, int pes_payloadlength, int pesID, boolean pes_isMpeg2, long file_position)
1075 	{
1076 		boolean extension_error = false;
1077 		int pes_extension2_id = -1;
1078 
1079 		if (!pes_isMpeg2)
1080 			return pes_extension2_id;
1081 
1082 		else if (pesID != PRIVATE_STREAM_1_CODE && (0xE0 & pesID) != 0xC0 && (0xF0 & pesID) != 0xE0) //not pD, Aud, Vid
1083 			return pes_extension2_id;
1084 
1085 		//read flags
1086 		int pes_shift = pes_headerlength; //points to 1st appendix
1087 
1088 		pes_shift += (0x80 & pes_packet[7]) != 0 ? 5 : 0; //pes_pts
1089 		pes_shift += (0x40 & pes_packet[7]) != 0 ? 5 : 0; //pes_dts
1090 		pes_shift += (0x20 & pes_packet[7]) != 0 ? 6 : 0; //pes_escr
1091 		pes_shift += (0x10 & pes_packet[7]) != 0 ? 3 : 0; //pes_esrate
1092 		pes_shift += (4 & pes_packet[7]) != 0 ? 1 : 0; //pes_copy
1093 		pes_shift += (2 & pes_packet[7]) != 0 ? 2 : 0; //pes_crc
1094 
1095 		boolean pes_ext1 = (1 & pes_packet[7]) != 0; //ext1
1096 		boolean pes_ext2 = false; //ext2
1097 
1098 		int pes_extension_length = 0xFF & pes_packet[8]; //all data must be inside extension
1099 
1100 		if (pes_headerlength + pes_extension_length < pes_shift)
1101 			extension_error = true;
1102 
1103 		else if (pes_ext1 && pes_headerlength + pes_extension_length < pes_shift + 1)
1104 			extension_error = true;
1105 
1106 		else if (pes_ext1)
1107 		{
1108 			int shift = pes_shift;
1109 
1110 			if (6 + pes_payloadlength < pes_shift + 1)
1111 				extension_error = true;
1112 
1113 			else
1114 			{
1115 				pes_shift += (0x80 & pes_packet[shift]) != 0 ? 16 : 0; //pes_private
1116 				pes_shift += (0x40 & pes_packet[shift]) != 0 ? 1 : 0; //pes_packfield
1117 				pes_shift += (0x20 & pes_packet[shift]) != 0 ? 2 : 0; //pes_sequ_counter
1118 				pes_shift += (0x10 & pes_packet[shift]) != 0 ? 2 : 0; //pes_P-STD
1119 				// marker 3 bits
1120 
1121 				pes_ext2 = (1 & pes_packet[shift]) != 0; //ext2
1122 
1123 				pes_shift++; //skip flag_fields of ext1
1124 
1125 				if (pes_headerlength + pes_extension_length < pes_shift)
1126 					extension_error = true;
1127 
1128 				else if (pes_ext2)
1129 				{
1130 					int pes_ext2_length = 0x7F & pes_packet[pes_shift];
1131 
1132 					pes_shift++; //skip length_fields of ext2
1133 
1134 					if (6 + pes_payloadlength < pes_shift + pes_ext2_length)
1135 						extension_error = true;
1136 
1137 					else if (pes_headerlength + pes_extension_length < pes_shift + pes_ext2_length)
1138 						extension_error = true;
1139 
1140 					else if (pesID == PRIVATE_STREAM_1_CODE)
1141 						pes_extension2_id = 0xFF & pes_packet[pes_shift]; //read byte0 (res.) of ext2
1142 				}
1143 			}
1144 		}
1145 
1146 		if (extension_error)
1147 			Common.setMessage("!> error in pes_extension of pes-ID 0x" + Integer.toHexString(pesID).toUpperCase() + " @ pos: " + file_position + " (" + (6 + pes_payloadlength) + " / " + (pes_headerlength + pes_extension_length) + " / " + (pes_shift + 1) + " / " + pes_ext1 + " / " + pes_ext2 + ")");
1148 
1149 		return pes_extension2_id;
1150 	}
1151 }