diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/ComponentType.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/ComponentType.java new file mode 100644 index 00000000..e64b781a --- /dev/null +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/ComponentType.java @@ -0,0 +1,51 @@ +/** + * + * http://www.digitalekabeltelevisie.nl/dvb_inspector + * + * This code is Copyright 2009-2024 by Eric Berendsen (e_berendsen@digitalekabeltelevisie.nl) + * + * This file is part of DVB Inspector. + * + * DVB Inspector is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DVB Inspector is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DVB Inspector. If not, see . + * + * The author requests that he be notified of any application, applet, or + * other binary that makes use of this code, but that's more out of curiosity + * than anything and is not required. + * + */ +package nl.digitalekabeltelevisie.data.mpeg; + +public enum ComponentType { + AC3("Dolby Audio (AC3)"), + E_AC3("Enhanced Dolby Audio (AC3)"), + VBI("VBI Data"), + TELETEXT("Teletext"), + DVB_SUBTITLING("DVB subtitling"), + AIT("Application Information Table (AIT)"), + RCT("Related Content Table (RCT)"), + T2MI("T2-MI"), + TTML("TTML subtitling"), + AC4("Dolby AC-4 Audio"), + SMPTE2038("SMPTE 2038"); + + private final String description; + + ComponentType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index cbe2226c..3ad0eeb5 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2023 by Eric Berendsen (e_berendsen@digitalekabeltelevisie.nl) + * This code is Copyright 2009-2024 by Eric Berendsen (e_berendsen@digitalekabeltelevisie.nl) * * This file is part of DVB Inspector. * @@ -78,34 +78,10 @@ /** - * TransportStream is responsible for parsing a file containing a transport stream, dividing it into 188 byte {@link TSPackets}, and handing them over to the correct PID. + * TransportStream is responsible for parsing a file containing a transport stream, dividing it into 188 byte TSPackets, and handing them over to the correct PID. * */ public class TransportStream implements TreeNode{ - - public enum ComponentType{ - AC3("Dolby Audio (AC3)"), - E_AC3("Enhanced Dolby Audio (AC3)"), - VBI("VBI Data"), - TELETEXT("Teletext"), - DVB_SUBTITLING("DVB subtitling"), - AIT("Application Information Table (AIT)"), - RCT("Related Content Table (RCT)"), - T2MI("T2-MI"), - TTML("TTML subtitling"), - AC4("Dolby AC-4 Audio"), - SMPTE2038("SMPTE 2038"); - - private final String description; - - ComponentType(String description){ - this.description = description; - } - - public String getDescription() { - return description; - } - } /** @@ -126,7 +102,7 @@ public String getDescription() { /** * File containing data of this TransportStream */ - private File file; + private final File file; /** * after reading a TSPAcket from the file, it is handed over to the respective PID for aggregating into larger PES or PSI sections, and further processing. */ @@ -135,15 +111,15 @@ public String getDescription() { * for every TSPacket read, store it's packet_id. Used for bit rate calculations, and Grid View */ private final short [] packet_pid; - private int [] packetATS = null; + private int [] packetATS; - private OffsetHelper offsetHelper = null; - private RollOverHelper rollOverHelper = null; + private OffsetHelper offsetHelper; + private RollOverHelper rollOverHelper; /** * Get value once at creation of TS, because getting it for every call to getAVCHDPacketTime is a bit expensive */ - private static boolean enabledHumaxAtsFix = false; + private boolean enabledHumaxAtsFix; /** * Starting point for all the PSI information in this TransportStream */ @@ -151,30 +127,30 @@ public String getDescription() { /** * how many TSPackets have bean read. */ - private int no_packets = 0; + private int no_packets; /** * number of TSPackets that had Transport Error Indicator set. */ - private int error_packets = 0; + private int error_packets; /** * Bitrate based on the average of all PIDs that contain a PCR. This is the most accurate way to calculate the bit rate. */ - private long bitRate = -1; + private long bitRate = -1L; /** * for streams that have no PIDS with PCRs (empty transport streams) this value is calculated based on the number of bytes between different occurences of the TDT table */ - private long bitRateTDT = -1; + private long bitRateTDT = -1L; /** * time at which this transportStream started. Calculated by calculating backwards from first TDT, using bitrate. null if no TDT found */ - private Calendar zeroTime = null; + private Calendar zeroTime; private final long len; /** * number of times sync was lost */ - private int sync_errors = 0; + private int sync_errors; private int packetLength = 188; @@ -186,7 +162,7 @@ public String getDescription() { * Creates a new Transport stream based on the supplied file. After construction the TransportStream is not complete, first parseStream() has to be called! * @param fileName name of the file to be read (null not permitted). */ - public TransportStream(final String fileName) throws NotAnMPEGFileException,IOException { + public TransportStream(String fileName) throws NotAnMPEGFileException,IOException { this(new File(fileName)); } @@ -196,7 +172,7 @@ public TransportStream(final String fileName) throws NotAnMPEGFileException,IOEx * @param file the file to be read (null not permitted). Don't enable TSPackets by default. */ - public TransportStream(final File file) throws NotAnMPEGFileException,IOException{ + public TransportStream(File file) throws NotAnMPEGFileException,IOException{ this.file = file; len = file.length(); packetLength = determinePacketLengthToUse(file); @@ -211,7 +187,7 @@ public TransportStream(final File file) throws NotAnMPEGFileException,IOExceptio } - private static int determinePacketLengthToUse(final File file) throws NotAnMPEGFileException, IOException { + private static int determinePacketLengthToUse(File file) throws NotAnMPEGFileException, IOException { int packetLengthModus = PreferencesManager.getPacketLengthModus(); if(packetLengthModus == 0) { // auto return determineActualPacketLength(file); @@ -224,12 +200,12 @@ private static int determinePacketLengthToUse(final File file) throws NotAnMPEGF * @param file * @return */ - private static int determineActualPacketLength(final File file) throws NotAnMPEGFileException,IOException{ - if(file.length()< 752) { + private static int determineActualPacketLength(File file) throws NotAnMPEGFileException,IOException{ + if(file.length() < 752L) { throw new NotAnMPEGFileException("File too short to determine packet length automatic. File should have at least 5 consecutive packets.\n\nTry setting packet length manual."); } - try(final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ - for(final int possiblePacketLength:ALLOWED_PACKET_LENGTHS){ + try(RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ + for(int possiblePacketLength:ALLOWED_PACKET_LENGTHS){ logger.log(Level.INFO, "Trying for packetLength {0}",possiblePacketLength); if(usesPacketLength(possiblePacketLength, randomAccessFile)){ @@ -238,9 +214,14 @@ private static int determineActualPacketLength(final File file) throws NotAnMPEG } } } - throw new NotAnMPEGFileException("DVB Inspector could not determine packetsize for this file. \n" + - "DVB Inspector supports packet sizes of 188, 192, 204 and 208 bytes.\n\n " + - "Are you sure this file contains a valid MPEG Transport Stream?\n\n "); + throw new NotAnMPEGFileException(""" + DVB Inspector could not determine packetsize for this file.\s + DVB Inspector supports packet sizes of 188, 192, 204 and 208 bytes. + + \ + Are you sure this file contains a valid MPEG Transport Stream? + + \s"""); } /** @@ -249,7 +230,7 @@ private static int determineActualPacketLength(final File file) throws NotAnMPEG * @return * @throws IOException */ - private static boolean usesPacketLength(final int possiblePacketLength, final RandomAccessFile randomAccessFile) throws IOException { + private static boolean usesPacketLength(int possiblePacketLength, RandomAccessFile randomAccessFile) throws IOException { int startPos = 0; do{ logger.log(Level.INFO, "starting at position {0}",startPos); @@ -263,9 +244,9 @@ private static boolean usesPacketLength(final int possiblePacketLength, final Ra // found a sync byte, try to find next 4 sync bytes boolean seqFound = true; for (int i = 1; (i < CONSECUTIVE_PACKETS) && seqFound; i++) { - randomAccessFile.seek((long)startPos + (i * possiblePacketLength)); + randomAccessFile.seek(startPos + ((long)i * possiblePacketLength)); logger.log(Level.INFO, "found {0} sequence syncs at pos {1}",new Object[]{i,startPos + (i * possiblePacketLength)}); - seqFound &= (randomAccessFile.read() == sync_byte); + seqFound = (randomAccessFile.read() == sync_byte); } if(seqFound){ return true; @@ -279,15 +260,15 @@ private static boolean usesPacketLength(final int possiblePacketLength, final Ra * read the file, and parse it. Packets are counted, bitrate calculated, etc. Used for initial construction. PES data is not analyzed. * @throws IOException */ - public void parseStream(final java.awt.Component component) throws IOException { + public void parseStream(java.awt.Component component) throws IOException { try (PositionPushbackInputStream fileStream = getInputStream(component)) { no_packets = 0; pids = new PID[MAX_PIDS]; psi = new PSI(); error_packets = 0; - bitRate = -1; - bitRateTDT = -1; + bitRate = -1L; + bitRateTDT = -1L; if(isAVCHD()) { readAVCHDPackets(fileStream); @@ -302,13 +283,13 @@ private void readPackets(PositionPushbackInputStream fileStream) throws IOExcept int count = 0; int bytes_read = 0; int lastHandledSyncErrorPacket = -1; - final byte[] buf = new byte[packetLength]; + byte[] buf = new byte[packetLength]; do { - final long offset = fileStream.getPosition(); + long offset = fileStream.getPosition(); bytes_read = fileStream.read(buf, 0, packetLength); - final int next = fileStream.read(); - if ((bytes_read == packetLength) && (buf[0] == MPEGConstants.sync_byte) - && ((next == -1) || (next == MPEGConstants.sync_byte))) { + int next = fileStream.read(); + if ((bytes_read == packetLength) && (buf[0] == sync_byte) + && ((next == -1) || (next == sync_byte))) { // always push back first byte of next packet if ((next != -1)) { fileStream.unread(next); @@ -337,24 +318,24 @@ private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOE int count = 0; int bytes_read = 0; int lastHandledSyncErrorPacket = -1; - final byte[] buf = new byte[AVCHD_PACKET_LENGTH]; + byte[] buf = new byte[AVCHD_PACKET_LENGTH]; int lastArrivalTimeStamp = Integer.MAX_VALUE; long currentRollOver = -1L; do { - final long offset = fileStream.getPosition(); + long offset = fileStream.getPosition(); bytes_read = fileStream.read(buf, 0, AVCHD_PACKET_LENGTH); - final byte[] nextBytes =new byte[5]; - final int next = fileStream.read(nextBytes,0,5); - if ((bytes_read == packetLength) && (buf[4] == MPEGConstants.sync_byte) - && ((next != 5) || (nextBytes[4] == MPEGConstants.sync_byte))) { + byte[] nextBytes =new byte[5]; + int next = fileStream.read(nextBytes,0,5); + if ((bytes_read == packetLength) && (buf[4] == sync_byte) + && ((next != 5) || (nextBytes[4] == sync_byte))) { // always push back first byte of next packet if ((next != -1)) { fileStream.unread(nextBytes,0,next); } offsetHelper.addPacket(no_packets, offset); - final AVCHDPacket packet = new AVCHDPacket(buf, count, this); - final int arrivalTimestamp = packet.getArrivalTimestamp(); + AVCHDPacket packet = new AVCHDPacket(buf, count, this); + int arrivalTimestamp = packet.getArrivalTimestamp(); if (arrivalTimestamp < lastArrivalTimeStamp) { currentRollOver++; rollOverHelper.addPacket(count, currentRollOver); @@ -389,8 +370,7 @@ public void postProcess() { } private void processPacket(TSPacket packet) { - assert(no_packets == packet.packetNo); - final short pid = packet.getPID(); + short pid = packet.getPID(); packet_pid[no_packets]=addPIDFlags(packet, pid); no_packets++; if(pids[pid]==null) { @@ -403,7 +383,7 @@ private void processPacket(TSPacket packet) { } } - private static short addPIDFlags(TSPacket packet, final short pid) { + private static short addPIDFlags(TSPacket packet, short pid) { short pidFlags = pid; if(packet.hasAdaptationField()){ pidFlags = (short) (pidFlags | ADAPTATION_FIELD_FLAG); @@ -423,15 +403,15 @@ private static short addPIDFlags(TSPacket packet, final short pid) { * @param toParsePids Map with an entry for each PID that should be parsed, and a handler that knows how to interpret the data * @throws IOException */ - public void parsePidStreams(final Map toParsePids) throws IOException { + public void parsePidStreams(Map toParsePids) throws IOException { if((toParsePids==null)||(toParsePids.isEmpty())){ return; } - try (final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ + try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ for(int t=0; t toParsePids) th } - private PositionPushbackInputStream getInputStream(final java.awt.Component component) throws IOException{ - final InputStream is = new FileInputStream(file); - final long expectedSize=file.length(); + private PositionPushbackInputStream getInputStream(java.awt.Component component) throws IOException{ + InputStream is = new FileInputStream(file); + long expectedSize=file.length(); if(component==null){ return new PositionPushbackInputStream(new BufferedInputStream(is),300); } @@ -458,13 +438,13 @@ private PositionPushbackInputStream getInputStream(final java.awt.Component comp @Override public String toString() { - final StringBuilder buf = new StringBuilder(); + StringBuilder buf = new StringBuilder(); buf.append("Transportstream :").append(file.getName()).append('\n'); for (int i = 0; i < pids.length; i++) { - final PID pid = pids[i]; + PID pid = pids[i]; if(pid!=null) { - buf.append(" PID :").append(i).append(", ").append(pid.toString()).append(" packets, ").append((pid.getPackets() * 100) / no_packets).append("%, duplicate packets:").append(pid.getDup_packets()).append("\n"); + buf.append(" PID :").append(i).append(", ").append(pid).append(" packets, ").append((pid.getPackets() * 100) / no_packets).append("%, duplicate packets:").append(pid.getDup_packets()).append("\n"); } } @@ -476,10 +456,6 @@ public File getFile() { return file; } - public void setFile(final File file) { - this.file = file; - } - /** * @return the number of TSPackets read */ @@ -495,11 +471,11 @@ public PSI getPsi() { return psi; } - public DefaultMutableTreeNode getJTreeNode(final int modus){ + public DefaultMutableTreeNode getJTreeNode(int modus){ - final KVP tsKvp = new KVP("Transport Stream "+psi.getPat().getTransportStreamId()); + KVP tsKvp = new KVP("Transport Stream "+psi.getPat().getTransportStreamId()); tsKvp.setCrumb("root"); - final DefaultMutableTreeNode t = new DefaultMutableTreeNode(tsKvp); + DefaultMutableTreeNode t = new DefaultMutableTreeNode(tsKvp); t.add(new DefaultMutableTreeNode(new KVP("file",file.getPath(),null))); t.add(new DefaultMutableTreeNode(new KVP("size",file.length(),null))); @@ -508,34 +484,34 @@ public DefaultMutableTreeNode getJTreeNode(final int modus){ t.add(new DefaultMutableTreeNode(new KVP("packet size",packetLength,PreferencesManager.getPacketLengthModus()==0?"(detected)":"(forced)"))); t.add(new DefaultMutableTreeNode(new KVP("Error packets",error_packets,null))); t.add(new DefaultMutableTreeNode(new KVP("Sync Errors",sync_errors,null))); - if(bitRate!=-1){ + if(bitRate!= -1L){ t.add(new DefaultMutableTreeNode(new KVP("bitrate",bitRate,null))); - t.add(new DefaultMutableTreeNode(new KVP("length (secs)",(file.length()*8)/bitRate,null))); + t.add(new DefaultMutableTreeNode(new KVP("length (secs)",(file.length()* 8L)/bitRate,null))); } - if(bitRateTDT!=-1){ + if(bitRateTDT!= -1L){ t.add(new DefaultMutableTreeNode(new KVP("bitrate based on TDT",bitRateTDT,null))); - t.add(new DefaultMutableTreeNode(new KVP("length (secs)",(file.length()*8)/bitRateTDT,null))); + t.add(new DefaultMutableTreeNode(new KVP("length (secs)",(file.length()* 8L)/bitRateTDT,null))); } t.add(psi.getJTreeNode(modus)); if(!psiOnlyModus(modus)){ KVP kvp = new KVP("PIDs"); kvp.addTableSource(this::getTableModel,"PIDs"); - final DefaultMutableTreeNode pidTreeNode = new DefaultMutableTreeNode(kvp); + DefaultMutableTreeNode pidTreeNode = new DefaultMutableTreeNode(kvp); t.add(pidTreeNode); - for (final PID pid : pids) { + for (PID pid : pids) { if((pid)!=null){ pidTreeNode.add(pid.getJTreeNode(modus)); } } // TSPackets - if(getNo_packets()!=0) { - final JTreeLazyList list = new JTreeLazyList(new TSPacketGetter(this,modus)); - t.add(list.getJTreeNode(modus, "Transport packets ")); - }else { - t.add(new DefaultMutableTreeNode(new KVP("Transport packets "))); - } + if (no_packets == 0) { + t.add(new DefaultMutableTreeNode(new KVP("Transport packets "))); + } else { + JTreeLazyList list = new JTreeLazyList(new TSPacketGetter(this, modus)); + t.add(list.getJTreeNode(modus, "Transport packets ")); + } } return t; @@ -566,7 +542,7 @@ public TableModel getTableModel() { return tableModel; } - private void setLabelMakerBase(final int pidNo, final String base) + private void setLabelMakerBase(int pidNo, String base) { if(pids[pidNo]!=null){ pids[pidNo].getLabelMaker().setBase(base); @@ -574,7 +550,7 @@ private void setLabelMakerBase(final int pidNo, final String base) } - private void addLabelMakerComponent(final int pidNo, final String type, final String serviceName) + private void addLabelMakerComponent(int pidNo, String type, String serviceName) { if(pids[pidNo]!=null){ pids[pidNo].getLabelMaker().addComponent(type, serviceName); @@ -588,7 +564,7 @@ private void addLabelMakerComponent(final int pidNo, final String type, final St * @param pid * @return */ - private static String getFixedLabel(final short pid){ + private static String getFixedLabel(short pid){ switch (pid) { case 0: return "PAT"; @@ -647,17 +623,17 @@ private void namePIDs() { // now the streams referenced from the CAT if(pids[1]!=null){ - for(CADescriptor caDescriptor:findGenericDescriptorsInList(getPsi().getCat().getDescriptorList(), CADescriptor.class)){ - addLabelMakerComponent(caDescriptor.getCaPID(), "EMM", "CA_ID:"+ caDescriptor.getCaSystemID()+ " ("+Utils.getCASystemIDString(caDescriptor.getCaSystemID())+")"); + for(CADescriptor caDescriptor:findGenericDescriptorsInList(psi.getCat().getDescriptorList(), CADescriptor.class)){ + addLabelMakerComponent(caDescriptor.getCaPID(), "EMM", "CA_ID:"+ caDescriptor.getCaSystemID()+ " ("+ getCASystemIDString(caDescriptor.getCaSystemID())+")"); } } // now all services, starting with PMTs themselves, then referenced ES - for(final PMTsection[] pmt:getPsi().getPmts()){ + for(PMTsection[] pmt: psi.getPmts()){ PMTsection pmtSection = pmt[0]; while(pmtSection!=null){ - final int service_id=pmtSection.getProgramNumber(); - String service_name = getPsi().getSdt().getServiceNameForActualTransportStreamOptional(service_id).orElse("Service "+service_id); + int service_id=pmtSection.getProgramNumber(); + String service_name = psi.getSdt().getServiceNameForActualTransportStreamOptional(service_id).orElse("Service "+service_id); labelPmtForProgram(pmtSection, service_name); labelEcmForProgram(pmtSection, service_name); @@ -679,9 +655,9 @@ private void namePIDs() { private void setGeneralPsiTableHandlers() { if(PreferencesManager.isEnableGenericPSI()) { - for (final PID pid : pids) { + for (PID pid : pids) { if((pid!=null)&&(pid.getType()==PID.PSI)) { - final GeneralPSITable psiData = pid.getPsi(); + GeneralPSITable psiData = pid.getPsi(); if (((!psiData.getLongSections().isEmpty())|| (!psiData.getSimpleSectionsd().isEmpty())) && pid.getPidHandler()==null) { GeneralPsiTableHandler generalPsiTableHandler = new GeneralPsiTableHandler(); @@ -699,7 +675,7 @@ private void setGeneralPsiTableHandlers() { */ private void labelM7FastscanTables() { - M7Fastscan fastScan = getPsi().getM7fastscan(); + M7Fastscan fastScan = psi.getM7fastscan(); labelM7FastscanONT(fastScan); labelM7FastscanFstFnt(fastScan); } @@ -709,20 +685,20 @@ private void labelM7FastscanFstFnt(M7Fastscan fastScan) { for (Integer operatorId : new TreeSet<>(operators.keySet())) { Map operatorsInPid = operators.get(operatorId); for (Integer pid : new TreeSet<>(operatorsInPid.keySet())) { - String name = "M7 FastScan operator "+fastScan.getOperatorName(operatorId); + StringBuilder name = new StringBuilder("M7 FastScan operator ").append(fastScan.getOperatorName(operatorId)); OperatorFastscan operatorFastscan = operatorsInPid.get(pid); if(operatorFastscan.getOperatorSubListName()!=null) { - name += " " + operatorFastscan.getOperatorSubListName(); + name.append(" ").append(operatorFastscan.getOperatorSubListName()); } if(operatorFastscan.getFntSections() != null){ - name += " FNT"; + name.append(" FNT"); } if(operatorFastscan.getFstSections() != null){ - name += " FST"; + name.append(" FST"); } if(pids[pid]!=null){ - pids[pid].getLabelMaker().setBase(name); + pids[pid].getLabelMaker().setBase(name.toString()); } } } @@ -730,7 +706,7 @@ private void labelM7FastscanFstFnt(M7Fastscan fastScan) { private static void labelM7FastscanONT(M7Fastscan fastScan) { ONTSection[] sections = fastScan.getOntSections(); - if((sections != null) && (sections.length >0)) { + if(sections != null) { for(ONTSection section:sections) { if(section != null) { section.getParentPID().getLabelMaker().setBase("M7 FastScan ONT"); @@ -752,7 +728,7 @@ private void labelEcmForProgram(PMTsection pmtSection, String service_name) { } private void labelPcrForProgram(PMTsection pmtSection, String service_name) { - final int PCR_pid = pmtSection.getPcrPid(); + int PCR_pid = pmtSection.getPcrPid(); boolean pcrInComponent = false; for(Component component:pmtSection.getComponentenList()) { if (PCR_pid == component.getElementaryPID()) { @@ -768,7 +744,7 @@ private void labelPcrForProgram(PMTsection pmtSection, String service_name) { private void labelComponentsForProgram(PMTsection pmtSection, String service_name) { for(Component component:pmtSection.getComponentenList()) { - final int streamType = component.getStreamtype(); + int streamType = component.getStreamtype(); GeneralPidHandler generalPidHandler = determinePesHandlerByStreamType(component,streamType); Optional componentType = determineComponentType(component.getComponentDescriptorList()); @@ -783,10 +759,7 @@ private void labelComponentsForProgram(PMTsection pmtSection, String service_nam case DVB_SUBTITLING: generalPidHandler = new DVBSubtitleHandler(); break; - case TELETEXT: - generalPidHandler = new EBUTeletextHandler(); - break; - case VBI: + case TELETEXT, VBI: generalPidHandler = new EBUTeletextHandler(); break; case AC3: @@ -798,11 +771,9 @@ private void labelComponentsForProgram(PMTsection pmtSection, String service_nam case E_AC3: generalPidHandler = new EAC3Handler(); break; - case AIT: - break; - case RCT: + case AIT, RCT: break; - case T2MI: + case T2MI: generalPidHandler = new T2miPidHandler(); break; case TTML: @@ -816,14 +787,14 @@ private void labelComponentsForProgram(PMTsection pmtSection, String service_nam } } - final PID pid = pids[component.getElementaryPID()]; + PID pid = pids[component.getElementaryPID()]; if (pid!=null && generalPidHandler!=null) { generalPidHandler.setTransportStream(this); generalPidHandler.setPID(pid); pid.setPidHandler(generalPidHandler); } - final List caDescriptorList =findGenericDescriptorsInList(component.getComponentDescriptorList(), CADescriptor.class); + List caDescriptorList =findGenericDescriptorsInList(component.getComponentDescriptorList(), CADescriptor.class); for(CADescriptor cad: caDescriptorList) { addLabelMakerComponent(cad.getCaPID(), "ECM", "CA_ID:"+ cad.getCaSystemID()+ " ("+service_name+")"); @@ -837,76 +808,70 @@ public static Optional determineComponentType(List co private static ComponentType findComponentType(List componentDescriptorList) { - for(Descriptor d:componentDescriptorList){ - if(d instanceof SubtitlingDescriptor) { - return ComponentType.DVB_SUBTITLING; - }else if(d instanceof TeletextDescriptor) { - return ComponentType.TELETEXT; - }else if(d instanceof VBIDataDescriptor) { - return ComponentType.VBI; - }else if(d instanceof AC3Descriptor){ - return ComponentType.AC3; - }else if(d instanceof AC4Descriptor){ - return ComponentType.AC4; - }else if(d instanceof RegistrationDescriptor registrationDescriptor){ - byte[] formatIdentifier = registrationDescriptor.getFormatIdentifier(); - if (Arrays.equals(formatIdentifier, RegistrationDescriptor.AC_3)) { + for(Descriptor descriptor:componentDescriptorList){ + switch (descriptor) { + case SubtitlingDescriptor ignored: + return ComponentType.DVB_SUBTITLING; + case TeletextDescriptor ignored: + return ComponentType.TELETEXT; + case VBIDataDescriptor ignored: + return ComponentType.VBI; + case AC3Descriptor ignored: return ComponentType.AC3; - } - if (Arrays.equals(formatIdentifier, RegistrationDescriptor.SMPTE_2038)) { - return ComponentType.SMPTE2038; - } - }else if(d instanceof EnhancedAC3Descriptor){ - return ComponentType.E_AC3; - }else if(d instanceof ApplicationSignallingDescriptor){ - return ComponentType.AIT; - }else if(d instanceof RelatedContentDescriptor){ - return ComponentType.RCT; - }else if(d instanceof T2MIDescriptor){ - return ComponentType.T2MI; - }else if(d instanceof TtmlSubtitlingDescriptor){ - return ComponentType.TTML; + case AC4Descriptor ignored: + return ComponentType.AC4; + case RegistrationDescriptor registrationDescriptor: + byte[] formatIdentifier = registrationDescriptor.getFormatIdentifier(); + if (Arrays.equals(formatIdentifier, RegistrationDescriptor.AC_3)) { + return ComponentType.AC3; + } + if (Arrays.equals(formatIdentifier, RegistrationDescriptor.SMPTE_2038)) { + return ComponentType.SMPTE2038; + } + break; + case EnhancedAC3Descriptor ignored: + return ComponentType.E_AC3; + case ApplicationSignallingDescriptor ignored: + return ComponentType.AIT; + case RelatedContentDescriptor ignored: + return ComponentType.RCT; + case T2MIDescriptor ignored: + return ComponentType.T2MI; + case TtmlSubtitlingDescriptor ignored: + return ComponentType.TTML; + default: } } return null; } - private GeneralPidHandler determinePesHandlerByStreamType(final Component component, - final int streamType) { - int comp_pid = component.getElementaryPID(); - GeneralPidHandler abstractPidHandler = null; - if((pids[comp_pid]!=null)&&(!pids[comp_pid].isScrambled())&&(pids[comp_pid].getType()==PID.PES)){ - if((streamType==1)||(streamType==2)){ - abstractPidHandler = new Video138182Handler(); - }else if((streamType==3)||(streamType==4)){ - abstractPidHandler = new Audio138183Handler(getAncillaryDataIdentifier(component)); - }else if(streamType==0x11){ - abstractPidHandler = new Audio144963Handler(); - }else if(streamType==0x1B){ - abstractPidHandler = new Video14496Handler(); - }else if(streamType==0x20){ //MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 - abstractPidHandler = new Video14496Handler(); - }else if(streamType==0x24){ - abstractPidHandler = new H265Handler(); - }else if(streamType==0x33){ - abstractPidHandler = new H266Handler(); - }else if(streamType==0x32){ - abstractPidHandler = new JpegXsHandler(); - }else{ - abstractPidHandler = new GeneralPesHandler(); - } + private GeneralPidHandler determinePesHandlerByStreamType(Component component, + int streamType) { + int componentElementaryPID = component.getElementaryPID(); + PID pid = pids[componentElementaryPID]; + if ((pid != null) && (!pid.isScrambled()) && (pid.getType() == PID.PES)){ + return switch(streamType){ + case 1,2 -> new Video138182Handler(); + case 3,4 -> new Audio138183Handler(getAncillaryDataIdentifier(component)); + case 0x11 -> new Audio144963Handler(); + case 0x1B -> new Video14496Handler(); + case 0x20 -> new Video14496Handler(); //MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 + case 0x24 -> new H265Handler(); + case 0x33 -> new H266Handler(); + case 0x32 -> new JpegXsHandler(); + default -> new GeneralPesHandler(); + }; } - return abstractPidHandler; + return null; } - private static int getAncillaryDataIdentifier(final Component component) { - int ancillaryData = 0; - final List ancillaryDataDescriptors = findGenericDescriptorsInList(component.getComponentDescriptorList(), AncillaryDataDescriptor.class); + private static int getAncillaryDataIdentifier(Component component) { + List ancillaryDataDescriptors = findGenericDescriptorsInList(component.getComponentDescriptorList(), AncillaryDataDescriptor.class); if(!ancillaryDataDescriptors.isEmpty()){ - ancillaryData = ancillaryDataDescriptors.get(0).getAncillaryDataIdentifier(); + return ancillaryDataDescriptors.getFirst().getAncillaryDataIdentifier(); } - return ancillaryData; + return 0; } @@ -920,31 +885,31 @@ private void calculateBitRate() { int teller=0; long totBitrate= 0L; - for(final PID pid:pids){ - if((pid!=null)&&(pid.getBitRate()!=-1)){ + for (PID pid : pids) { + if ((pid != null) && (pid.getBitRate() != -1L)) { teller++; - totBitrate+=pid.getBitRate(); + totBitrate += pid.getBitRate(); } } - if(teller!=0){ + if (teller != 0) { bitRate = totBitrate / teller; } } private void calculateBitrateTDT() { // calculate bitrate based on TDT sections. Need at least 2 - if(getPsi().getTdt()!=null){ - final List tdtSectionList = getPsi().getTdt().getTdtSectionList(); + if(psi.getTdt()!=null){ + List tdtSectionList = psi.getTdt().getTdtSectionList(); if(tdtSectionList.size()>=2){ - final TDTsection first = tdtSectionList.get(0); - final TDTsection last = tdtSectionList.get(tdtSectionList.size()-1); - final long diffPacket = (long)last.getPacket_no() - first.getPacket_no(); - final Calendar utcCalenderLast = getUTCCalender(last.getUTC_time()); - final Calendar utcCalenderFirst = getUTCCalender(first.getUTC_time()); + TDTsection first = tdtSectionList.getFirst(); + TDTsection last = tdtSectionList.getLast(); + long diffPacket = (long)last.getPacket_no() - first.getPacket_no(); + Calendar utcCalenderLast = getUTCCalender(last.getUTC_time()); + Calendar utcCalenderFirst = getUTCCalender(first.getUTC_time()); // getUTCCalender might fail if not correct BCD, then will return null. if((utcCalenderLast!=null)&&(utcCalenderFirst!=null)){ - final long timeDiffMills = utcCalenderLast.getTimeInMillis()- utcCalenderFirst.getTimeInMillis(); - if(timeDiffMills>0){ // shit happens... capture.guangdong has 10 with same timestamp.... + long timeDiffMills = utcCalenderLast.getTimeInMillis()- utcCalenderFirst.getTimeInMillis(); + if(timeDiffMills> 0L){ // shit happens... capture.guangdong has 10 with same timestamp.... bitRateTDT = (diffPacket * packetLength * 8 * 1000)/timeDiffMills; } } @@ -953,14 +918,14 @@ private void calculateBitrateTDT() { } private void calculateZeroTime() { - if((getPsi().getTdt()!=null)&&(getBitRate()!=-1)){ - final List tdtSectionList = getPsi().getTdt().getTdtSectionList(); - if(!tdtSectionList.isEmpty()){ - final TDTsection first = tdtSectionList.get(0); - final Calendar firstTime = getUTCCalender(first.getUTC_time()); - if(firstTime!=null){ - final long millsIntoStream= (first.getPacket_no() *packetLength * 8 * 1000)/getBitRate(); - firstTime.add(Calendar.MILLISECOND, (int)-millsIntoStream); + if ((psi.getTdt() != null) && (getBitRate() != -1L)) { + List tdtSectionList = psi.getTdt().getTdtSectionList(); + if (!tdtSectionList.isEmpty()) { + TDTsection first = tdtSectionList.getFirst(); + Calendar firstTime = getUTCCalender(first.getUTC_time()); + if (firstTime != null) { + long millsIntoStream = ((long) first.getPacket_no() * packetLength * 8 * 1000) / getBitRate(); + firstTime.add(Calendar.MILLISECOND, (int) -millsIntoStream); zeroTime = firstTime; } } @@ -978,7 +943,7 @@ public int getNoPIDS() { int t=0; - for(final PID pid:pids){ + for(PID pid:pids){ if(pid!=null){ t++; } @@ -987,8 +952,8 @@ public int getNoPIDS() } public short [] getUsedPids(){ - final int no = getNoPIDS(); - final short[] r = new short[no]; + int no = getNoPIDS(); + short[] r = new short[no]; int i = 0; for (short pid = 0; pid < MAX_PIDS; pid++) { if (pids[pid] != null) { @@ -998,16 +963,16 @@ public int getNoPIDS() return r; } - public short getPacket_pid(final int t) { + public short getPacket_pid(int t) { return (short) (0x1fff & packet_pid[t]); } - public short getPacketPidFlags(final int t) { + public short getPacketPidFlags(int t) { return packet_pid[t]; } - public String getShortLabel(final short pid){ + public String getShortLabel(short pid){ if(pids[pid]!=null){ return pids[pid].getLabelMaker().toString(); } @@ -1018,104 +983,103 @@ public String getShortLabel(final short pid){ * @return the bitrate based on PCRs if available, else bitrate based on TDTs (if available). -1 if we have no idea what the bitrate could be. */ public long getBitRate() { - if(bitRate!=-1){ + if(bitRate!= -1L){ return bitRate; - }else if(bitRateTDT!=-1){ + }else if(bitRateTDT!= -1L){ return bitRateTDT; } - return -1; + return -1L; } /** * @return the length of the stream in seconds, based on PCRs bitrate if available, else based on bitrate based on TDTs (if available). -1 if we have no idea what the length could be. */ public double getLength(){ - if(bitRate!=-1){ + if(bitRate!= -1L){ return ((double)file.length()*8)/bitRate; - }else if(bitRateTDT!=-1){ + }else if(bitRateTDT!= -1L){ return ((double)file.length()*8)/bitRateTDT; }else{ - return -1; + return -1.0; } } - public String getPacketTime(final int packetNo){ - String r = null; + public String getPacketTime(int packetNo){ if(isAVCHD()) { - return Utils.printPCRTime(getAVCHDPacketTime(packetNo)); + return printPCRTime(getAVCHDPacketTime(packetNo)); } - if(getBitRate()!=-1){ //can't calculate time without a bitrate - if(zeroTime==null){ - final Calendar now=new GregorianCalendar(); - now.setTimeZone(java.util.TimeZone.getTimeZone("GMT")); - now.setTimeInMillis(0); - now.add(Calendar.MILLISECOND, (int)((packetNo * packetLength * 8 * 1000)/getBitRate())); - // return only the hours/min,secs and millisecs. Not TS recording will last days - r = getFormattedTime(now); + if (getBitRate() == -1L) { // no bitrate, return packet number + return packetNo + " (packetNo)"; + } + if (zeroTime == null) { + Calendar calendar = new GregorianCalendar(); + calendar.setTimeZone(TimeZone.getTimeZone("GMT")); + calendar.setTimeInMillis(0L); + calendar.add(Calendar.MILLISECOND, getTimeFromStartInMilliSecs(packetNo)); + // return only the hours/min,secs and millisecs. Not TS recording will last days + return getFormattedTime(calendar); + } + Calendar calendar = (Calendar) zeroTime.clone(); + // calculation in long, intermediate results can be > Integer.MAX_VALUE - }else{ - final Calendar now=(Calendar)zeroTime.clone(); - now.add(Calendar.MILLISECOND, (int)((packetNo * packetLength * 8 * 1000)/getBitRate())); + calendar.add(Calendar.MILLISECOND, getTimeFromStartInMilliSecs( packetNo)); + return getFormattedDateTime(calendar); + } - r = getFormattedDate(now)+ " "+getFormattedTime(now); - } - }else{ // no bitrate, return packet number - r = packetNo +" (packetNo)"; - } - return r; + private int getTimeFromStartInMilliSecs(int packetNo) { + return (int) (((long) packetNo * packetLength * 8 * 1000) / getBitRate()); } - private static String getFormattedDate(final Calendar now) { - StringBuilder sb = new StringBuilder(); - sb.append(now.get(Calendar.YEAR)).append("/"). - append(now.get(Calendar.MONTH)+1).append("/"). - append(now.get(Calendar.DAY_OF_MONTH)); - return sb.toString(); + private static String getFormattedDateTime(Calendar calendar) { + return(String.format("%1$tY/%1$tm/%1$td %1$tHh%1$tMm%1$tS:%1$tL", calendar)); } - private static String getFormattedTime(final Calendar now) { - StringBuilder sb = new StringBuilder(); - - sb.append(df2pos.format(now.get(Calendar.HOUR_OF_DAY))).append("h"). - append(df2pos.format(now.get(Calendar.MINUTE))).append("m"). - append(df2pos.format(now.get(Calendar.SECOND))).append(":"). - append(df3pos.format(now.get(Calendar.MILLISECOND))); - return sb.toString(); + private static String getFormattedTime(Calendar calendar) { + + return(String.format("%1$tHh%1$tMm%1$tS:%1$tL", calendar)); } - public String getShortPacketTime(final long packetNo){ + /** + * TODO the parameter packetNoOrPCR has two different meaning, because BitRateChat and TimeStampChart use different X-axis for aVCHD/DVB Full stream + * This should be fixed somewhere else ??? + * @param packetNoOrPCR when stream is a AVCHD stream, this is time in PCR ticks, otherwise this is packetNo (which will be converted into time. + * packetNo is always in range int, pcr value is long. + * @return + */ + public String getShortPacketTime(long packetNoOrPCR){ if(isAVCHD()) { - return Utils.printPCRTime(packetNo); + return printPCRTime(packetNoOrPCR); } if(getBitRate()!=-1){ //can't calculate time without a bitrate - Calendar now; + Calendar calendar; if(zeroTime==null){ - now = new GregorianCalendar(); - now.setTimeZone(java.util.TimeZone.getTimeZone("GMT")); - now.setTimeInMillis(0); + calendar = new GregorianCalendar(); + calendar.setTimeZone(TimeZone.getTimeZone("GMT")); + calendar.setTimeInMillis(0); }else{ - now = (Calendar)zeroTime.clone(); + calendar = (Calendar)zeroTime.clone(); } - now.add(Calendar.MILLISECOND, (int)((packetNo * packetLength * 8 * 1000)/getBitRate())); - // return only the hours/min,secs and millisecs. Not TS recording will last days - return now.get(Calendar.HOUR_OF_DAY)+"h"+df2pos.format(now.get(Calendar.MINUTE))+"m"+df2pos.format(now.get(Calendar.SECOND))+":"+df3pos.format(now.get(Calendar.MILLISECOND)); + calendar.add(Calendar.MILLISECOND, getTimeFromStartInMilliSecs((int)packetNoOrPCR)); + // return only the hours/min,secs and millisecs. No TS recording will last days + + return getFormattedTime(calendar); } // no bitrate - return packetNo +" (packetNo)"; + return packetNoOrPCR +" (packetNo)"; } - public boolean isAVCHD() { + public final boolean isAVCHD() { return packetLength == AVCHD_PACKET_LENGTH; } - public PMTsection getPMTforPID(final int thisPID) { - final PMTs pmts = getPsi().getPmts(); - for (final PMTsection[] pmTsections : pmts) { - final PMTsection pmt = pmTsections[0]; - for(final Component component :pmt.getComponentenList()){ + public PMTsection getPMTforPID(int thisPID) { + PMTs pmts = psi.getPmts(); + for (PMTsection[] pmTsections : pmts) { + PMTsection pmt = pmTsections[0]; + for(Component component :pmt.getComponentenList()){ if(component.getElementaryPID()==thisPID){ return pmt; } @@ -1125,12 +1089,12 @@ public PMTsection getPMTforPID(final int thisPID) { } // TODO handle FileNotFoundException more elegant, show some msg in GUI - public TSPacket getTSPacket(final int packetNo){ + public TSPacket getTSPacket(int packetNo){ TSPacket packet = null; if(offsetHelper.getMaxPacket()>packetNo){ - try (final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ + try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")){ packet = readPacket(packetNo,randomAccessFile); - } catch (final IOException e) { + } catch (IOException e) { logger.warning("IOException:"+e); } }else{ @@ -1139,13 +1103,13 @@ public TSPacket getTSPacket(final int packetNo){ return packet; } - private TSPacket readPacket(final int packetNo, final RandomAccessFile randomAccessFile) + private TSPacket readPacket(int packetNo, RandomAccessFile randomAccessFile) throws IOException { TSPacket packet = null; - final long offset = offsetHelper.getOffset(packetNo); + long offset = offsetHelper.getOffset(packetNo); randomAccessFile.seek(offset); - final byte [] buf = new byte[packetLength]; - final int bytesRead = randomAccessFile.read(buf); + byte [] buf = new byte[packetLength]; + int bytesRead = randomAccessFile.read(buf); if(bytesRead==packetLength){ if(isAVCHD()) { packet = new AVCHDPacket(buf, packetNo,this); @@ -1191,7 +1155,7 @@ private static int fixHumaxAts(int ats) { return base * 300 + extension; } - public PID getPID(final int p){ + public PID getPID(int p){ return pids[p]; } @@ -1207,38 +1171,30 @@ public int getSync_errors() { return sync_errors; } - public void setSync_errors(int sync_errors) { - this.sync_errors = sync_errors; - } - public int getError_packets() { return error_packets; } - public void setError_packets(int error_packets) { - this.error_packets = error_packets; - } - /** * @return */ List getLinkageDescriptorsFromNitNetworkLoop() { - final NIT nit = getPsi().getNit(); - final int actualNetworkID = nit.getActualNetworkID(); - final List descriptors = nit.getNetworkDescriptors(actualNetworkID); - return Descriptor.findGenericDescriptorsInList(descriptors, LinkageDescriptor.class); + NIT nit = psi.getNit(); + int actualNetworkID = nit.getActualNetworkID(); + List descriptors = nit.getNetworkDescriptors(actualNetworkID); + return findGenericDescriptorsInList(descriptors, LinkageDescriptor.class); } public boolean isONTSection(int pid) { - final NIT nit = getPsi().getNit(); - final int actualNetworkID = nit.getActualNetworkID(); - final List linkageDescriptors = getLinkageDescriptorsFromNitNetworkLoop(); + NIT nit = psi.getNit(); + int actualNetworkID = nit.getActualNetworkID(); + List linkageDescriptors = getLinkageDescriptorsFromNitNetworkLoop(); int streamID = getStreamID(); - final int originalNetworkID = nit.getOriginalNetworkID(actualNetworkID, streamID); + int originalNetworkID = nit.getOriginalNetworkID(actualNetworkID, streamID); - for (final LinkageDescriptor ld : linkageDescriptors) { + for (LinkageDescriptor ld : linkageDescriptors) { if (ld.getLinkageType() == 0x8D && ld.getTransportStreamId() == streamID && ld.getOriginalNetworkId() == originalNetworkID diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/PMTs.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/PMTs.java index 1a749ab6..28495fd7 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/PMTs.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/PMTs.java @@ -48,8 +48,8 @@ import javax.swing.tree.DefaultMutableTreeNode; import nl.digitalekabeltelevisie.controller.KVP; +import nl.digitalekabeltelevisie.data.mpeg.ComponentType; import nl.digitalekabeltelevisie.data.mpeg.PSI; -import nl.digitalekabeltelevisie.data.mpeg.TransportStream.ComponentType; import nl.digitalekabeltelevisie.data.mpeg.descriptors.ApplicationSignallingDescriptor; import nl.digitalekabeltelevisie.data.mpeg.descriptors.ISO639LanguageDescriptor; import nl.digitalekabeltelevisie.data.mpeg.descriptors.StreamIdentifierDescriptor; @@ -65,49 +65,49 @@ public class PMTs extends AbstractPSITabel implements Iterable{ - public PMTs(final PSI parentPSI) { + public PMTs(PSI parentPSI) { super(parentPSI); } - private Map pmts = new HashMap<>(); + private final Map pmts = new HashMap<>(); - public void update(final PMTsection section){ + public void update(PMTsection section){ - final int programNumber = section.getProgramNumber(); + int programNumber = section.getProgramNumber(); PMTsection[] sections = pmts.computeIfAbsent(programNumber, k -> new PMTsection[section.getSectionLastNumber() + 1]); if(sections[section.getSectionNumber()]==null){ sections[section.getSectionNumber()] = section; }else{ - final TableSection last = sections[section.getSectionNumber()]; + TableSection last = sections[section.getSectionNumber()]; updateSectionVersion(section, last); } } - public DefaultMutableTreeNode getJTreeNode(final int modus) { + public DefaultMutableTreeNode getJTreeNode(int modus) { - final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP("PMTs")); - final TreeSet s = new TreeSet<>(pmts.keySet()); + DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP("PMTs")); + Iterable serviceIds = new TreeSet<>(pmts.keySet()); - for (Integer programNumber : s) { - final PMTsection[] sections = pmts.get(programNumber); + for (Integer programNumber : serviceIds) { + PMTsection[] sections = pmts.get(programNumber); KVP kvp = new KVP("program", programNumber, getParentPSI().getSdt().getServiceNameForActualTransportStream(programNumber)); kvp.addTableSource(() -> getTableForProgram(programNumber),"Components"); - final DefaultMutableTreeNode n = new DefaultMutableTreeNode(kvp); - for (final PMTsection pmtSection : sections) { + DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(kvp); + for (PMTsection pmtSection : sections) { if (pmtSection != null) { if (Utils.simpleModus(modus)) { // keep it simple - n.add(new DefaultMutableTreeNode(new KVP("PCR_PID", pmtSection.getPcrPid(), null))); - addListJTree(n, pmtSection.getDescriptorList(), modus, "program_info"); - addListJTree(n, pmtSection.getComponentenList(), modus, "components"); + treeNode.add(new DefaultMutableTreeNode(new KVP("PCR_PID", pmtSection.getPcrPid(), null))); + addListJTree(treeNode, pmtSection.getDescriptorList(), modus, "program_info"); + addListJTree(treeNode, pmtSection.getComponentenList(), modus, "components"); } else { // show all details - addSectionVersionsToJTree(n, pmtSection, modus); + addSectionVersionsToJTree(treeNode, pmtSection, modus); } } } - t.add(n); + t.add(treeNode); } return t; @@ -120,9 +120,9 @@ static TableHeader buildPmtTableHeader() { addOptionalRowColumn("stream type", Component::getStreamtype, StreamTypeTableCellRenderer.class). addOptionalRowColumn("usage", - c -> determineComponentType(c.getComponentDescriptorList()). + component -> determineComponentType(component.getComponentDescriptorList()). map(ComponentType::getDescription). - orElse(getStreamTypeShortString(c.getStreamtype())), + orElse(getStreamTypeShortString(component.getStreamtype())), String.class). addOptionalRowColumn("elementary PID", Component::getElementaryPID, Integer.class). @@ -148,7 +148,7 @@ static TableHeader buildPmtTableHeader() { ISO639LanguageDescriptor.class, iso -> iso.getLanguageList(). stream(). - map(l->getAudioTypeString(l.getAudioType())). + map(language->getAudioTypeString(language.getAudioType())). collect(Collectors.toList())), String.class, "iso"). @@ -214,7 +214,7 @@ private TableModel getTableForProgram(int programNumber) { FlexTableModel tableModel = new FlexTableModel<>(buildPmtTableHeader()); PMTsection[] sections = pmts.get(programNumber); - for (final PMTsection pmtSection : sections) { + for (PMTsection pmtSection : sections) { if(pmtSection!= null){ tableModel.addData(pmtSection, pmtSection.getComponentenList()); } @@ -224,8 +224,8 @@ private TableModel getTableForProgram(int programNumber) { return tableModel; } - public int getPmtPID(final int programNumber){ - final PMTsection [] sections = pmts.get(programNumber); + public int getPmtPID(int programNumber){ + PMTsection [] sections = pmts.get(programNumber); for (PMTsection section : sections) { if(section!= null){ return section.getParentPID().getPid(); @@ -235,13 +235,13 @@ public int getPmtPID(final int programNumber){ } public ListfindPMTsFromComponentPID(int pid){ - ArrayList result = new ArrayList<>(); + List result = new ArrayList<>(); for(PMTsection[] pmtArray: pmts.values()){ PMTsection p = pmtArray[0]; for(Component component:p.getComponentenList()){ if(component.getElementaryPID()==pid){ result.add(p); - break; // every PMT is included once, even if more components wold point to same PID (which is illegal) + break; // every PMT is included once, even if more components would point to same PID (which is illegal) } } } @@ -250,7 +250,7 @@ public int getPmtPID(final int programNumber){ // PMT is always one section per program - public PMTsection getPmt(final int programNumber){ + public PMTsection getPmt(int programNumber){ return pmts.get(programNumber)[0]; } @@ -262,9 +262,5 @@ public Map getPmts() { return pmts; } - public void setPmts(final Map pmts) { - this.pmts = pmts; - } - } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/DVBtree.java b/src/main/java/nl/digitalekabeltelevisie/gui/DVBtree.java index 7cffb443..46f2d399 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/DVBtree.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/DVBtree.java @@ -29,10 +29,7 @@ import static nl.digitalekabeltelevisie.util.Utils.toHexStringUnformatted; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.GridLayout; -import java.awt.Toolkit; +import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; @@ -277,9 +274,9 @@ public void mousePressed(final MouseEvent e) { detailPanel.setUI(new BasicTabbedPaneUI() { @Override - protected int calculateTabAreaHeight(int tab_placement, int run_count, int max_tab_height) { + protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { if (detailPanel.getTabCount() > 1) { - return super.calculateTabAreaHeight(tab_placement, run_count, max_tab_height); + return super.calculateTabAreaHeight(tabPlacement, horizRunCount, maxTabHeight); } return 0; } @@ -320,17 +317,14 @@ public void hyperlinkUpdate(HyperlinkEvent e) { * @return */ private MutableTreeNode findNodeByTrail(String trail, DefaultTreeModel treeModel) { - if(trail ==null || - trail.isEmpty() || - !trail.startsWith("root") || - tree == null) { + if(trail == null || + !trail.startsWith("root") || + tree == null) { return null; } List pathList = Arrays.asList(trail.split("/")); return searchNode(pathList,(DefaultMutableTreeNode)treeModel.getRoot()); - - } /** @@ -344,23 +338,27 @@ private MutableTreeNode searchNode(List crumbTrail, DefaultMutableTreeNo } if (node.getUserObject() instanceof KVP kvp) { String crumbFound = kvp.getCrumb(); - if (crumbTrail.get(0).equalsIgnoreCase(crumbFound)) { + if (crumbTrail.getFirst().equalsIgnoreCase(crumbFound)) { if (crumbTrail.size() == 1) { return node; } List subList = crumbTrail.subList(1, crumbTrail.size()); for (Enumeration e = node.children(); e.hasMoreElements();) { TreeNode nextChild = e.nextElement(); - MutableTreeNode res; - if (nextChild instanceof DefaultMutableTreeNode dmtn) { - res = searchNode(subList, dmtn); - if (res != null) { - return res; - } - } else if (nextChild instanceof JTreeLazyList.RangeNode rangeNode - && subList.get(0).equalsIgnoreCase(rangeNode.getLabel().trim())) { - return rangeNode.findChildForActual(Integer.parseInt(subList.get(1))); - } + + switch(nextChild){ + case DefaultMutableTreeNode dmtn: + MutableTreeNode res = searchNode(subList, dmtn); + if (res != null) { + return res; + } + break; + case JTreeLazyList.RangeNode rangeNode when subList.get(0).equalsIgnoreCase(rangeNode.getLabel().trim()): + return rangeNode.findChildForActual(Integer.parseInt(subList.get(1))); + default: + // EMPTY + } + } } // name does not match @@ -377,7 +375,7 @@ private MutableTreeNode searchNode(List crumbTrail, DefaultMutableTreeNo * @param transportStream stream to be displayed (can be {@code null}) * @param viewContext ignored, required by {@link TransportStreamView} - * @see nl.digitalekabeltelevisie.gui.TransportStreamView#setTransportStream(nl.digitalekabeltelevisie.data.mpeg.TransportStream, nl.digitalekabeltelevisie.controller.ViewContext) + * @see TransportStreamView#setTransportStream(TransportStream, ViewContext) */ @Override public void setTransportStream(final TransportStream transportStream, final ViewContext viewContext){ @@ -441,7 +439,7 @@ private static boolean isNotStructuralChange(final int modus) { private void rebuildTree(){ if(ts!=null){ - model = new DefaultTreeModel(ts.getJTreeNode(this.mod)); + model = new DefaultTreeModel(ts.getJTreeNode(mod)); tree.setModel(model); } else { tree.setModel(null); @@ -451,15 +449,15 @@ private void rebuildTree(){ /** - * - * Retrieves the expansion state as a String, defined by a comma delimited list - * of each row node that is expanded. - * - * Based on {@link http://www.algosome.com/articles/save-jtree-expand-state.html} - * - * @return the expansion state as a String, defined by a comma delimited list - * - */ + * + * Retrieves the expansion state as a String, defined by a comma delimited list + * of each row node that is expanded. + * + * Based on {@link ...} + * + * @return the expansion state as a String, defined by a comma delimited list + * + */ private String getExpansionState() { StringBuilder sb = new StringBuilder(); @@ -475,13 +473,13 @@ private String getExpansionState() { /** - * Sets the expansion state based upon a comma delimited list of row indexes that - * are expanded. - * - * Based on {@link http://www.algosome.com/articles/save-jtree-expand-state.html} - * - * @param s the expansion state based upon a comma delimited list of row indexes that need to be expanded - */ + * Sets the expansion state based upon a comma delimited list of row indexes that + * are expanded. + * + * Based on {@link ...} + * + * @param s the expansion state based upon a comma delimited list of row indexes that need to be expanded + */ private void setExpansionState(String s) { String[] indexes = s.split(","); @@ -512,9 +510,11 @@ public void valueChanged(final TreeSelectionEvent e) { if(detailViews.isEmpty()) { return; } + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); for(DetailView view : detailViews) { createTabForView(view); } + setCursor(Cursor.getDefaultCursor()); } return; } @@ -525,46 +525,45 @@ public void valueChanged(final TreeSelectionEvent e) { private void createTabForView(DetailView view) { DetailSource detailSource = view.detailSource(); String label = view.label(); - if(detailSource instanceof ImageSource imageSource){ - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - BufferedImage img; - try { - img = imageSource.getImage(); - } catch (RuntimeException e1) { - logger.log(Level.WARNING, "could not create image from getImageSource():", e1); - img = GuiUtils.getErrorImage("Ooops.\n\n" + "Something went wrong generating this image.\n\n" + GuiUtils.getImproveMsg()); - } - setCursor(Cursor.getDefaultCursor()); - if(img != null){ - ImagePanel imagePanel = new ImagePanel(); - imagePanel.setImage(img); - detailPanel.addTab(label, imagePanel); - } - } else if(detailSource instanceof HTMLSource htmlSource){ - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - HtmlPanel htmlPanel = new HtmlPanel(controller, this, htmlSource.getHTML()); - setCursor(Cursor.getDefaultCursor()); - detailPanel.addTab(label, new JScrollPane(htmlPanel)); - } else if(detailSource instanceof XMLSource xmlSource){ - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - XmlPanel xmlPanel = new XmlPanel(); - // hack to reset - xmlPanel.setDocument(xmlPanel.getEditorKit().createDefaultDocument()); - xmlPanel.setText(xmlSource.getXML()); - xmlPanel.setCaretPosition(0); - setCursor(Cursor.getDefaultCursor()); - detailPanel.addTab(label, new JScrollPane(xmlPanel)); - } else if(detailSource instanceof TableSource tableSource){ - try { - TableModel tableModel = tableSource.getTableModel(); - if(tableModel.getColumnCount()>0 && tableModel.getRowCount()>0) { - TablePanel tablePanel = new TablePanel(new JTable()); - tablePanel.setModel(tableModel); - detailPanel.addTab(label, tablePanel); + + switch(detailSource){ + case ImageSource imageSource: + BufferedImage img; + try { + img = imageSource.getImage(); + } catch (RuntimeException e1) { + logger.log(Level.WARNING, "could not create image from getImageSource():", e1); + img = GuiUtils.getErrorImage("Ooops.\n\n" + "Something went wrong generating this image.\n\n" + GuiUtils.getImproveMsg()); + } + if(img != null){ + ImagePanel imagePanel = new ImagePanel(); + imagePanel.setImage(img); + detailPanel.addTab(label, imagePanel); + } + break; + case HTMLSource htmlSource: + HtmlPanel htmlPanel = new HtmlPanel(controller, this, htmlSource.getHTML()); + detailPanel.addTab(label, new JScrollPane(htmlPanel)); + break; + case XMLSource xmlSource: + XmlPanel xmlPanel = new XmlPanel(); + // hack to reset + xmlPanel.setDocument(xmlPanel.getEditorKit().createDefaultDocument()); + xmlPanel.setText(xmlSource.getXML()); + xmlPanel.setCaretPosition(0); + detailPanel.addTab(label, new JScrollPane(xmlPanel)); + break; + case TableSource tableSource: + try { + TableModel tableModel = tableSource.getTableModel(); + if(tableModel.getColumnCount()>0 && tableModel.getRowCount()>0) { + TablePanel tablePanel = new TablePanel(new JTable()); + tablePanel.setModel(tableModel); + detailPanel.addTab(label, tablePanel); + } + }catch (RuntimeException e2) { + logger.log(Level.WARNING, "could not create table:", e2); } - }catch (RuntimeException e2) { - logger.log(Level.WARNING, "could not create table:", e2); - } } } @@ -572,54 +571,31 @@ private void createTabForView(DetailView view) { * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override - public void actionPerformed(final ActionEvent ae) { + public void actionPerformed(final ActionEvent actionEvent) { final TreePath path = tree.getSelectionPath(); if(path!=null){ - DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) path.getLastPathComponent(); final KVP kvp = (KVP)dmtn.getUserObject(); - if (ae.getActionCommand().equals(EXPAND)) { - expandItem(); - } - if (ae.getActionCommand().equals(EXPAND_ALL)) { - expandAllItems(dmtn); - } - if (ae.getActionCommand().equals(COPY)) { - copyItemToClipboard(kvp); - } - if (ae.getActionCommand().equals(COPY_TREE)){ - copyEntireSubTreeToClipboard(dmtn); - } - if (ae.getActionCommand().equals(VIEW)){ - copyVisibleSubTreeToClipboard(dmtn, path, kvp); - } - if (ae.getActionCommand().equals(PARSE)){ - parsePid(dmtn, kvp); - } - if (ae.getActionCommand().equals(SAVE)){ - saveDsmccFile(kvp); - } - if (ae.getActionCommand().equals(EXPORT)){ - saveDsmccTree(kvp); - } - if (ae.getActionCommand().equals(PLAY)){ - playAudio138183(kvp); - } - if (ae.getActionCommand().equals(STOP)){ - stopAudio138183(kvp); - } - if (ae.getActionCommand().equals(T2MI)){ - saveT2miTs(kvp); - } - if (ae.getActionCommand().equals(T42)){ - saveT42File(kvp); - } - if (ae.getActionCommand().equals(SAVE_BYTES)){ - saveBytes(kvp); + String actionCommand = actionEvent.getActionCommand(); + switch (actionCommand){ + case EXPAND -> expandItem(); + case EXPAND_ALL ->expandAllItems(dmtn); + case COPY -> copyItemToClipboard(kvp); + case COPY_TREE -> copyEntireSubTreeToClipboard(dmtn); + case VIEW -> copyVisibleSubTreeToClipboard(dmtn, path, kvp); + case PARSE -> parsePid(dmtn, kvp); + case SAVE -> saveDsmccFile(kvp); + case EXPORT -> saveDsmccTree(kvp); + case PLAY -> playAudio138183(kvp); + case STOP -> stopAudio138183(kvp); + case T2MI -> saveT2miTs(kvp); + case T42 -> saveT42File(kvp); + case SAVE_BYTES -> saveBytes(kvp); } } } + /** * @param dmtn start node from where to expand */ @@ -723,18 +699,17 @@ private void saveDsmccFile(final KVP kvp) { private void saveT42File(final KVP kvp) { Object owner = kvp.getOwner(); - if (owner instanceof SaveAble savable) { - if (savable instanceof SubPage subPage) { - String fileName = "Page" + subPage.getMagazineNo() + toHexStringUnformatted(subPage.getPageNo(), 2) + "-" - + toHexStringUnformatted(subPage.getSubPageNo(), 4) + ".t42"; - selectFileAndSave(fileName, savable); - - } else if (savable instanceof EBUTeletextHandler txtHandler) { - String fileName = "Txt Service.t42"; - selectFileAndSave(fileName, savable); - - } - } + switch(owner){ + case SubPage subPage: + String fileName = "Page" + subPage.getMagazineNo() + toHexStringUnformatted(subPage.getPageNo(), 2) + "-" + + toHexStringUnformatted(subPage.getSubPageNo(), 4) + ".t42"; + selectFileAndSave(fileName, subPage); + break; + case EBUTeletextHandler txtHandler: + selectFileAndSave("Txt Service.t42", txtHandler); + break; + default: + } } /** @@ -744,45 +719,45 @@ private void saveT42File(final KVP kvp) { private void parsePid(DefaultMutableTreeNode dmtn, final KVP kvp) { final PID p = (PID) kvp.getOwner(); final int pid = p.getPid(); - GeneralPidHandler pesH = p.getPidHandler(); - if(!pesH.isInitialized()){ // prevent double click - Map handlerMap = new HashMap<>(); - handlerMap.put(pid, pesH); - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - try { - ts.parsePidStreams(handlerMap); - } catch (final IOException e) { - logger.log(Level.WARNING,"could not read file "+ts.getFile().getName()+" while parsing PES",e); - setCursor(Cursor.getDefaultCursor()); - }catch (RuntimeException e) { - logger.log(Level.WARNING,"could not parse PID "+pid+" using handler "+pesH.getClass().getName(),e); - if((pesH.getClass() != GeneralPesHandler.class) && - (pesH.getClass() != GeneralPsiTableHandler.class)){ // only if specialized subclass of GeneralPesHandler - logger.log(Level.WARNING,"trying again with GeneralPesHandler"); - JOptionPane.showMessageDialog(this, - "Error parsing PID PES Packets for "+p.getLabelMaker()+", falling back to general PES packets", - "DVB Inspector", - JOptionPane.WARNING_MESSAGE); - p.setPidHandler(new GeneralPesHandler()); - pesH = p.getPidHandler(); - handlerMap = new HashMap<>(); - handlerMap.put(pid, pesH); - try { - ts.parsePidStreams(handlerMap); - } catch (IOException e1) { - logger.log(Level.WARNING,"could not read file "+ts.getFile().getName()+" while parsing PES again with general PESHandler",e1); - } - setCursor(Cursor.getDefaultCursor()); + GeneralPidHandler generalPidHandler = p.getPidHandler(); + if(generalPidHandler.isInitialized()) return; // prevent double click + + Map handlerMap = new HashMap<>(); + handlerMap.put(pid, generalPidHandler); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + try { + ts.parsePidStreams(handlerMap); + } catch (final IOException e) { + logger.log(Level.WARNING,"could not read file "+ts.getFile().getName()+" while parsing PES",e); + setCursor(Cursor.getDefaultCursor()); + }catch (RuntimeException e) { + logger.log(Level.WARNING,"could not parse PID "+pid+" using handler "+generalPidHandler.getClass().getName(),e); + if((generalPidHandler.getClass() != GeneralPesHandler.class) && + (generalPidHandler.getClass() != GeneralPsiTableHandler.class)){ // only if specialized subclass of GeneralPesHandler + logger.log(Level.WARNING,"trying again with GeneralPesHandler"); + JOptionPane.showMessageDialog(this, + "Error parsing PID PES Packets for "+p.getLabelMaker()+", falling back to general PES packets", + "DVB Inspector", + JOptionPane.WARNING_MESSAGE); + p.setPidHandler(new GeneralPesHandler()); + generalPidHandler = p.getPidHandler(); + handlerMap = new HashMap<>(); + handlerMap.put(pid, generalPidHandler); + try { + ts.parsePidStreams(handlerMap); + } catch (IOException e1) { + logger.log(Level.WARNING,"could not read file "+ts.getFile().getName()+" while parsing PES again with general PESHandler",e1); } + setCursor(Cursor.getDefaultCursor()); } - final DefaultMutableTreeNode node = p.getPidHandler().getJTreeNode(mod); - // https://www.java-tips.org/java-se-tips-100019/15-javax-swing/2393-have-a-popup-attached-to-a-jtree.html - // thanks to Yong Zhang for the tip for refreshing the tree structure. - dmtn.add(node); - ((DefaultTreeModel )tree.getModel()).nodeStructureChanged(dmtn); - setCursor(Cursor.getDefaultCursor()); } + final DefaultMutableTreeNode node = p.getPidHandler().getJTreeNode(mod); + // https://www.java-tips.org/java-se-tips-100019/15-javax-swing/2393-have-a-popup-attached-to-a-jtree.html + // thanks to Yong Zhang for the tip for refreshing the tree structure. + dmtn.add(node); + ((DefaultTreeModel )tree.getModel()).nodeStructureChanged(dmtn); + setCursor(Cursor.getDefaultCursor()); } /** @@ -827,11 +802,10 @@ private void copyItemToClipboard(final KVP kvp) { */ public static StringBuilder getEntireTree(final DefaultMutableTreeNode dmtn,final String preFix) { - final StringBuilder res = new StringBuilder(); - @SuppressWarnings("rawtypes") - final Enumeration children = dmtn.children(); + StringBuilder res = new StringBuilder(); + Enumeration children = dmtn.children(); while(children.hasMoreElements()){ - Object next = children.nextElement(); + TreeNode next = children.nextElement(); if(next instanceof final DefaultMutableTreeNode child){ Object userObject = child.getUserObject(); if(userObject instanceof final KVP chKVP) { @@ -858,11 +832,10 @@ public static StringBuilder getEntireTree(final DefaultMutableTreeNode dmtn,fina private StringBuilder getViewTree(final DefaultMutableTreeNode dmtn,final String preFix,final TreePath path) { final StringBuilder res = new StringBuilder(); - @SuppressWarnings("rawtypes") - final Enumeration children = dmtn.children(); + Enumeration children = dmtn.children(); while(children.hasMoreElements()){ - Object next = children.nextElement(); + TreeNode next = children.nextElement(); if(next instanceof final DefaultMutableTreeNode child){ final TreePath childPath = path.pathByAddingChild(child); if(tree.isVisible(childPath)){ @@ -888,7 +861,7 @@ private void showContextMenu(final MouseEvent e) { final TreePath path = tree.getSelectionPath(); - MenuElement[] subs = popup.getSubElements(); + MenuElement[] subs = popup.getSubElements(); for (MenuElement sub : subs) { JMenuItem menuElement = (JMenuItem) sub; menuElement.setEnabled(path != null); @@ -901,12 +874,9 @@ private void showContextMenu(final MouseEvent e) { } // add optional menu - DefaultMutableTreeNode dmtn; if(path!=null){ - MutableTreeNode node= (MutableTreeNode)path.getLastPathComponent(); - if((node instanceof DefaultMutableTreeNode)){ - dmtn = (DefaultMutableTreeNode) path.getLastPathComponent(); + if(((MutableTreeNode)path.getLastPathComponent() instanceof DefaultMutableTreeNode dmtn)){ final KVP kvp=(KVP)dmtn.getUserObject(); JMenuItem subMenu = kvp.getSubMenu(); if(subMenu!=null){ @@ -925,7 +895,7 @@ private void showContextMenu(final MouseEvent e) { }else{ if(kvp.getFieldType()== KVP.FIELD_TYPE_BYTES){ final JMenuItem bytesMenu = new JMenuItem("Save bytes as..."); - + bytesMenu.setActionCommand(SAVE_BYTES); bytesMenu.addActionListener(this); popup.add(bytesMenu); @@ -942,8 +912,7 @@ private void showContextMenu(final MouseEvent e) { } } - - popup.show( (JComponent)e.getSource(), e.getX(), e.getY() ); + popup.show((Component) e.getSource(), e.getX(), e.getY() ); } /* (non-Javadoc) @@ -965,8 +934,8 @@ public boolean findAndShow(String s,DefaultMutableTreeNodePreorderEnumaration en return false; } - private void showNode(MutableTreeNode node) { - javax.swing.tree.TreeNode[] nodes = model.getPathToRoot(node); + private void showNode(TreeNode node) { + TreeNode[] nodes = model.getPathToRoot(node); TreePath path = new TreePath(nodes); tree.scrollPathToVisible(path); @@ -1036,11 +1005,11 @@ private void confirmOverwriteIfExisting(final File file, SaveAble saveAble) { boolean write=true; if(file.exists()){ logger.log(Level.INFO, "file {} already exists.", file); - final int n = JOptionPane.showConfirmDialog( + final int option = JOptionPane.showConfirmDialog( this, "File "+file+" already exists, want to overwrite?", "File already exists", JOptionPane.YES_NO_OPTION); - if (n == JOptionPane.NO_OPTION) { + if (JOptionPane.NO_OPTION == option) { write=false; logger.info("User canceled overwrite"); }else{ diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/DetailSource.java b/src/main/java/nl/digitalekabeltelevisie/gui/DetailSource.java index 54b8ac34..8903e1ba 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/DetailSource.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/DetailSource.java @@ -31,6 +31,6 @@ * @author Eric * */ -public interface DetailSource { +sealed public interface DetailSource permits HTMLSource, ImageSource, TableSource, XMLSource { } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/HTMLSource.java b/src/main/java/nl/digitalekabeltelevisie/gui/HTMLSource.java index f390eef9..5ad532cd 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/HTMLSource.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/HTMLSource.java @@ -34,8 +34,7 @@ * */ -@FunctionalInterface -public interface HTMLSource extends DetailSource{ +public non-sealed interface HTMLSource extends DetailSource{ /** * @return a HTML fragment, without the start and end <html> tags. This way several fragments can be concatenated. diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/ImageSource.java b/src/main/java/nl/digitalekabeltelevisie/gui/ImageSource.java index 8faa510f..91abb542 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/ImageSource.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/ImageSource.java @@ -29,8 +29,7 @@ import java.awt.image.BufferedImage; -@FunctionalInterface -public interface ImageSource extends DetailSource{ +public non-sealed interface ImageSource extends DetailSource{ BufferedImage getImage(); } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/TableSource.java b/src/main/java/nl/digitalekabeltelevisie/gui/TableSource.java index 8e4f4bf8..47d36516 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/TableSource.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/TableSource.java @@ -29,7 +29,7 @@ import javax.swing.table.TableModel; -public interface TableSource extends DetailSource{ +public non-sealed interface TableSource extends DetailSource{ TableModel getTableModel(); } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/XMLSource.java b/src/main/java/nl/digitalekabeltelevisie/gui/XMLSource.java index 76e54fd8..e6b2c987 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/XMLSource.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/XMLSource.java @@ -34,8 +34,7 @@ * */ -@FunctionalInterface -public interface XMLSource extends DetailSource{ +public non-sealed interface XMLSource extends DetailSource{ /** * @return a XML string diff --git a/src/main/java/nl/digitalekabeltelevisie/util/Utils.java b/src/main/java/nl/digitalekabeltelevisie/util/Utils.java index 6398057f..e5e182eb 100644 --- a/src/main/java/nl/digitalekabeltelevisie/util/Utils.java +++ b/src/main/java/nl/digitalekabeltelevisie/util/Utils.java @@ -1203,7 +1203,9 @@ public static void addListJTree(final DefaultMutableTreeNode parent, } else { final KVP kvp = new KVP(label + ": " + itemCollection.size() + " entries"); kvp.setCrumb(label); - kvp.addTableSource(tableSource, label); + if (tableSource != null) { + kvp.addTableSource(tableSource, label); + } final DefaultMutableTreeNode descriptorListNode = new DefaultMutableTreeNode(kvp); addToList(descriptorListNode, itemCollection, modus); parent.add(descriptorListNode); diff --git a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java index 47b3fd44..e6038eb3 100644 --- a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java +++ b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java @@ -85,4 +85,19 @@ public void packet328081Test() { assertEquals("file offset",61679228, packet328081.getPacketOffset()); } + @Test + public void testPacketTime(){ + assertEquals("PacketTime packet 1","2009/06/30 17h43m54:962",transportStream.getPacketTime(1)); + assertEquals("PacketTime packet 123432","2009/06/30 17h44m07:396",transportStream.getPacketTime(123432)); + assertEquals("PacketTimepacket 343551","2009/06/30 17h44m29:571",transportStream.getPacketTime(343551)); + + } + + @Test + public void testShortPacketTime(){ + assertEquals("ShortPacketTime packet 1","17h43m54:962",transportStream.getShortPacketTime(1)); + assertEquals("ShortPacketTime packet 123432","17h44m07:396",transportStream.getShortPacketTime(123432)); + assertEquals("ShortPacketTime packet 343551","17h44m29:571",transportStream.getShortPacketTime(343551)); + + } }