1 /* 2 * @(#)StreamParser 3 * 4 * Copyright (c) 2005-2006 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.File; 30 import java.io.InputStream; 31 import java.io.IOException; 32 import java.io.PushbackInputStream; 33 import java.io.FileOutputStream; 34 35 import java.util.Arrays; 36 import java.util.List; 37 import java.util.ArrayList; 38 import java.util.Hashtable; 39 40 import net.sourceforge.dvb.projectx.common.Common; 41 import net.sourceforge.dvb.projectx.common.Resource; 42 import net.sourceforge.dvb.projectx.common.Keys; 43 import net.sourceforge.dvb.projectx.common.JobCollection; 44 import net.sourceforge.dvb.projectx.common.JobProcessing; 45 46 import net.sourceforge.dvb.projectx.io.StandardBuffer; 47 48 import net.sourceforge.dvb.projectx.xinput.XInputFile; 49 import net.sourceforge.dvb.projectx.xinput.StreamInfo; 50 51 import net.sourceforge.dvb.projectx.parser.CommonParsing; 52 import net.sourceforge.dvb.projectx.parser.StreamConverter; 53 import net.sourceforge.dvb.projectx.parser.StreamDemultiplexer; 54 import net.sourceforge.dvb.projectx.parser.StreamParserBase; 55 56 57 /** 58 * main thread 59 */ 60 public class StreamParserPESPrimary extends StreamParserBase { 61 62 private boolean Message_2; 63 private boolean Debug; 64 private boolean SimpleMPG; 65 private boolean GetEnclosedPackets; 66 private boolean IgnoreScrambledPackets; 67 private boolean PreviewAllGops; 68 private boolean DumpDroppedGop; 69 private boolean Overlap; 70 71 /** 72 * 73 */ StreamParserPESPrimary()74 public StreamParserPESPrimary() 75 { 76 super(); 77 } 78 79 /** 80 * primary PES Parser 81 */ parseStream(JobCollection collection, XInputFile aXInputFile, int _pes_streamtype, int action, String vptslog)82 public String parseStream(JobCollection collection, XInputFile aXInputFile, int _pes_streamtype, int action, String vptslog) 83 { 84 JobProcessing job_processing = collection.getJobProcessing(); 85 86 setFileName(collection, job_processing, aXInputFile); 87 88 Debug = collection.getSettings().getBooleanProperty(Keys.KEY_DebugLog); 89 Message_2 = collection.getSettings().getBooleanProperty(Keys.KEY_MessagePanel_Msg2); 90 SimpleMPG = collection.getSettings().getBooleanProperty(Keys.KEY_simpleMPG); 91 GetEnclosedPackets = collection.getSettings().getBooleanProperty(Keys.KEY_Input_getEnclosedPackets); 92 IgnoreScrambledPackets = collection.getSettings().getBooleanProperty(Keys.KEY_TS_ignoreScrambled); 93 PreviewAllGops = collection.getSettings().getBooleanProperty(Keys.KEY_Preview_AllGops); 94 DumpDroppedGop = collection.getSettings().getBooleanProperty(Keys.KEY_dumpDroppedGop); 95 CreateD2vIndex = collection.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_createD2vIndex); 96 SplitProjectFile = collection.getSettings().getBooleanProperty(Keys.KEY_ExternPanel_splitProjectFile); 97 Overlap = collection.getSettings().getBooleanProperty(Keys.KEY_ExportPanel_Export_Overlap); 98 99 setOverheadSize(collection); 100 101 boolean isTeletext = false; 102 boolean missing_startcode = false; 103 boolean scrambling_messaged = false; 104 boolean pes_isMpeg2; 105 boolean pes_alignment; 106 boolean pes_scrambled; 107 boolean containsPts = false; 108 boolean usePidfilter = false; 109 boolean isZeroPacket = false; 110 boolean isZeroSubPacket = false; 111 boolean ende = false; 112 boolean foundObject; 113 114 int Infoscan_Value = Integer.parseInt(collection.getSettings().getProperty(Keys.KEY_ExportPanel_Infoscan_Value)); 115 int CutMode = collection.getSettings().getIntProperty(Keys.KEY_CutMode); 116 int pes_streamtype = _pes_streamtype; 117 int pes_payloadlength; 118 int pes_packetlength; 119 int pes_extensionlength; 120 int pes_headerlength = 9; 121 int pes_packetoffset = 6; 122 int pes_extension2_id; 123 int pesID; 124 int subID; 125 int offset; 126 int returncode = 0; 127 int vob_ID = 0; 128 int cell_ID = 0; 129 int ZeroPacketPayload = 0x17FA; 130 131 int tmp_value1 = 0; 132 133 int pesID0 = 0; //first video stream ID 134 int dumped_packets = 0; 135 136 job_processing.clearStatusVariables(); 137 int[] clv = job_processing.getStatusVariables(); 138 139 int[] newID = { 0x80, 0x90, 0xC0, 0xE0, 0xA0, 0x20 }; 140 141 byte[] pes_packet = new byte[0x10010]; 142 byte[] buffered_data; 143 144 long count = 0; 145 long base; 146 long size = count; 147 long qexit; 148 long ptsoffset = 0; 149 long lastpts = 0; 150 long startPoint = 0; 151 long starts[] = new long[collection.getPrimaryInputFileSegments()]; 152 long Overlap_Value = 1048576L * (collection.getSettings().getIntProperty(Keys.KEY_ExportPanel_Overlap_Value) + 1); 153 154 vptslog = "-1"; //fix 155 156 String file_id = aXInputFile.getFileID(); 157 158 streamconverter = new StreamConverter(); 159 160 Hashtable substreams = new Hashtable(); 161 StandardBuffer sb; 162 163 demuxList = job_processing.getPrimaryPESDemuxList(); 164 165 /** 166 * re-read old streams, for next split part 167 */ 168 if (job_processing.getSplitPart() == 0) 169 demuxList.clear(); 170 171 else 172 { 173 for (int i = 0; i < demuxList.size(); i++) 174 { 175 streamdemultiplexer = (StreamDemultiplexer) demuxList.get(i); 176 177 if (streamdemultiplexer.getnewID() != 0) 178 newID[streamdemultiplexer.getType()]++; 179 180 if (streamdemultiplexer.getNum() == -1) 181 continue; 182 183 if (streamdemultiplexer.getType() == CommonParsing.MPEG_VIDEO) 184 { 185 streamdemultiplexer.initVideo2(collection, fparent); 186 187 if (pesID0 == 0) //? 188 pesID0 = streamdemultiplexer.getID(); 189 } 190 else 191 streamdemultiplexer.init2(collection, fparent); 192 } 193 } 194 195 /** 196 * init conversions 197 */ 198 String mpeg_type_str = (Keys.ITEMS_FileTypes[pes_streamtype]).toString().toLowerCase(); 199 mpeg_type_str = "[" + mpeg_type_str.substring(0, mpeg_type_str.indexOf(' ')) + "]"; 200 201 initConversion(collection, fparent + (job_processing.getSplitSize() == 0 ? mpeg_type_str : ""), action, CommonParsing.ACTION_TO_VDR, job_processing.getSplitPart()); 202 203 /** 204 * d2v projectfile 205 */ 206 if (CreateD2vIndex || SplitProjectFile) 207 job_processing.getProjectFileD2V().Init(fparent); 208 209 job_processing.setMinBitrate(CommonParsing.MAX_BITRATE_VALUE); 210 job_processing.setMaxBitrate(0); 211 job_processing.setExportedVideoFrameNumber(0); 212 job_processing.setEndPtsOfGop(-10000); 213 job_processing.setSequenceHeader(true); 214 job_processing.setAllMediaFilesExportLength(0); 215 job_processing.setProjectFileExportLength(0); 216 job_processing.setCutByteposition(0); 217 218 /** 219 * pid inclusion 220 */ 221 int[] predefined_Pids = collection.getPIDsAsInteger(); 222 int[] include = new int[predefined_Pids.length]; 223 224 for (int i = 0; i < include.length; i++) 225 include[i] = 0xFF & predefined_Pids[i]; 226 227 if (include.length > 0) 228 { 229 Arrays.sort(include); 230 231 String str = " "; 232 233 for (int i = 0; i < include.length; i++) 234 str += "0x" + Integer.toHexString(include[i]).toUpperCase() + " "; 235 236 Common.setMessage(Resource.getString("parsePrimaryPES.special.pes") + ": {" + str + "}"); 237 238 usePidfilter = true; 239 } 240 241 242 try { 243 244 /** 245 * determine start & end byte pos. of each file segment 246 */ 247 for (int i = 0; i < starts.length; i++) 248 { 249 aXInputFile = (XInputFile) collection.getInputFile(i); 250 starts[i] = size; 251 size += aXInputFile.length(); 252 } 253 254 aXInputFile = (XInputFile) collection.getInputFile(job_processing.getFileNumber()); 255 256 /** 257 * set start & end byte pos. of first file segment 258 */ 259 count = starts[job_processing.getFileNumber()]; 260 size = count + aXInputFile.length(); 261 262 /** 263 * split skipping first, for next split part 264 */ 265 if (job_processing.getSplitSize() > 0) 266 { 267 startPoint = job_processing.getLastHeaderBytePosition(); 268 startPoint -= !Overlap ? 0 : Overlap_Value; 269 270 job_processing.setLastGopTimecode(0); 271 job_processing.setLastGopPts(0); 272 job_processing.setLastSimplifiedPts(0); 273 } 274 275 List CutpointList = collection.getCutpointList(); 276 List ChapterpointList = collection.getChapterpointList(); 277 278 /** 279 * jump near to first cut-in point to collect more audio 280 */ 281 if (CutMode == CommonParsing.CUTMODE_BYTE && CutpointList.size() > 0 && CommonParsing.getCutCounter() == 0 && (!PreviewAllGops || action != CommonParsing.ACTION_DEMUX)) 282 startPoint = Long.parseLong(CutpointList.get(CommonParsing.getCutCounter()).toString()) - ((action == CommonParsing.ACTION_DEMUX) ? OverheadSize : 0); 283 284 if (startPoint < 0) 285 startPoint = count; // =0 286 287 else if (startPoint < count) 288 { 289 for (int i = starts.length; i > 0; i--) 290 if (starts[i - 1] > startPoint) 291 job_processing.countFileNumber(-1); 292 } 293 294 else if (startPoint > count) 295 { 296 for (int i = job_processing.getFileNumber() + 1; i < starts.length; i++) 297 { 298 if (starts[i] > startPoint) 299 break; 300 else 301 job_processing.countFileNumber(+1); 302 } 303 } 304 305 aXInputFile = (XInputFile) collection.getInputFile(job_processing.getFileNumber()); 306 count = starts[job_processing.getFileNumber()]; 307 308 if (job_processing.getFileNumber() > 0) 309 Common.setMessage(Resource.getString("parsePrimaryPES.continue") + ": " + aXInputFile); 310 311 base = count; 312 size = count + aXInputFile.length(); 313 314 PushbackInputStream in = new PushbackInputStream(aXInputFile.getInputStream(startPoint - base), pes_packet.length); 315 316 count += (startPoint - base); 317 318 Common.updateProgressBar((action == CommonParsing.ACTION_DEMUX ? Resource.getString("parsePrimaryPES.demuxing") : Resource.getString("parsePrimaryPES.converting")) + " " + Resource.getString("parsePrimaryPES.avpes.file") + " " + aXInputFile.getName(), (count - base), (size - base)); 319 320 qexit = count + (0x100000L * Infoscan_Value); 321 322 //yield(); 323 324 bigloop: 325 while (true) 326 { 327 loop: 328 while (count < size) 329 { 330 pes_streamtype = _pes_streamtype; // reset to original type 331 332 Common.updateProgressBar(count, size); 333 334 //yield(); 335 336 while (pause()) 337 {} 338 339 if (CommonParsing.isProcessCancelled() || (CommonParsing.isInfoScan() && count > qexit)) 340 { 341 CommonParsing.setProcessCancelled(false); 342 job_processing.setSplitSize(0); 343 344 break bigloop; 345 } 346 347 /** 348 * after last cut out, still read some packets to collect some audio 349 */ 350 if (job_processing.getCutComparePoint() + 20 < job_processing.getSourceVideoFrameNumber()) 351 { 352 ende = true; 353 break bigloop; 354 } 355 356 /** 357 * cut mode bytepos + min 1 cutpoint 358 */ 359 if (CutMode == CommonParsing.CUTMODE_BYTE && CutpointList.size() > 0) 360 { 361 if (CommonParsing.getCutCounter() == CutpointList.size() && (CommonParsing.getCutCounter() & 1) == 0) 362 if (count > Long.parseLong(CutpointList.get(CommonParsing.getCutCounter() - 1).toString()) + (action == CommonParsing.ACTION_DEMUX ? OverheadSize : 64000)) 363 { 364 ende = true; 365 break bigloop; 366 } 367 } 368 369 in.read(pes_packet, 0, pes_packetoffset); 370 371 pesID = CommonParsing.getPES_IdField(pes_packet, 0); 372 373 /** 374 * 375 */ 376 if ((returncode = CommonParsing.validateStartcode(pes_packet, 0)) < 0 || pesID < CommonParsing.SYSTEM_END_CODE) 377 { 378 returncode = returncode < 0 ? -returncode : 4; 379 380 if (Message_2 && !missing_startcode) 381 Common.setMessage(Resource.getString("parsePrimaryPES.missing.startcode") + " " + count); 382 383 in.read(pes_packet, pes_packetoffset, pes_packet.length - pes_packetoffset); 384 385 int i = returncode; 386 387 for (; i < pes_packet.length - 3; ) 388 { 389 returncode = CommonParsing.validateStartcode(pes_packet, i); 390 391 if (returncode < 0) 392 { 393 i += -returncode; 394 continue; 395 } 396 397 else 398 { 399 in.unread(pes_packet, i, pes_packet.length - i); 400 401 count += i; 402 missing_startcode = true; 403 404 continue loop; 405 } 406 } 407 408 in.unread(pes_packet, i, pes_packet.length - i); 409 410 count += i; 411 missing_startcode = true; 412 413 continue loop; 414 } 415 416 if (Message_2 && missing_startcode) 417 Common.setMessage(Resource.getString("parsePrimaryPES.found.startcode") + " " + count); 418 419 missing_startcode = false; 420 421 if (pes_streamtype == CommonParsing.MPEG1PS_TYPE || pes_streamtype == CommonParsing.MPEG2PS_TYPE || SimpleMPG) 422 { 423 switch (pesID) 424 { 425 case CommonParsing.SYSTEM_END_CODE: 426 in.unread(pes_packet, 4, 2); 427 Common.setMessage("-> skip system_end_code @ " + count); 428 count += 4; 429 continue loop; 430 431 case CommonParsing.PACK_START_CODE: 432 if ((0xC0 & pes_packet[4]) == 0) //mpg1 433 { 434 in.skip(pes_packetoffset); 435 count += 12; 436 continue loop; 437 } 438 439 else if ((0xC0 & pes_packet[4]) == 0x40) //mpg2 440 { 441 in.read(pes_packet, pes_packetoffset, 8); 442 443 offset = 7 & pes_packet[13]; 444 445 count += 14; 446 447 in.read(pes_packet, 14, offset); 448 449 if (offset > 0) 450 { 451 for (int i = 0; i < offset; i++) 452 if (pes_packet[14 + i] != -1) 453 { 454 in.unread(pes_packet, 14, offset); 455 456 Common.setMessage("!> wrong pack header stuffing @ " + count); 457 missing_startcode = true; 458 continue loop; 459 } 460 } 461 462 count += offset; 463 464 continue loop; 465 } 466 467 else 468 { 469 in.unread(pes_packet, 4, 2); 470 count += 4; 471 continue loop; 472 } 473 474 case CommonParsing.PRIVATE_STREAM_2_CODE: //determine cellids 475 pes_payloadlength = CommonParsing.getPES_LengthField(pes_packet, 0); 476 477 in.read(pes_packet, pes_packetoffset, pes_payloadlength); 478 479 if (pes_packet[pes_packetoffset] == 1) //substream id 1 480 { 481 int cellid = 0xFF & pes_packet[0x22]; 482 int vobid = (0xFF & pes_packet[0x1F])<<8 | (0xFF & pes_packet[0x20]); 483 484 if (cell_ID != cellid || vob_ID != vobid) 485 { 486 Common.setMessage(Resource.getString("parsePrimaryPES.split.cellids", "" + vobid, "" + cellid, "" + count, "" + clv[6], "" + job_processing.getExportedVideoFrameNumber())); 487 488 if (collection.getSettings().getBooleanProperty(Keys.KEY_VOB_resetPts)) 489 { 490 // ptsoffset = nextFilePTS(collection, CommonParsing.PRIMARY_PES_PARSER, pes_streamtype, lastpts, job_processing.getFileNumber(), (count - base)); 491 ptsoffset = nextFilePTS(collection, CommonParsing.PRIMARY_PES_PARSER, pes_streamtype, lastpts, ptsoffset, job_processing.getFileNumber(), (count - base)); 492 493 if (ptsoffset == -1) 494 ptsoffset = 0; 495 496 else 497 { 498 for (int i = 0; i < demuxList.size(); i++) 499 { 500 streamdemultiplexer = (StreamDemultiplexer)demuxList.get(i); 501 streamdemultiplexer.PTSOffset(ptsoffset); 502 503 if (streamdemultiplexer.getID() == pesID0) 504 streamdemultiplexer.resetVideo(); 505 } 506 507 job_processing.setSequenceHeader(true); 508 job_processing.setNewVideoStream(true); 509 // job_processing.addCellTime(String.valueOf(job_processing.getExportedVideoFrameNumber())); 510 } 511 } 512 } 513 514 cell_ID = cellid; 515 vob_ID = vobid; 516 } 517 518 count += (pes_packetoffset + pes_payloadlength); 519 continue loop; 520 521 case CommonParsing.SYSTEM_START_CODE: 522 case CommonParsing.PROGRAM_STREAM_MAP_CODE: 523 case CommonParsing.PADDING_STREAM_CODE: 524 case CommonParsing.ECM_STREAM_CODE: 525 case CommonParsing.EMM_STREAM_CODE: 526 case CommonParsing.DSM_CC_STREAM_CODE: 527 case 0xF3: 528 case 0xF4: 529 case 0xF5: 530 case 0xF6: 531 case 0xF7: 532 case 0xF8: 533 case 0xF9: 534 case 0xFA: 535 case 0xFB: 536 case 0xFC: 537 case 0xFD: 538 case 0xFE: 539 case 0xFF: 540 pes_payloadlength = CommonParsing.getPES_LengthField(pes_packet, 0); 541 542 in.skip(pes_payloadlength); 543 544 count += (pes_packetoffset + pes_payloadlength); 545 continue loop; 546 } 547 } 548 549 if ( (0xF0 & pesID) != 0xE0 && (0xE0 & pesID) != 0xC0 && pesID != CommonParsing.PRIVATE_STREAM_1_CODE) 550 { 551 in.unread(pes_packet, 3, pes_packetoffset - 3); 552 count += 3; 553 continue loop; 554 } 555 556 /** 557 * mark for split at sequenceheader 558 */ 559 job_processing.setLastHeaderBytePosition(count); 560 job_processing.setCutByteposition(count); 561 562 pes_payloadlength = CommonParsing.getPES_LengthField(pes_packet, 0); 563 564 /** 565 * zeropackets of video only as PES from TS allowed 566 */ 567 isZeroPacket = pes_payloadlength == 0 && (0xF0 & pesID) == 0xE0; 568 569 if (isZeroPacket) 570 pes_payloadlength = ZeroPacketPayload; 571 572 in.read(pes_packet, pes_packetoffset, pes_payloadlength + 4); 573 574 pes_packetlength = pes_packetoffset + pes_payloadlength; 575 576 pes_isMpeg2 = (0xC0 & pes_packet[6]) == 0x80; 577 578 /** 579 * determine next startcode in zero packets 580 */ 581 if (isZeroPacket) 582 { 583 if (Debug) 584 System.out.println("A " + Resource.getString("parsePrimaryPES.packet.length") + " " + count); 585 586 //start after pes header 587 for (int i = pes_packetoffset + (pes_isMpeg2 ? 3 : 1); isZeroPacket && i <= pes_packetlength; ) 588 { 589 if ((returncode = CommonParsing.validateStartcode(pes_packet, i)) < 0 || CommonParsing.getPES_IdField(pes_packet, i) < CommonParsing.SYSTEM_END_CODE) 590 { 591 i += (returncode < 0 ? -returncode : 4); 592 continue; 593 } 594 595 /** 596 * next header found before max. size of ZeroPacketPayload 597 * handle packet as normal, the 4 added bytes will be unread in the next startcode check 598 */ 599 in.unread(pes_packet, i + 4, pes_packetlength - i); 600 601 pes_packetlength = i; 602 pes_payloadlength = pes_packetlength - pes_packetoffset; 603 604 isZeroPacket = false; 605 } 606 607 CommonParsing.setPES_LengthField(pes_packet, 0, pes_payloadlength); 608 } 609 610 /** 611 * check next startcode 612 */ 613 if (GetEnclosedPackets && !isZeroPacket && CommonParsing.validateStartcode(pes_packet, pes_packetlength) < 0) 614 { 615 if (count + pes_packetlength < size) 616 { 617 if (Message_2 && !missing_startcode) 618 Common.setMessage(Resource.getString("parsePrimaryPES.miss.startcode2", String.valueOf(count + pes_packetlength), String.valueOf(count), Integer.toHexString(pesID).toUpperCase())); 619 620 missing_startcode = true; 621 622 in.unread(pes_packet, pes_packetoffset, pes_payloadlength + 4); 623 count += pes_packetoffset; 624 625 continue loop; 626 } 627 } 628 629 else 630 in.unread(pes_packet, pes_packetlength, 4); 631 632 633 clv[5]++; 634 635 if (Debug) 636 System.out.println(Resource.getString("parsePrimaryPES.packs") + ": " + pesID + "/" + clv[5] + "/" + (pes_packetlength) + "/" + ((count * 100 / size)) + "% " + (count)); 637 638 pes_extensionlength = CommonParsing.getPES_ExtensionLengthField(pes_packet, 0); 639 640 pes_isMpeg2 = (0xC0 & pes_packet[6]) == 0x80; 641 pes_alignment = pes_isMpeg2 && (4 & pes_packet[6]) != 0; 642 pes_scrambled = pes_isMpeg2 && (0x30 & pes_packet[6]) != 0; 643 644 count += pes_packetlength; 645 646 zeropacketloop: 647 do { 648 /** 649 * exit loop 650 */ 651 if (isZeroPacket && count >= size) 652 break zeropacketloop; 653 654 /** 655 * read videos zerosubpacket data in a loop, if packet data is greater than max. ZeroPacketPayload 656 * the first read header data is re-used, we read only the rest 657 */ 658 if (isZeroSubPacket) 659 { 660 if (Debug) 661 System.out.println("B " + Resource.getString("parsePrimaryPES.packet.length") + " " + count + " / " + pes_isMpeg2); 662 663 pes_payloadlength = ZeroPacketPayload; 664 665 pes_packetlength = pes_packetoffset + pes_payloadlength; 666 667 offset = pes_isMpeg2 ? 3 : 1; 668 669 in.read(pes_packet, pes_packetoffset + offset, pes_payloadlength - offset + 4); 670 in.unread(pes_packet, pes_packetlength, 4); 671 672 for (int i = pes_packetoffset + offset; isZeroPacket && i <= pes_packetlength; ) 673 { 674 if ((returncode = CommonParsing.validateStartcode(pes_packet, i)) < 0 || CommonParsing.getPES_IdField(pes_packet, i) < CommonParsing.SYSTEM_END_CODE) 675 { 676 i += (returncode < 0 ? -returncode : 4); 677 continue; 678 } 679 680 /** 681 * next header found before max. size of ZeroPacketPayload 682 * handle packet as normal, the 4 added bytes will be unread in the next startcode check 683 */ 684 in.unread(pes_packet, i, pes_packetlength - i); 685 686 pes_packetlength = i; 687 pes_payloadlength = pes_packetlength - pes_packetoffset; 688 689 // set isZeroPacket to false, if next startcode was found 690 isZeroPacket = false; 691 } 692 693 CommonParsing.setValue(pes_packet, pes_packetoffset, offset, false, pes_isMpeg2 ? (0xF3 & pes_packet[pes_packetoffset])<<16 : 0x0F); // values of pes scrambling and copyright/copy prot. are taken from orig. 694 CommonParsing.setPES_LengthField(pes_packet, 0, pes_payloadlength); 695 696 count += (pes_payloadlength - offset); 697 } 698 699 isZeroSubPacket = isZeroPacket; 700 701 /** 702 * check scrambling 703 */ 704 if (IgnoreScrambledPackets) 705 { 706 // cannot work with scrambled data 707 if (pes_scrambled) 708 { 709 if (!scrambling_messaged) 710 { 711 scrambling_messaged = true; 712 713 Common.setMessage(Resource.getString("parseTS.scrambled", Integer.toHexString(pesID).toUpperCase(), String.valueOf(clv[5]), String.valueOf(count - pes_packetlength))); 714 } 715 716 continue zeropacketloop; 717 } 718 719 else if (scrambling_messaged) 720 { 721 Common.setMessage(Resource.getString("parseTS.clear", Integer.toHexString(pesID).toUpperCase(), String.valueOf(clv[5]), String.valueOf(count - pes_packetlength))); 722 scrambling_messaged = false; 723 } 724 } 725 726 /** 727 * vdr_dvbsub determination 728 */ 729 pes_extension2_id = CommonParsing.getExtension2_Id(pes_packet, pes_headerlength, pes_payloadlength, pesID, pes_isMpeg2, job_processing.getLastHeaderBytePosition()); 730 731 isTeletext = false; 732 subID = 0; 733 734 if (pesID == CommonParsing.PRIVATE_STREAM_1_CODE && pes_payloadlength > 2) 735 { 736 offset = pes_headerlength + pes_extensionlength; 737 738 if (offset < pes_packetlength) 739 { 740 subID = 0xFF & pes_packet[offset]; 741 isTeletext = pes_extensionlength == 0x24 && subID>>>4 == 1; 742 743 // vdr 1.5.x dvb-subs container 744 if (pes_payloadlength >= 4 && subID>>>4 == 2) 745 { 746 tmp_value1 = CommonParsing.getIntValue(pes_packet, offset, 4, !CommonParsing.BYTEREORDERING); 747 748 //vdr 1.5.x start packet of dvb-sub || subsequent packet 749 if ((pes_alignment && (0xF0FFFFFF & tmp_value1) == 0x20010000) || (!pes_alignment && (0xF0FFFFFF & tmp_value1) == 0x20010001)) 750 { 751 for (int i = offset, j = offset + 4; i < j; i++) 752 pes_packet[i] = (byte) 0xFF; 753 754 pes_extensionlength += 4; 755 pes_packet[8] = (byte)(pes_extensionlength); 756 pes_payloadlength -= 4; 757 758 //pes_extension2_id = 1; 759 pes_extension2_id = subID = tmp_value1>>>24; 760 pes_streamtype = CommonParsing.MPEG2PS_TYPE; //will be resetted before next packet 761 762 if (pes_alignment) 763 pes_packet[offset + 4] = (byte)(subID); 764 } 765 } 766 767 //subpic in vdr_pes before 1.5.x 768 if (pes_alignment && !isTeletext && (subID>>>4 == 2 || subID>>>4 == 3)) 769 pes_streamtype = CommonParsing.MPEG2PS_TYPE; //will be resetted before next packet 770 771 if (pes_streamtype != CommonParsing.MPEG1PS_TYPE && pes_streamtype != CommonParsing.MPEG2PS_TYPE && !isTeletext) 772 subID = 0; //disables LPCM too 773 } 774 775 else if (pes_streamtype != CommonParsing.MPEG1PS_TYPE) //? 776 { 777 pes_extensionlength = pes_payloadlength - 3; 778 pes_packet[8] = (byte)(pes_extensionlength); 779 } 780 781 782 /** 783 * packet buffering esp. of subpics from vdr or other pes 784 */ 785 if (pes_extension2_id != -1) 786 { 787 String str = String.valueOf(pes_extension2_id); 788 offset = pes_headerlength + pes_extensionlength; 789 790 if ( !substreams.containsKey(str)) 791 substreams.put(str, new StandardBuffer()); 792 793 sb = (StandardBuffer) substreams.get(str); 794 795 // buffer raw packet data 796 if (!pes_alignment) 797 { 798 sb.write(pes_packet, offset, pes_packetlength - offset); 799 continue zeropacketloop; 800 } 801 802 // start packet, buffer this and get last completed packet 803 else 804 { 805 buffered_data = sb.getData(); 806 807 sb.reset(); 808 sb.write(pes_packet, 0, pes_packetlength); 809 810 if (buffered_data == null || buffered_data.length < 10) 811 continue zeropacketloop; 812 813 pes_packetlength = buffered_data.length; 814 815 if (pes_packetlength > 0x10005) 816 { 817 Common.setMessage("!> sub packet too long: 0x" + Integer.toHexString(pesID).toUpperCase() + " /ext2_id " + pes_extension2_id); 818 pes_packetlength = 0x10005; 819 } 820 821 pes_payloadlength = pes_packetlength - pes_packetoffset; 822 823 System.arraycopy(buffered_data, 0, pes_packet, 0, pes_packetlength); 824 825 CommonParsing.setPES_LengthField(pes_packet, 0, pes_payloadlength); 826 827 buffered_data = null; 828 } 829 } 830 } 831 832 /** 833 * pesID, subID inclusion 834 */ 835 if (usePidfilter) 836 { 837 if (Arrays.binarySearch(include, pesID) < 0 && Arrays.binarySearch(include, subID) < 0) 838 continue zeropacketloop; 839 } 840 841 /** 842 * raw id filter extraction 843 */ 844 if (action == CommonParsing.ACTION_FILTER) 845 { 846 if (subID != 0) 847 pes_packet[6] |= 4; //set alignment 848 849 streamconverter.write(job_processing, pes_packet, 0, pes_packetlength, null, job_processing.getCutByteposition(), CommonParsing.isInfoScan(), CutpointList); 850 continue zeropacketloop; 851 } 852 853 foundObject = false; 854 855 /** 856 * find ID object 857 */ 858 for (int i = 0; i < demuxList.size(); i++) 859 { 860 streamdemultiplexer = (StreamDemultiplexer) demuxList.get(i); 861 862 foundObject = pesID == streamdemultiplexer.getID() && subID == streamdemultiplexer.subID() && isTeletext == streamdemultiplexer.isTTX(); 863 864 if (foundObject) 865 break; 866 } 867 868 /** 869 * create new ID object 870 */ 871 if (!foundObject) 872 { 873 /** 874 * dump startpacket 875 */ 876 if (DumpDroppedGop) 877 { 878 String dumpname = fparent + "(" + Integer.toHexString(pesID) + "-" + Integer.toHexString(subID) + "#" + (dumped_packets++) + "@" + (count - pes_packetlength) + ").bin"; 879 880 FileOutputStream dump = new FileOutputStream(dumpname); 881 882 dump.write(pes_packet, 0, pes_packetlength); 883 dump.flush(); 884 dump.close(); 885 886 Common.setMessage(Resource.getString("parsePrimaryPES.dump.1st") + ": " + dumpname); 887 } 888 889 String IDtype = ""; 890 891 switch (0xF0 & pesID) 892 { 893 case 0xE0: 894 IDtype = Resource.getString("idtype.mpeg.video"); 895 896 streamdemultiplexer = new StreamDemultiplexer(collection, ptsoffset); 897 streamdemultiplexer.setID(pesID); 898 streamdemultiplexer.setType(CommonParsing.MPEG_VIDEO); 899 streamdemultiplexer.setnewID(newID[CommonParsing.MPEG_VIDEO]++); 900 streamdemultiplexer.setsubID(0); 901 streamdemultiplexer.setStreamType(pes_streamtype); 902 903 demuxList.add(streamdemultiplexer); 904 905 if (pesID0 == 0 || pesID0 == pesID) 906 { 907 if (action == CommonParsing.ACTION_DEMUX) 908 streamdemultiplexer.initVideo(collection, fparent, MainBufferSize, demuxList.size(), CommonParsing.PRIMARY_PES_PARSER); 909 910 else 911 IDtype += " " + Resource.getString("idtype.mapped.to") + Integer.toHexString(streamdemultiplexer.getnewID()).toUpperCase(); 912 913 pesID0 = pesID; 914 } 915 916 else 917 IDtype += Resource.getString("idtype.ignored"); 918 919 break; 920 921 case 0xC0: 922 case 0xD0: 923 IDtype = Resource.getString("idtype.mpeg.audio"); 924 925 streamdemultiplexer = new StreamDemultiplexer(collection, ptsoffset); 926 streamdemultiplexer.setID(pesID); 927 streamdemultiplexer.setType(CommonParsing.MPEG_AUDIO); 928 streamdemultiplexer.setnewID(newID[CommonParsing.MPEG_AUDIO]++); 929 streamdemultiplexer.setsubID(0); 930 streamdemultiplexer.setStreamType(pes_streamtype); 931 932 demuxList.add(streamdemultiplexer); 933 934 if (action == CommonParsing.ACTION_DEMUX) 935 streamdemultiplexer.init(collection, fparent, MainBufferSize / demuxList.size(), demuxList.size(), CommonParsing.PRIMARY_PES_PARSER); 936 937 else 938 IDtype += " " + Resource.getString("idtype.mapped.to") + Integer.toHexString(streamdemultiplexer.getnewID()).toUpperCase(); 939 940 break; 941 } 942 943 switch (pesID) 944 { 945 case CommonParsing.PRIVATE_STREAM_1_CODE: 946 IDtype = Resource.getString("idtype.private.stream"); 947 IDtype += (isTeletext ? " TTX " : "") + (subID != 0 ? " (SubID 0x" + Integer.toHexString(subID).toUpperCase() + ")" : ""); 948 949 streamdemultiplexer = new StreamDemultiplexer(collection, ptsoffset); 950 streamdemultiplexer.setID(pesID); 951 streamdemultiplexer.setsubID(subID); 952 streamdemultiplexer.setTTX(isTeletext); 953 954 if (isTeletext) 955 { 956 streamdemultiplexer.setnewID(newID[CommonParsing.TELETEXT]++); 957 streamdemultiplexer.setType(CommonParsing.TELETEXT); 958 } 959 960 else 961 { 962 switch(subID>>>4) 963 { 964 case 0: 965 if (pes_streamtype != CommonParsing.MPEG1PS_TYPE && pes_streamtype != CommonParsing.MPEG2PS_TYPE) 966 { 967 streamdemultiplexer.setnewID(newID[CommonParsing.AC3_AUDIO]++); 968 streamdemultiplexer.setType(CommonParsing.AC3_AUDIO); 969 } 970 break; 971 972 case 8: 973 streamdemultiplexer.setnewID(newID[CommonParsing.AC3_AUDIO]++); 974 streamdemultiplexer.setType(CommonParsing.AC3_AUDIO); 975 break; 976 977 case 0xA: 978 streamdemultiplexer.setnewID(newID[CommonParsing.LPCM_AUDIO]++); 979 streamdemultiplexer.setType(CommonParsing.LPCM_AUDIO); 980 break; 981 982 case 2: 983 case 3: 984 streamdemultiplexer.setnewID(newID[CommonParsing.SUBPICTURE]++); 985 streamdemultiplexer.setType(CommonParsing.SUBPICTURE); 986 break; 987 988 default: 989 streamdemultiplexer.setType(CommonParsing.UNKNOWN); 990 } 991 } 992 993 streamdemultiplexer.setStreamType(pes_streamtype); 994 demuxList.add(streamdemultiplexer); 995 996 if (action == CommonParsing.ACTION_DEMUX) 997 { 998 switch (streamdemultiplexer.getType()) 999 { 1000 case CommonParsing.AC3_AUDIO: 1001 case CommonParsing.DTS_AUDIO: 1002 case CommonParsing.TELETEXT: 1003 case CommonParsing.SUBPICTURE: 1004 case CommonParsing.LPCM_AUDIO: 1005 streamdemultiplexer.init(collection, fparent, MainBufferSize / demuxList.size(), demuxList.size(), CommonParsing.PRIMARY_PES_PARSER); 1006 break; 1007 1008 default: 1009 IDtype += Resource.getString("idtype.ignored"); 1010 } 1011 } 1012 1013 else 1014 { 1015 if (pes_streamtype != CommonParsing.MPEG1PS_TYPE && pes_streamtype != CommonParsing.MPEG2PS_TYPE) 1016 IDtype += " " + Resource.getString("idtype.mapped.to") + Integer.toHexString(streamdemultiplexer.getnewID()).toUpperCase(); 1017 1018 else if (isTeletext || subID>>>4 == 8) 1019 IDtype += " " + Resource.getString("idtype.mapped.to") + Integer.toHexString(streamdemultiplexer.getnewID()).toUpperCase(); 1020 1021 else 1022 IDtype += Resource.getString("idtype.ignored"); 1023 } 1024 1025 if (action == CommonParsing.ACTION_TO_VDR) 1026 { 1027 if ((pes_streamtype == CommonParsing.MPEG1PS_TYPE || pes_streamtype == CommonParsing.MPEG2PS_TYPE) && subID>>>4 != 8) 1028 IDtype += Resource.getString("idtype.ignored"); 1029 } 1030 1031 break; 1032 } 1033 1034 Common.setMessage(Resource.getString("parsePrimaryPES.found.pesid") + Integer.toHexString(pesID).toUpperCase() + " " + IDtype + " @ " + job_processing.getCutByteposition()); 1035 } 1036 1037 1038 if (!streamdemultiplexer.StreamEnabled()) 1039 continue zeropacketloop; 1040 1041 /** 1042 * packet to streamdemultiplexer 1043 */ 1044 if (action == CommonParsing.ACTION_DEMUX) 1045 { 1046 if (streamdemultiplexer.getType() == CommonParsing.MPEG_VIDEO) 1047 { 1048 if (pesID0 != streamdemultiplexer.getID()) 1049 continue zeropacketloop; 1050 1051 streamdemultiplexer.writeVideo(job_processing, pes_packet, 0, pes_packetlength, true, CutpointList, ChapterpointList); 1052 } 1053 else 1054 streamdemultiplexer.write(job_processing, pes_packet, 0, pes_packetlength, true); 1055 1056 if (streamdemultiplexer.getPTS() > lastpts) 1057 lastpts = streamdemultiplexer.getPTS(); 1058 } 1059 1060 /** 1061 * packet to streamconverter 1062 */ 1063 else 1064 streamconverter.write(job_processing, pes_packet, streamdemultiplexer, job_processing.getCutByteposition(), CommonParsing.isInfoScan(), CutpointList); 1065 1066 } while (isZeroPacket); 1067 1068 1069 if (action != CommonParsing.ACTION_DEMUX) 1070 job_processing.setLastHeaderBytePosition(count); 1071 1072 /** 1073 * split size reached 1074 */ 1075 if (job_processing.getSplitSize() > 0 && job_processing.getSplitSize() < job_processing.getAllMediaFilesExportLength()) 1076 break loop; 1077 } 1078 1079 1080 if (job_processing.getSplitSize() > 0 && job_processing.getSplitSize() < job_processing.getAllMediaFilesExportLength()) 1081 break bigloop; 1082 1083 /** 1084 * next file segment 1085 */ 1086 if (job_processing.getFileNumber() < collection.getPrimaryInputFileSegments() - 1) 1087 { 1088 in.close(); 1089 //System.gc(); 1090 1091 if (collection.getSettings().getBooleanProperty(Keys.KEY_Input_concatenateForeignRecords) && action == CommonParsing.ACTION_DEMUX) 1092 { 1093 ptsoffset = nextFilePTS(collection, CommonParsing.PRIMARY_PES_PARSER, pes_streamtype, lastpts, job_processing.getFileNumber() + 1); 1094 1095 if (ptsoffset == -1) 1096 ptsoffset = 0; 1097 1098 else 1099 { 1100 for (int i = 0; i < demuxList.size(); i++) 1101 { 1102 streamdemultiplexer = (StreamDemultiplexer) demuxList.get(i); 1103 streamdemultiplexer.PTSOffset(ptsoffset); 1104 1105 if (streamdemultiplexer.getID() == pesID0) // ?? 1106 streamdemultiplexer.resetVideo(); 1107 } 1108 1109 job_processing.setSequenceHeader(true); 1110 job_processing.setNewVideoStream(true); 1111 // job_processing.addCellTime(String.valueOf(job_processing.getExportedVideoFrameNumber())); 1112 } 1113 } 1114 1115 XInputFile nextXInputFile = (XInputFile) collection.getInputFile(job_processing.countFileNumber(+1)); 1116 count = size; 1117 base = count; 1118 1119 size += nextXInputFile.length(); 1120 in = new PushbackInputStream(nextXInputFile.getInputStream(), 0x10010); 1121 1122 Common.setMessage(Resource.getString("parsePrimaryPES.actual.written") + " " + job_processing.getExportedVideoFrameNumber()); 1123 Common.setMessage(Resource.getString("parsePrimaryPES.switch") + " " + nextXInputFile + " (" + Common.formatNumber(nextXInputFile.length()) + " bytes) @ " + base); 1124 1125 Common.updateProgressBar((action == CommonParsing.ACTION_DEMUX ? Resource.getString("parsePrimaryPES.demuxing") : Resource.getString("parsePrimaryPES.converting")) + " " + Resource.getString("parsePrimaryPES.avpes.file") + " " + nextXInputFile.getName()); 1126 } 1127 1128 else 1129 break bigloop; 1130 1131 } 1132 1133 /** 1134 * file end reached for split 1135 */ 1136 if ( (count >= size || ende) && job_processing.getSplitSize() > 0 ) 1137 job_processing.setSplitLoopActive(false); 1138 1139 in.close(); 1140 1141 vptslog = processElementaryStreams(vptslog, action, clv, collection, job_processing); 1142 1143 } catch (IOException e2) { 1144 1145 Common.setExceptionMessage(e2); 1146 } 1147 1148 return vptslog; 1149 } 1150 } 1151