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 }