From f658160285955f4c6d691ea9b6d3012ab9d79e5b Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 30 Jun 2024 12:36:56 +0200 Subject: [PATCH 01/23] inlined parseStream(), renamed parsePSITables to parseStream --- .../data/mpeg/TransportStream.java | 11 +---------- .../java/nl/digitalekabeltelevisie/gui/TSLoader.java | 2 +- .../nl/digitalekabeltelevisie/main/DVBinspector.java | 2 +- .../nl/digitalekabeltelevisie/test/ExportTree.java | 2 +- .../data/mpeg/TransportStreamMissingPacketsTest.java | 2 +- .../data/mpeg/TransportStreamTest.java | 2 +- .../data/mpeg/pes/PesHandlerSetup.java | 2 +- 7 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 558e5565..1a16190a 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -285,16 +285,7 @@ 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() throws IOException { - parsePSITables(null); - } - - - /** - * 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 parsePSITables(final java.awt.Component component) throws IOException { + public void parseStream(final java.awt.Component component) throws IOException { try (PositionPushbackInputStream fileStream = getInputStream(component)) { final byte[] buf = new byte[packetLength]; int count = 0; diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/TSLoader.java b/src/main/java/nl/digitalekabeltelevisie/gui/TSLoader.java index 748f3da8..4cf90c37 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/TSLoader.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/TSLoader.java @@ -88,7 +88,7 @@ protected TransportStream doInBackground() { TransportStream transportStream = null; try { transportStream = new TransportStream(file); - transportStream.parsePSITables(control.getFrame()); + transportStream.parseStream(control.getFrame()); } catch (final NotAnMPEGFileException e) { try { diff --git a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java index e3965c1c..5ba5cf3a 100644 --- a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java +++ b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java @@ -163,7 +163,7 @@ public static void main(final String[] args) { try { final TransportStream ts = new TransportStream(filename); inspector.transportStream = ts; - inspector.transportStream.parseStream(); + inspector.transportStream.parseStream(null); if (args.length >= 2) { final Map pidHandlerMap = determinePidHandlers(args, ts); diff --git a/src/main/java/nl/digitalekabeltelevisie/test/ExportTree.java b/src/main/java/nl/digitalekabeltelevisie/test/ExportTree.java index d8785a9a..a813388c 100644 --- a/src/main/java/nl/digitalekabeltelevisie/test/ExportTree.java +++ b/src/main/java/nl/digitalekabeltelevisie/test/ExportTree.java @@ -96,7 +96,7 @@ static void exportFile(Path filePath) { try { TransportStream transportStream = new TransportStream(tsFile); - transportStream.parseStream(); + transportStream.parseStream(null); DefaultMutableTreeNode node = transportStream.getJTreeNode(2); // psi only diff --git a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamMissingPacketsTest.java b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamMissingPacketsTest.java index 879f72b3..f9d7fb5c 100644 --- a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamMissingPacketsTest.java +++ b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamMissingPacketsTest.java @@ -21,7 +21,7 @@ public static void setUp() throws NotAnMPEGFileException, IOException, URISyntax // spaces in dirname... final File ts = new File(resource.toURI()); transportStream = new TransportStream(ts); - transportStream.parseStream(); + transportStream.parseStream(null); } diff --git a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java index 3170edda..47b3fd44 100644 --- a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java +++ b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/TransportStreamTest.java @@ -22,7 +22,7 @@ public static void setUp() throws NotAnMPEGFileException, IOException, URISyntax // spaces in dirname... final File ts = new File(resource.toURI()); transportStream = new TransportStream(ts); - transportStream.parseStream(); + transportStream.parseStream(null); } diff --git a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/pes/PesHandlerSetup.java b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/pes/PesHandlerSetup.java index cfc7607a..ddd1da1d 100644 --- a/src/test/java/nl/digitalekabeltelevisie/data/mpeg/pes/PesHandlerSetup.java +++ b/src/test/java/nl/digitalekabeltelevisie/data/mpeg/pes/PesHandlerSetup.java @@ -66,7 +66,7 @@ public static void setUp() throws NotAnMPEGFileException, IOException, URISyntax // spaces in dirname... final File ts = new File(resource.toURI()); transportStream = new TransportStream(ts); - transportStream.parseStream(); + transportStream.parseStream(null); final Map map = new HashMap<>(); From 672ba2ef133c226c455523966a6710dd7ee40580 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 30 Jun 2024 12:37:44 +0200 Subject: [PATCH 02/23] removed commented code --- .../nl/digitalekabeltelevisie/data/mpeg/TSPacket.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java index 0b84ce2e..19dce746 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java @@ -110,17 +110,6 @@ public TSPacket(final byte[] buf, final int no, final TransportStream ts) { buffer=Arrays.copyOf(buf, buf.length); //buf should be copied, or else PID.getLast_packet() will always point to last packet parsed, regardless of the actual pid. packetNo = no; transportStream = ts; - -// if((getAdaptationFieldControl()==2)||(getAdaptationFieldControl()==3)) { //Adaptation field present -// getAdaptationField(); -// } -// -// if(getPayloadUnitStartIndicator()==1){ -// if((getAdaptationFieldControl()!=1)&&(getAdaptationFieldControl()!=3)){ -// System.out.println("Error: TSPacket:"+packetNo+", PID:"+getPID()+", If a PID is carrying PES packets or PSI sections, and payload_unit_start_indicator is set to 1, then test that adaptation_field_control is ‘01’ or ‘11’”"); -// } -// } -// } public int getTransportScramblingControl(){ From 05ed257393de09c13647825a0b5745731597e7fd Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 30 Jun 2024 14:13:24 +0200 Subject: [PATCH 03/23] Fixed FEC/timestamp not shown in Tree when no payload, refactoring --- .../data/mpeg/TSPacket.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java index 19dce746..fa31a613 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java @@ -344,18 +344,7 @@ private int getSyncByte() { @Override public DefaultMutableTreeNode getJTreeNode(final int modus) { - final StringBuilder l = new StringBuilder("transport_packet [").append(packetNo).append("]"); - if((getAdaptationFieldControl()==2)||(getAdaptationFieldControl()==3)) { //Adaptation field present - l.append(" (adaptation field)"); - } - if(hasPayload()) { //payload present - l.append(" (payload)"); - } - if(isPayloadUnitStartIndicator()){ - l.append(" (payload start)"); - } - - final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(l.toString(), this)); + final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(buildNodeLabel(), this)); t.add(new DefaultMutableTreeNode(new KVP("sync_byte",getSyncByte() ,"Should be 0x47"))); t.add(new DefaultMutableTreeNode(new KVP("transport_error_indicator",getTransportErrorIndicator() ,null))); t.add(new DefaultMutableTreeNode(new KVP("payload_unit_start_indicator",getPayloadUnitStartIndicator() ,null))); @@ -390,13 +379,29 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { t.add(pesHeaderView.getJTreeNode(modus)); } } - if(buffer.length>PAYLOAD_PACKET_LENGTH){ - t.add(new DefaultMutableTreeNode(new KVP("FEC/timestamp",buffer,PAYLOAD_PACKET_LENGTH ,buffer.length - PAYLOAD_PACKET_LENGTH, null))); - } + } + if(buffer.length>PAYLOAD_PACKET_LENGTH){ + t.add(new DefaultMutableTreeNode(new KVP("FEC/timestamp",buffer,PAYLOAD_PACKET_LENGTH ,buffer.length - PAYLOAD_PACKET_LENGTH, null))); } return t; } + protected String buildNodeLabel() { + final StringBuilder l = new StringBuilder("transport_packet [").append(packetNo).append("]"); + if((getAdaptationFieldControl()==2)||(getAdaptationFieldControl()==3)) { //Adaptation field present + l.append(" (adaptation field)"); + } + if(hasPayload()) { //payload present + l.append(" (payload)"); + } + if(isPayloadUnitStartIndicator()){ + l.append(" (payload start)"); + } + + final String nodeLabel = l.toString(); + return nodeLabel; + } + public long getPacketOffset() { return packetOffset; } From 58f6ba0f858f15abc89b9c6b8e8d6e7aeb0f2047 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 30 Jun 2024 22:46:55 +0200 Subject: [PATCH 04/23] first attempt at TP_extra_header support for 192 byte packets --- .../data/mpeg/AVCHDPacket.java | 117 ++++++++++++++++++ .../data/mpeg/TSPacket.java | 68 +++++----- .../data/mpeg/TransportStream.java | 116 ++++++++++++----- .../nl/digitalekabeltelevisie/util/Utils.java | 4 +- 4 files changed, 241 insertions(+), 64 deletions(-) create mode 100644 src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java new file mode 100644 index 00000000..cadbd818 --- /dev/null +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -0,0 +1,117 @@ +/** + * + * 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; + +import static nl.digitalekabeltelevisie.util.Utils.*; + +import java.awt.Color; +import java.util.Arrays; + +import javax.swing.tree.DefaultMutableTreeNode; + +import nl.digitalekabeltelevisie.controller.KVP; +import nl.digitalekabeltelevisie.util.RangeHashMap; +import nl.digitalekabeltelevisie.util.Utils; + +/** + * + */ +public class AVCHDPacket extends TSPacket { + byte[] tp_extra_header; + int roll_over; + + public AVCHDPacket(byte[] buf, int no, TransportStream ts, int roll_over) { + super(Arrays.copyOfRange(buf,4,192), no, ts); + tp_extra_header = Arrays.copyOf(buf,4); + this.roll_over = roll_over; + } + + + public byte[] getTP_extra_header() { + return tp_extra_header; + } + + public int getCopyPermissionIndicator() { + return (tp_extra_header[0] & 0b1100_0000)>>6; + } + + public int getArrivalTimestamp() { + return getInt(tp_extra_header,0,4,MASK_30BITS); + } + + + @Override + public DefaultMutableTreeNode getJTreeNode(final int modus) { + + final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(buildNodeLabel(),this)); + final DefaultMutableTreeNode tpHeaderNode = new DefaultMutableTreeNode(new KVP("tp_extra_header",tp_extra_header,null)); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Copy_permission_indicator",getCopyPermissionIndicator(),null))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",getArrivalTimestamp(),printPCRTime(getArrivalTimestamp())))); + t.add(tpHeaderNode); + addMainPacketDetails(modus, t); + return t; + } + + public String getHTML() { + final StringBuilder s = new StringBuilder(); + + s.append("Packet: ").append(packetNo); + if(packetOffset!=-1){ + s.append("
File Offset: ").append(packetOffset); + } + if(transportStream!=null){ + //s.append("
Time: ").append(transportStream.getPacketTime(packetNo)); + final short pid = transportStream.getPacket_pid(packetNo); + s.append("
").append(escapeHtmlBreakLines(transportStream.getShortLabel(pid))).append("
"); + } + + + + final RangeHashMap coloring = new RangeHashMap<>(); + + //tp_extra_header + Utils.appendHeader(s, "TP_extra_header: 0x" + toHexString(tp_extra_header, 0, 4), FEC_COLOR); + coloring.put(0, 4, FEC_COLOR); + + + s.append("
Copy_permission_indicator: ").append(getCopyPermissionIndicator()); + s.append("
Arrival_time_stamp: ").append(getArrivalTimestamp()).append(" (").append(printPCRTime(getArrivalTimestamp())).append(")").append("
"); + + addBasicPacketDetails(s, 4, coloring); + + byte[] buf = new byte[192]; + + System.arraycopy(tp_extra_header, 0, buf, 0, 4); + System.arraycopy(buffer, 0, buf, 4, 188); + + s.append("
Data:
").append(getHTMLHexviewColored(buf,0,192,coloring)); + return s.toString(); + } + + +} diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java index fa31a613..b5b6e3fc 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java @@ -67,16 +67,16 @@ public class TSPacket implements HTMLSource, TreeNode{ private static final Logger logger = Logger.getLogger(TSPacket.class.getName()); private static final String ERROR_PARSING_ADAPTATION_FIELD = "Error parsing AdaptationField"; - final private byte[] buffer ; + protected final byte[] buffer ; - private int packetNo=-1; - final private static Color HEADER_COLOR = new Color(0x0000ff); - final private static Color ADAPTATION_FIELD_COLOR = new Color(0x008000); - final private static Color FEC_COLOR = new Color(0x800080); - final private static Color PES_HEADER_COLOR = new Color(0x800000); - private static final Color ERROR_COLOR = new Color(0xFF0000); - final private TransportStream transportStream; - private long packetOffset = -1; + protected int packetNo=-1; + final protected static Color HEADER_COLOR = new Color(0x0000ff); + final protected static Color ADAPTATION_FIELD_COLOR = new Color(0x008000); + final protected static Color FEC_COLOR = new Color(0x800080); + final protected static Color PES_HEADER_COLOR = new Color(0x800000); + final protected static Color ERROR_COLOR = new Color(0xFF0000); + final protected TransportStream transportStream; + protected long packetOffset = -1; private PesHeader pesHeader = null; @@ -261,9 +261,25 @@ public String getHTML() { s.append("
").append(escapeHtmlBreakLines(transportStream.getShortLabel(pid))).append("
"); } - Utils.appendHeader(s, "Header:", HEADER_COLOR); final RangeHashMap coloring = new RangeHashMap<>(); - coloring.put(0, 3, HEADER_COLOR); + addBasicPacketDetails(s, 0, coloring); + + // FEC / timestamp + if(buffer.length>PAYLOAD_PACKET_LENGTH){ + final RangeHashMap localColoring = new RangeHashMap<>(); + //for some reason using getHTMLHexview resets color, so we use getHTMLHexviewColored with only one color. + localColoring.put(0, buffer.length-PAYLOAD_PACKET_LENGTH, FEC_COLOR); + Utils.appendHeader(s, "FEC/timestamp:", FEC_COLOR); + s.append(getHTMLHexviewColored(buffer,PAYLOAD_PACKET_LENGTH,buffer.length-PAYLOAD_PACKET_LENGTH,localColoring)).append(""); + coloring.put(PAYLOAD_PACKET_LENGTH, buffer.length, FEC_COLOR); + } + s.append("
Data:
").append(getHTMLHexviewColored(buffer,0,buffer.length,coloring)); + return s.toString(); + } + + protected void addBasicPacketDetails(final StringBuilder s, int coloringOffset, final RangeHashMap coloring) { + Utils.appendHeader(s, "Header:", HEADER_COLOR); + coloring.put(coloringOffset, coloringOffset + 3, HEADER_COLOR); s.append("
sync_byte: ").append(getHexAndDecimalFormattedString(getSyncByte())); s.append("
transport_error_indicator: ").append(getTransportErrorIndicator()); @@ -286,7 +302,7 @@ public String getHTML() { if(adaptationField!=null){ Utils.appendHeader(s, "adaptation_field:", ADAPTATION_FIELD_COLOR); s.append(adaptationField.getHTML()).append("
"); - coloring.put(4, 4+adaptationField.getAdaptation_field_length(), ADAPTATION_FIELD_COLOR); + coloring.put(coloringOffset + 4, coloringOffset + 4 + adaptationField.getAdaptation_field_length(), ADAPTATION_FIELD_COLOR); } // PES header @@ -303,25 +319,13 @@ public String getHTML() { s.append("
").append(Utils.getChildrenAsHTML(treeNode)); s.append(""); if(pesHeaderView.hasExtendedHeader()){ - coloring.put(payloadStart, payloadStart+8+pesHeaderView.getPes_header_data_length(), PES_HEADER_COLOR); + coloring.put(coloringOffset + payloadStart, coloringOffset + payloadStart+8+pesHeaderView.getPes_header_data_length(), PES_HEADER_COLOR); }else{ - coloring.put(payloadStart, payloadStart+5, PES_HEADER_COLOR); + coloring.put(coloringOffset + payloadStart, coloringOffset + payloadStart+5, PES_HEADER_COLOR); } } } } - - // FEC / timestamp - if(buffer.length>PAYLOAD_PACKET_LENGTH){ - final RangeHashMap localColoring = new RangeHashMap<>(); - //for some reason using getHTMLHexview resets color, so we use getHTMLHexviewColored with only one color. - localColoring.put(0, buffer.length-PAYLOAD_PACKET_LENGTH, FEC_COLOR); - Utils.appendHeader(s, "FEC/timestamp:", FEC_COLOR); - s.append(getHTMLHexviewColored(buffer,PAYLOAD_PACKET_LENGTH,buffer.length-PAYLOAD_PACKET_LENGTH,localColoring)).append(""); - coloring.put(PAYLOAD_PACKET_LENGTH, buffer.length, FEC_COLOR); - } - s.append("
Data:
").append(getHTMLHexviewColored(buffer,0,buffer.length,coloring)); - return s.toString(); } /** @@ -345,6 +349,14 @@ private int getSyncByte() { public DefaultMutableTreeNode getJTreeNode(final int modus) { final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(buildNodeLabel(), this)); + addMainPacketDetails(modus, t); + if(buffer.length>PAYLOAD_PACKET_LENGTH){ + t.add(new DefaultMutableTreeNode(new KVP("FEC/timestamp",buffer,PAYLOAD_PACKET_LENGTH ,buffer.length - PAYLOAD_PACKET_LENGTH, null))); + } + return t; + } + + protected void addMainPacketDetails(final int modus, final DefaultMutableTreeNode t) { t.add(new DefaultMutableTreeNode(new KVP("sync_byte",getSyncByte() ,"Should be 0x47"))); t.add(new DefaultMutableTreeNode(new KVP("transport_error_indicator",getTransportErrorIndicator() ,null))); t.add(new DefaultMutableTreeNode(new KVP("payload_unit_start_indicator",getPayloadUnitStartIndicator() ,null))); @@ -380,10 +392,6 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { } } } - if(buffer.length>PAYLOAD_PACKET_LENGTH){ - t.add(new DefaultMutableTreeNode(new KVP("FEC/timestamp",buffer,PAYLOAD_PACKET_LENGTH ,buffer.length - PAYLOAD_PACKET_LENGTH, null))); - } - return t; } protected String buildNodeLabel() { diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 1a16190a..280c1761 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -101,6 +101,8 @@ */ public class TransportStream implements TreeNode{ + private static final int AVCHD_PACKET_LENGTH = 192; + public enum ComponentType{ AC3("Dolby Audio (AC3)"), E_AC3("Enhanced Dolby Audio (AC3)"), @@ -189,7 +191,7 @@ public String getDescription() { private int packetLength = 188; - public static final int [] ALLOWED_PACKET_LENGTHS = {188,192,204,208}; + public static final int [] ALLOWED_PACKET_LENGTHS = {188,AVCHD_PACKET_LENGTH,204,208}; /** @@ -287,8 +289,6 @@ private static boolean usesPacketLength(final int possiblePacketLength, final Ra */ public void parseStream(final java.awt.Component component) throws IOException { try (PositionPushbackInputStream fileStream = getInputStream(component)) { - final byte[] buf = new byte[packetLength]; - int count = 0; no_packets = 0; pids = new PID[8192]; @@ -297,38 +297,84 @@ public void parseStream(final java.awt.Component component) throws IOException { bitRate = -1; bitRateTDT = -1; - int bytes_read = 0; - int lastHandledSyncErrorPacket = -1; - do { - final 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))) { - // always push back first byte of next packet - if ((next != -1)) { - fileStream.unread(next); + if(packetLength == AVCHD_PACKET_LENGTH) { + readAVCHDPackets(fileStream); + } else { + readPackets(fileStream); + } + } + postProcess(); + } + + private void readPackets(PositionPushbackInputStream fileStream) throws IOException { + int count = 0; + int bytes_read = 0; + int lastHandledSyncErrorPacket = -1; + final byte[] buf = new byte[packetLength]; + do { + final 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))) { + // always push back first byte of next packet + if ((next != -1)) { + fileStream.unread(next); + } + offsetHelper.addPacket(no_packets, offset); + processPacket(new TSPacket(buf, count, this)); + count++; + } else { // something wrong, find next syncbyte. First push back the lot + if ((next != -1)) { + if (lastHandledSyncErrorPacket != no_packets) { + sync_errors++; + logger.severe(String.format("Did not find sync byte, resyncing at offset:%d, packet_no:%d", offset, + no_packets)); + lastHandledSyncErrorPacket = no_packets; } - offsetHelper.addPacket(no_packets, offset); - processPacket(new TSPacket(buf, count, this)); - count++; - } else { // something wrong, find next syncbyte. First push back the lot - if ((next != -1)) { - if (lastHandledSyncErrorPacket != no_packets) { - sync_errors++; - logger.severe(String.format("Did not find sync byte, resyncing at offset:%d, packet_no:%d", offset, - no_packets)); - lastHandledSyncErrorPacket = no_packets; - } - fileStream.unread(next); - fileStream.unread(buf, 0, bytes_read); - // now read 1 byte and restart all - fileStream.read(); // ignore result + fileStream.unread(next); + fileStream.unread(buf, 0, bytes_read); + // now read 1 byte and restart all + fileStream.read(); // ignore result + } + } + } while (bytes_read == packetLength); + } + + private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOException { + int count = 0; + int bytes_read = 0; + int lastHandledSyncErrorPacket = -1; + final byte[] buf = new byte[AVCHD_PACKET_LENGTH]; + do { + final 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))) { + // always push back first byte of next packet + if ((next != -1)) { + fileStream.unread(nextBytes,0,next); + } + offsetHelper.addPacket(no_packets, offset); + processPacket(new AVCHDPacket(buf, count, this,0)); + count++; + } else { // something wrong, find next syncbyte. First push back the lot + if ((next != -1)) { + if (lastHandledSyncErrorPacket != no_packets) { + sync_errors++; + logger.severe(String.format("Did not find sync byte, resyncing at offset:%d, packet_no:%d", offset, + no_packets)); + lastHandledSyncErrorPacket = no_packets; } + fileStream.unread(nextBytes,0,next); + fileStream.unread(buf, 0, bytes_read); + // now read 1 byte and restart all + fileStream.read(); // ignore result } - } while (bytes_read == packetLength); - } - postProcess(); + } + } while (bytes_read == packetLength); } public void postProcess() { @@ -1089,7 +1135,11 @@ private TSPacket readPacket(final int packetNo, final RandomAccessFile randomAcc final byte [] buf = new byte[packetLength]; final int bytesRead = randomAccessFile.read(buf); if(bytesRead==packetLength){ - packet = new TSPacket(buf, packetNo,this); + if(packetLength == AVCHD_PACKET_LENGTH) { + packet = new AVCHDPacket(buf, packetNo,this,0); //TODO handle roll-over + }else { + packet = new TSPacket(buf, packetNo,this); + } packet.setPacketOffset(offset); }else{ logger.warning(String.format("read less then packetLenghth (%d) bytes, actual read: %d", packetLength, bytesRead)); diff --git a/src/main/java/nl/digitalekabeltelevisie/util/Utils.java b/src/main/java/nl/digitalekabeltelevisie/util/Utils.java index a1b612af..6398057f 100644 --- a/src/main/java/nl/digitalekabeltelevisie/util/Utils.java +++ b/src/main/java/nl/digitalekabeltelevisie/util/Utils.java @@ -118,7 +118,9 @@ private Utils() { public static final int MASK_20BITS=0xF_FFFF; public static final int MASK_22BITS=0x3F_FFFF; public static final int MASK_24BITS=0xFF_FFFF; - public static final int MASK_31BITS=0x7FF_FFFFF; + public static final int MASK_30BITS=0x3FFF_FFFF; + + public static final int MASK_31BITS=0x7FFF_FFFF; public static final int MASK_32BITS=0xFFFF_FFFF; public static final long MASK_33BITS=0x1_FFFF_FFFFL; From a5dda80a4fbceb144ff5b39a6aef7144145c764d Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Mon, 1 Jul 2024 14:53:16 +0200 Subject: [PATCH 05/23] added rollOverHelper to reconstruct a 'PCR' --- .../data/mpeg/AVCHDPacket.java | 23 ++++++- .../data/mpeg/TransportStream.java | 17 ++++- .../util/OffsetHelper.java | 5 +- .../util/RollOverHelper.java | 65 +++++++++++++++++++ 4 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index cadbd818..e652397f 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -42,10 +42,12 @@ * */ public class AVCHDPacket extends TSPacket { + + static final int bit30 = 0x4000_0000; byte[] tp_extra_header; - int roll_over; + long roll_over; - public AVCHDPacket(byte[] buf, int no, TransportStream ts, int roll_over) { + public AVCHDPacket(byte[] buf, int no, TransportStream ts, long roll_over) { super(Arrays.copyOfRange(buf,4,192), no, ts); tp_extra_header = Arrays.copyOf(buf,4); this.roll_over = roll_over; @@ -71,7 +73,11 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(buildNodeLabel(),this)); final DefaultMutableTreeNode tpHeaderNode = new DefaultMutableTreeNode(new KVP("tp_extra_header",tp_extra_header,null)); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Copy_permission_indicator",getCopyPermissionIndicator(),null))); - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",getArrivalTimestamp(),printPCRTime(getArrivalTimestamp())))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Roll-over",roll_over,null))); + final int arrivalTimestamp = getArrivalTimestamp(); + long cats = (roll_over * bit30) + arrivalTimestamp; + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",arrivalTimestamp,printPCRTime(arrivalTimestamp)))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Continuos ATS ",cats,printPCRTime(cats)))); t.add(tpHeaderNode); addMainPacketDetails(modus, t); return t; @@ -100,6 +106,7 @@ public String getHTML() { s.append("
Copy_permission_indicator: ").append(getCopyPermissionIndicator()); + s.append("
roll-over: ").append(roll_over); s.append("
Arrival_time_stamp: ").append(getArrivalTimestamp()).append(" (").append(printPCRTime(getArrivalTimestamp())).append(")").append("
"); addBasicPacketDetails(s, 4, coloring); @@ -114,4 +121,14 @@ public String getHTML() { } + public long getRoll_over() { + return roll_over; + } + + + public void setRoll_over(long roll_over) { + this.roll_over = roll_over; + } + + } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 280c1761..d483f3a2 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -157,6 +157,7 @@ public String getDescription() { private final short [] packet_pid; private OffsetHelper offsetHelper = null; + private RollOverHelper rollOverHelper = null; /** * Starting point for all the PSI information in this TransportStream */ @@ -216,6 +217,7 @@ public TransportStream(final File file) throws NotAnMPEGFileException,IOExceptio int max_packets = (int) (len / packetLength); packet_pid = new short [max_packets]; offsetHelper = new OffsetHelper(max_packets,packetLength); + rollOverHelper = new RollOverHelper(max_packets); } @@ -346,6 +348,9 @@ private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOE int bytes_read = 0; int lastHandledSyncErrorPacket = -1; final byte[] buf = new byte[AVCHD_PACKET_LENGTH]; + + int lastArrivalTimeStamp = Integer.MAX_VALUE; + long currentRollOver = -1L; do { final long offset = fileStream.getPosition(); bytes_read = fileStream.read(buf, 0, AVCHD_PACKET_LENGTH); @@ -358,7 +363,14 @@ private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOE fileStream.unread(nextBytes,0,next); } offsetHelper.addPacket(no_packets, offset); - processPacket(new AVCHDPacket(buf, count, this,0)); + final AVCHDPacket packet = new AVCHDPacket(buf, count, this,currentRollOver); + if(packet.getArrivalTimestamp() rangeHashMap = new RangeHashMap<>(); diff --git a/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java b/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java new file mode 100644 index 00000000..3fdd3382 --- /dev/null +++ b/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java @@ -0,0 +1,65 @@ +/** + * + * 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.util; + +/** + * Keeps track of at roll-over for AVCHD packets (192 bytes) + */ +public class RollOverHelper { + + private RangeHashMap rangeHashMap = new RangeHashMap<>(); + private int maxPackets = -1; + + RangeHashMap.Entry currentEntry = null; + + public RollOverHelper(int max_packets) { + this.maxPackets = max_packets; + } + + public void addPacket(int packetNo, long rollOver) { + if(currentEntry == null){ + currentEntry = rangeHashMap.new Entry(0,maxPackets, rollOver); + rangeHashMap.put(0, currentEntry); + }else if(currentEntry.getValue() != rollOver){ + currentEntry.setUpper(packetNo - 1); + currentEntry = rangeHashMap.new Entry(packetNo, maxPackets, rollOver); + rangeHashMap.put(packetNo, currentEntry); + } + } + + public int getMaxPacket() { + return maxPackets; + } + + public long getRollOver(int packetNo) { + RangeHashMap.Entry entry = rangeHashMap.findEntry(packetNo); + return entry.getValue(); + } + + +} From 4301b648be7eb49b67f5f2cc318783bdc48a15b1 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Wed, 3 Jul 2024 23:00:46 +0200 Subject: [PATCH 06/23] TimeStampChart handles AVCHD stream correct, PCR is a straight line --- .../data/mpeg/AVCHDPacket.java | 27 +++++++++++++++---- .../digitalekabeltelevisie/data/mpeg/PID.java | 10 +++---- .../data/mpeg/TSPacket.java | 6 +++++ .../data/mpeg/TimeStamp.java | 2 +- .../data/mpeg/TransportStream.java | 24 ++++++++++------- .../digitalekabeltelevisie/gui/PIDDialog.java | 21 ++++++++++++--- .../gui/PacketSelectionPanel.java | 17 ++---------- .../gui/TimeStampChart.java | 17 ++++++++++-- .../gui/utils/TimestampXYDataset.java | 18 ++++++++----- .../main/DVBinspector.java | 2 ++ 10 files changed, 96 insertions(+), 48 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index e652397f..ff78bd84 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -74,10 +74,8 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { final DefaultMutableTreeNode tpHeaderNode = new DefaultMutableTreeNode(new KVP("tp_extra_header",tp_extra_header,null)); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Copy_permission_indicator",getCopyPermissionIndicator(),null))); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Roll-over",roll_over,null))); - final int arrivalTimestamp = getArrivalTimestamp(); - long cats = (roll_over * bit30) + arrivalTimestamp; - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",arrivalTimestamp,printPCRTime(arrivalTimestamp)))); - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Continuos ATS ",cats,printPCRTime(cats)))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",getArrivalTimestamp(),printPCRTime(getArrivalTimestamp())))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Continuous ATS ",getTimeBase(),printPCRTime(getTimeBase())))); t.add(tpHeaderNode); addMainPacketDetails(modus, t); return t; @@ -107,7 +105,15 @@ public String getHTML() { s.append("
Copy_permission_indicator: ").append(getCopyPermissionIndicator()); s.append("
roll-over: ").append(roll_over); - s.append("
Arrival_time_stamp: ").append(getArrivalTimestamp()).append(" (").append(printPCRTime(getArrivalTimestamp())).append(")").append("
"); + s.append("
Arrival_time_stamp: ").append(getArrivalTimestamp()).append(" (").append(printPCRTime(getArrivalTimestamp())).append(")"); + s.append("
Continuous ATS: ").append(getTimeBase()).append(" (").append(printPCRTime(getTimeBase())).append(")"); + int lowBits = getInt(tp_extra_header,0,4,MASK_9BITS); + s.append("
lowBits: ").append(lowBits); + if(lowBits >299) { + s.append("

lowBits > 299

"); + } + + s.append("
"); addBasicPacketDetails(s, 4, coloring); @@ -130,5 +136,16 @@ public void setRoll_over(long roll_over) { this.roll_over = roll_over; } + + /** + * for AVCHD file time corresponds to TP_header ATS (plus roll over + */ + + // TODO implement quirks mode for Humax, where last 9 bitss only use values 0-299 (like PCR) + @Override + public long getTimeBase() { + return (roll_over * bit30) + getArrivalTimestamp(); + } + } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java index 56faeb0c..218b5d79 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java @@ -224,10 +224,10 @@ private void startPesPacket(final TSPacket packet, final PID parentPID) { final int pts_dts_flags = pesHeader.getPts_dts_flags(); if ((pts_dts_flags == 2) || (pts_dts_flags == 3)) { // PTS present, - ptsList.add(new TimeStamp(packet.getPacketNo(), pesHeader.getPts())); + ptsList.add(new TimeStamp(packet.getTimeBase(), pesHeader.getPts())); } if (pts_dts_flags == 3) { // DTS present, - dtsList.add(new TimeStamp(packet.getPacketNo(), pesHeader.getDts())); + dtsList.add(new TimeStamp(packet.getTimeBase(), pesHeader.getDts())); } } } catch (Exception e) { @@ -387,7 +387,7 @@ private AdaptationField handleAdaptationField(final TSPacket packet) { AdaptationField adaptationField; try{ adaptationField = packet.getAdaptationField(); - processAdaptationField(adaptationField,packet.getPacketNo()); + processAdaptationField(adaptationField,packet.getPacketNo(),packet.getTimeBase()); }catch(final RuntimeException re){ // might be some error in adaptation field, it is not well protected logger.log(Level.WARNING, "Error getting adaptationField", re); adaptationField = null; @@ -418,12 +418,12 @@ private void updateMegaFrameInitializationPacket(final TSPacket packet) { } - private void processAdaptationField(AdaptationField adaptationField, int packetNo) { + private void processAdaptationField(AdaptationField adaptationField, int packetNo, long timeBase) { processTEMI(adaptationField, temiList, packetNo); if (adaptationField.isPCR_flag()) { final PCR newPCR = adaptationField.getProgram_clock_reference(); if(PreferencesManager.isEnablePcrPtsView()) { - pcrList.add(new TimeStamp(packetNo, newPCR.getProgram_clock_reference_base())); + pcrList.add(new TimeStamp(timeBase, newPCR.getProgram_clock_reference_base())); } if ((firstPCR != null) && !adaptationField.isDiscontinuity_indicator()) { final long packetsDiff = packetNo - firstPCRpacketNo; diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java index b5b6e3fc..78412272 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TSPacket.java @@ -237,6 +237,12 @@ public int getPacketNo() { return packetNo; } + /** + * for CBR file time corresponds to packetNo + */ + public long getTimeBase() { + return packetNo; + } /** * @param packet_no */ diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TimeStamp.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TimeStamp.java index e48656b4..6f0c6adc 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TimeStamp.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TimeStamp.java @@ -26,7 +26,7 @@ */ package nl.digitalekabeltelevisie.data.mpeg; -public record TimeStamp(int packetNo, long time) { +public record TimeStamp(long x, long time) { } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index d483f3a2..15e0726b 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -299,7 +299,7 @@ public void parseStream(final java.awt.Component component) throws IOException { bitRate = -1; bitRateTDT = -1; - if(packetLength == AVCHD_PACKET_LENGTH) { + if(isAVCHD()) { readAVCHDPackets(fileStream); } else { readPackets(fileStream); @@ -1090,7 +1090,10 @@ private static String getFormattedTime(final Calendar now) { } public String getShortPacketTime(final long packetNo){ - String r = null; + + if(isAVCHD()) { + return Utils.printPCRTime(packetNo); + } if(getBitRate()!=-1){ //can't calculate time without a bitrate Calendar now; @@ -1103,12 +1106,14 @@ public String getShortPacketTime(final long packetNo){ } 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 = 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)); + 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)); - }else{ // no bitrate - r = packetNo +" (packetNo)"; - } - return r; + } // no bitrate + return packetNo +" (packetNo)"; + } + + public boolean isAVCHD() { + return packetLength == AVCHD_PACKET_LENGTH; } public PMTsection getPMTforPID(final int thisPID) { @@ -1143,13 +1148,12 @@ private TSPacket readPacket(final int packetNo, final RandomAccessFile randomAcc throws IOException { TSPacket packet = null; final long offset = offsetHelper.getOffset(packetNo); - long rollOver = rollOverHelper.getRollOver(packetNo); randomAccessFile.seek(offset); final byte [] buf = new byte[packetLength]; final int bytesRead = randomAccessFile.read(buf); if(bytesRead==packetLength){ - if(packetLength == AVCHD_PACKET_LENGTH) { - packet = new AVCHDPacket(buf, packetNo,this,rollOver); + if(isAVCHD()) { + packet = new AVCHDPacket(buf, packetNo,this,rollOverHelper.getRollOver(packetNo)); }else { packet = new TSPacket(buf, packetNo,this); } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java index 23d8b2c3..390b85b6 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java @@ -125,7 +125,8 @@ public AddAllAction(final String text) { super(text); } - public void actionPerformed(final ActionEvent e) { + @Override + public void actionPerformed(final ActionEvent e) { final Enumeration el = leftListModel.elements(); while(el.hasMoreElements()){ rightListModel.addElement(el.nextElement()); @@ -144,6 +145,7 @@ public AddAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = leftList.getSelectedIndex(); @@ -169,6 +171,7 @@ class SwitchAction extends AbstractAction { public SwitchAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final DefaultListModel tmp = leftListModel; leftListModel = rightListModel; @@ -190,6 +193,7 @@ public RemoveAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -218,6 +222,7 @@ public RemoveAllAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final Enumeration el = rightListModel.elements(); while(el.hasMoreElements()){ @@ -237,6 +242,7 @@ public UpAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -260,6 +266,7 @@ public TopAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -283,6 +290,7 @@ public ReverseAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -311,6 +319,7 @@ public DownAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -335,6 +344,7 @@ public BottomAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final int index = rightList.getSelectedIndex(); @@ -358,6 +368,7 @@ public ApplyAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { final List shown = new ArrayList<>(); @@ -413,6 +424,7 @@ public CancelAction(final String text) { super(text); } + @Override public void actionPerformed(final ActionEvent e) { clearAndHide(); @@ -558,8 +570,8 @@ public PIDDialog(final Frame aFrame, final ViewContext viewContext, final DVBins pidPanel.add(sortButtonPanel); pidPanel.add(Box.createRigidArea(new Dimension(10, 10))); - packetSelectionStart = new PacketSelectionPanel("Start", 0, viewContext.getMaxPacket(), 0,viewContext.getTransportStream()); - packetSelectionEnd = new PacketSelectionPanel("End",0, viewContext.getMaxPacket(), viewContext.getMaxPacket(),viewContext.getTransportStream()); + packetSelectionStart = new PacketSelectionPanel("Start packet", 0, viewContext.getMaxPacket(), 0); + packetSelectionEnd = new PacketSelectionPanel("End packet",0, viewContext.getMaxPacket(), viewContext.getMaxPacket()); packetPanel.setLayout(new BoxLayout(packetPanel, BoxLayout.Y_AXIS)); packetPanel.add(packetSelectionStart); @@ -607,6 +619,7 @@ public void windowClosing(final WindowEvent we) { } /** This method handles events for the steps choosr field. */ + @Override public void actionPerformed(final ActionEvent e) { // EMPTY @@ -615,11 +628,13 @@ public void actionPerformed(final ActionEvent e) { + @Override public void propertyChange(final PropertyChangeEvent evt) { enableButtons(); } + @Override public void valueChanged(final ListSelectionEvent e) { enableButtons(); diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java b/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java index 20f576a5..4e3ee356 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2012 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. * @@ -38,7 +38,6 @@ import javax.swing.BoxLayout; import javax.swing.DefaultBoundedRangeModel; import javax.swing.JFormattedTextField; -import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; @@ -63,19 +62,15 @@ public class PacketSelectionPanel extends JPanel implements private JSlider slider; private BoundedRangeModel boundedRangeModel; - private final JLabel timeLabel = new JLabel(); private NumberFormat numberFormat; - private TransportStream transportStream; - PacketSelectionPanel( final String myTitle, final int low, final int upper, final int value, final TransportStream tStream) { + PacketSelectionPanel( final String myTitle, final int low, final int upper, final int value) { super(); setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder(myTitle), BorderFactory.createEmptyBorder(5,5,5,5))); - transportStream = tStream; - //Create the text field format, and then the text field. numberFormat = NumberFormat.getNumberInstance(); @@ -126,7 +121,6 @@ public Dimension getMaximumSize() { final JPanel timePanel = new JPanel(); timePanel.setLayout(new BoxLayout(timePanel, BoxLayout.PAGE_AXIS)); - timePanel.add(timeLabel); //Put everything together. setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); @@ -156,9 +150,6 @@ public void stateChanged(final ChangeEvent e) { formatter.setMinimum(min); formatter.setMaximum(max); textField.setValue(val); - if(transportStream!=null){ - timeLabel.setText(transportStream.getShortPacketTime(val)); - } } @@ -178,10 +169,6 @@ public void setRangeValue(final int min, final int max, final int val,final Tran slider.setMaximum(max); slider.setValue(val); textField.setValue(val); - transportStream = ts; - if(transportStream!=null){ - timeLabel.setText(transportStream.getShortPacketTime(val)); - } } public int getValue(){ diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/TimeStampChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/TimeStampChart.java index 2a3e4f73..ba7aa960 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/TimeStampChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/TimeStampChart.java @@ -171,6 +171,13 @@ public StringBuffer format(final double number, final StringBuffer toAppendTo, f private JCheckBox temiOptionCheckBox = new JCheckBox("enable"); private JPanel seriesSelectionPanel; + // TODO disable when packetsize == 192, means not CBR + + private JRadioButton timeButton; + // TODO disable when packetsize == 192, means not CBR + + private JRadioButton packetNoButton; + /** * Creates a new TimeStampChart @@ -252,6 +259,12 @@ public final void setTransportStream(final TransportStream transportStream, fina temiOptionCheckBox.setEnabled(false); }else{ + + timeButton.setEnabled(!transportStream.isAVCHD()); + packetNoButton.setEnabled(!transportStream.isAVCHD()); + if(transportStream.isAVCHD()) { + usepacketTime = true; + } final PMTs streamPmts = transportStream.getPsi().getPmts(); if(streamPmts.getPmts().isEmpty()){ chartPanel.setChart(GuiUtils.createTitleOnlyChart("No PMTs found, nothing to display in this graph")); @@ -471,7 +484,7 @@ private void addTEMIOption(JPanel temiPanel) { private void addTimePacketNoRadioButtons(JPanel buttonPanel) { final JLabel typeLabel = new JLabel("X-Axis:"); buttonPanel.add(typeLabel); - final JRadioButton timeButton = new JRadioButton("Time"); + timeButton = new JRadioButton("Time"); timeButton.addActionListener(e -> { if(!usepacketTime){ usepacketTime = true; @@ -480,7 +493,7 @@ private void addTimePacketNoRadioButtons(JPanel buttonPanel) { } } }); - final JRadioButton packetNoButton = new JRadioButton("Packet No."); + packetNoButton = new JRadioButton("Packet No."); packetNoButton.addActionListener(e -> { if(usepacketTime){ usepacketTime = false; diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/utils/TimestampXYDataset.java b/src/main/java/nl/digitalekabeltelevisie/gui/utils/TimestampXYDataset.java index eb801d7b..bbc5e3ef 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/utils/TimestampXYDataset.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/utils/TimestampXYDataset.java @@ -50,8 +50,8 @@ public class TimestampXYDataset implements XYDataset { ArrayList seriesOffset = new ArrayList<>(); ArrayList seriesViewContextLength = new ArrayList<>(); - int startPacket; - int endPacket; + long startPacket; + long endPacket; private static final Logger logger = Logger.getLogger(TimestampXYDataset.class.getName()); @@ -61,8 +61,12 @@ public TimestampXYDataset(PMTsection pmt, TransportStream transportStream, ViewC short pcrPid= (short)pmt.getPcrPid(); - startPacket = viewContext.getStartPacket(); - endPacket = viewContext.getEndPacket(); + int startPacketNo = viewContext.getStartPacket(); + int endPacketNo = viewContext.getEndPacket()-1; + + startPacket = transportStream.getTSPacket(startPacketNo).getTimeBase(); + endPacket = transportStream.getTSPacket(endPacketNo).getTimeBase() + 1; + if(transportStream.getPID(pcrPid)!=null){ // should not happen, however leave it up to UPC to fuck up... String pcrLabel = pcrPid+" - "+transportStream.getShortLabel(pcrPid)+" PCR"; @@ -150,7 +154,7 @@ private void addToSeriesList(final List list, String componentLabel) TimeStamp startKey = new TimeStamp(startPacket, 0); TimeStamp endKey = new TimeStamp(endPacket, Long.MAX_VALUE); Comparator comperator = Comparator - .comparingInt(TimeStamp::packetNo) + .comparingLong(TimeStamp::x) .thenComparingLong(TimeStamp::time); int startOffset = Collections.binarySearch(list, startKey, comperator); @@ -217,7 +221,7 @@ public int getItemCount(int series) { @Override public Number getX(int series, int item) { - return getTimestamp(series, item).packetNo(); + return getTimestamp(series, item).x(); } private TimeStamp getTimestamp(int series, int item) { @@ -226,7 +230,7 @@ private TimeStamp getTimestamp(int series, int item) { @Override public double getXValue(int series, int item) { - return getTimestamp(series, item).packetNo(); + return getTimestamp(series, item).x(); } @Override diff --git a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java index 5ba5cf3a..3848b17c 100644 --- a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java +++ b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java @@ -713,6 +713,7 @@ public void setPIDList(final ViewContext vContext){ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) */ + @Override public void stateChanged(final ChangeEvent e) { enableViewMenus(); } @@ -741,6 +742,7 @@ private void saveWindowState(){ * called when "exit" is selected in menu. * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ + @Override public void actionPerformed(final ActionEvent e) { saveWindowState(); System.exit(0); From bec6fbc12707ba33d6cd69f8cac2f3ff051b4f8b Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Thu, 4 Jul 2024 11:14:21 +0200 Subject: [PATCH 07/23] reverse loops, remove needless iteration over PIDs --- .../gui/BitRateChart.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java index 03549aca..aedb7963 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java @@ -198,27 +198,27 @@ private static XYPlot createXYPlot(final TransportStream transportStream, private static CategoryTableXYDataset createDataSet(final TransportStream transportStream, final ViewContext viewContext, final int noPIDs) { - final short[]used_pids=new short[noPIDs]; - final ChartLabel[] labels= new ChartLabel[noPIDs]; + final short[] used_pids = new short[noPIDs]; + final ChartLabel[] labels = new ChartLabel[noPIDs]; for (int i = 0; i < noPIDs; i++) { - labels[i]=viewContext.getShown().get(i); - used_pids[i]=viewContext.getShown().get(i).getPid(); + labels[i] = viewContext.getShown().get(i); + used_pids[i] = viewContext.getShown().get(i).getPid(); } - final int numberOfSteps=viewContext.getGraphSteps(); + final int numberOfSteps = viewContext.getGraphSteps(); final CategoryTableXYDataset categoryTableXYDataset = new CategoryTableXYDataset(); - for (int pidIndex = 0; pidIndex < used_pids.length; pidIndex++) { - for(int step=0; step startPacketStep) { - categoryTableXYDataset.add(startPacketStep,((pidcount[used_pids[pidIndex]])*transportStream.getBitRate()) / (endPacketStep - startPacketStep),labels[pidIndex].getLabel()); + categoryTableXYDataset.add(startPacketStep, ((pidcount[used_pids[pidIndex]]) * transportStream.getBitRate()) / (endPacketStep - startPacketStep), labels[pidIndex].getLabel()); } } } @@ -231,8 +231,7 @@ private static CategoryTableXYDataset createDataSet(final TransportStream transp * @param endPacketStep * @return */ - private static int[] countPidOccurrencesInStep(final TransportStream transportStream, final int startPacketStep, - final int endPacketStep) { + private static int[] countPidOccurrencesInStep(final TransportStream transportStream, final int startPacketStep, final int endPacketStep) { final int [] pidcount = new int [8192]; for(int r = startPacketStep; r< endPacketStep;r++ ){ final int pid_current_packet=transportStream.getPacket_pid(r); From 29abff86f426a317c7ad98728f9a47b30a1b4f5a Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Thu, 4 Jul 2024 13:44:12 +0200 Subject: [PATCH 08/23] refactor determining interval boundaries --- .../digitalekabeltelevisie/gui/BitRateChart.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java index aedb7963..8ae3139d 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java @@ -208,10 +208,9 @@ private static CategoryTableXYDataset createDataSet(final TransportStream transp final CategoryTableXYDataset categoryTableXYDataset = new CategoryTableXYDataset(); + int startPacketStep = getFirstPacketNoOfStep(viewContext, 0); for (int step = 0; step < numberOfSteps; step++) { - - final int startPacketStep = getFirstPacketNoOfStep(viewContext, numberOfSteps, step); - final int endPacketStep = getFirstPacketNoOfStep(viewContext, numberOfSteps, step + 1); + final int endPacketStep = getFirstPacketNoOfStep(viewContext, step + 1); final int[] pidcount = countPidOccurrencesInStep(transportStream, startPacketStep, endPacketStep); for (int pidIndex = 0; pidIndex < used_pids.length; pidIndex++) { @@ -221,6 +220,7 @@ private static CategoryTableXYDataset createDataSet(final TransportStream transp categoryTableXYDataset.add(startPacketStep, ((pidcount[used_pids[pidIndex]]) * transportStream.getBitRate()) / (endPacketStep - startPacketStep), labels[pidIndex].getLabel()); } } + startPacketStep = endPacketStep; } return categoryTableXYDataset; } @@ -246,9 +246,11 @@ private static int[] countPidOccurrencesInStep(final TransportStream transportSt * @param step * @return */ - private static int getFirstPacketNoOfStep(final ViewContext viewContext, - final int steps, final int step) { - return viewContext.getStartPacket() +(int)(((long)step*(long)(viewContext.getEndPacket() - viewContext.getStartPacket()))/steps); + private static int getFirstPacketNoOfStep(final ViewContext viewContext, final int step) { + + int steps = viewContext.getGraphSteps(); + final long packetsInSelectedRange = viewContext.getEndPacket() - viewContext.getStartPacket(); + return viewContext.getStartPacket() + (int) ((step * packetsInSelectedRange) / steps); } private void addLegendRadioButtons() { From 48d8e3c4cab9423c6a4ec65b26d53d8f2d461430 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Fri, 5 Jul 2024 12:22:41 +0200 Subject: [PATCH 09/23] add packetATS as helper for arrival time AVCHD Packets --- .../data/mpeg/AVCHDPacket.java | 14 +++++++---- .../data/mpeg/TransportStream.java | 24 +++++++++++++++++-- .../gui/BitRateChart.java | 13 +++++----- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index ff78bd84..56de12a3 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -43,13 +43,16 @@ */ public class AVCHDPacket extends TSPacket { - static final int bit30 = 0x4000_0000; byte[] tp_extra_header; + // TODO remove, the rollOverHelper In ts can handle all that is needed. long roll_over; + + int arrivalTimestamp; public AVCHDPacket(byte[] buf, int no, TransportStream ts, long roll_over) { super(Arrays.copyOfRange(buf,4,192), no, ts); tp_extra_header = Arrays.copyOf(buf,4); + arrivalTimestamp = getInt(tp_extra_header,0,4,MASK_30BITS); this.roll_over = roll_over; } @@ -63,7 +66,7 @@ public int getCopyPermissionIndicator() { } public int getArrivalTimestamp() { - return getInt(tp_extra_header,0,4,MASK_30BITS); + return arrivalTimestamp; } @@ -74,7 +77,7 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { final DefaultMutableTreeNode tpHeaderNode = new DefaultMutableTreeNode(new KVP("tp_extra_header",tp_extra_header,null)); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Copy_permission_indicator",getCopyPermissionIndicator(),null))); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Roll-over",roll_over,null))); - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",getArrivalTimestamp(),printPCRTime(getArrivalTimestamp())))); + tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",arrivalTimestamp,printPCRTime(arrivalTimestamp)))); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Continuous ATS ",getTimeBase(),printPCRTime(getTimeBase())))); t.add(tpHeaderNode); addMainPacketDetails(modus, t); @@ -144,8 +147,11 @@ public void setRoll_over(long roll_over) { // TODO implement quirks mode for Humax, where last 9 bitss only use values 0-299 (like PCR) @Override public long getTimeBase() { - return (roll_over * bit30) + getArrivalTimestamp(); + return transportStream.getAVCHDPacketTime(packetNo); } + public String toString() { + return super.toString() + " , arrivalTimestamp: "+arrivalTimestamp + " , roll_over: " + roll_over; + } } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 15e0726b..34d6d6f7 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -155,6 +155,7 @@ 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 OffsetHelper offsetHelper = null; private RollOverHelper rollOverHelper = null; @@ -216,6 +217,9 @@ public TransportStream(final File file) throws NotAnMPEGFileException,IOExceptio packetLength = determinePacketLengthToUse(file); int max_packets = (int) (len / packetLength); packet_pid = new short [max_packets]; + if(isAVCHD()) { + packetATS = new int [max_packets]; + } offsetHelper = new OffsetHelper(max_packets,packetLength); rollOverHelper = new RollOverHelper(max_packets); @@ -364,12 +368,14 @@ private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOE } offsetHelper.addPacket(no_packets, offset); final AVCHDPacket packet = new AVCHDPacket(buf, count, this,currentRollOver); - if(packet.getArrivalTimestamp() Date: Fri, 5 Jul 2024 15:32:27 +0200 Subject: [PATCH 10/23] BitRateChart can now handle AVCHD streams --- .../data/mpeg/MPEGConstants.java | 4 +- .../data/mpeg/TransportStream.java | 8 +- .../gui/BitRateChart.java | 80 ++++++++++++++++--- 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java index ab67aea2..139c9f03 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java @@ -28,7 +28,6 @@ package nl.digitalekabeltelevisie.data.mpeg; public final class MPEGConstants { - /** * */ @@ -37,6 +36,9 @@ private MPEGConstants() { } public final static byte sync_byte=0x47; public final static int PAYLOAD_PACKET_LENGTH=188; + + public final static int AVCHD_PACKET_LENGTH = 192; + public final static int system_clock_frequency=27000000; public final static int NO_PCR_PID=0x1FFF; } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 34d6d6f7..e56a5125 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -27,6 +27,7 @@ package nl.digitalekabeltelevisie.data.mpeg; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.sync_byte; import static nl.digitalekabeltelevisie.data.mpeg.descriptors.Descriptor.findGenericDescriptorsInList; import static nl.digitalekabeltelevisie.util.Utils.df2pos; @@ -101,8 +102,6 @@ */ public class TransportStream implements TreeNode{ - private static final int AVCHD_PACKET_LENGTH = 192; - public enum ComponentType{ AC3("Dolby Audio (AC3)"), E_AC3("Enhanced Dolby Audio (AC3)"), @@ -1241,7 +1240,8 @@ public boolean isONTSection(int pid) { } public int getFirstAvchdPacketATS() { - return packetATS[0]; + return packetATS[0]; } - + + } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java index 8d3e1942..e4e01db2 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java @@ -27,6 +27,8 @@ package nl.digitalekabeltelevisie.gui; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; + import java.awt.BorderLayout; import java.text.FieldPosition; import java.text.NumberFormat; @@ -39,6 +41,7 @@ import nl.digitalekabeltelevisie.controller.ChartLabel; import nl.digitalekabeltelevisie.controller.ViewContext; +import nl.digitalekabeltelevisie.data.mpeg.MPEGConstants; import nl.digitalekabeltelevisie.data.mpeg.TransportStream; import nl.digitalekabeltelevisie.gui.utils.GuiUtils; @@ -141,8 +144,13 @@ public final void setTransportStream(final TransportStream transportStream, fina freeChart = null; chartPanel.setChart(GuiUtils.createTitleOnlyChart(GuiUtils.NO_TRANSPORTSTREAM_LOADED)); }else{ - - final CategoryTableXYDataset categoryTableXYDataset = createDataSet(transportStream, viewContext); + CategoryTableXYDataset categoryTableXYDataset; + + if(transportStream.isAVCHD()) { + categoryTableXYDataset = createAvchdDataSet(transportStream, viewContext); + }else { + categoryTableXYDataset = createCbrDataSet(transportStream, viewContext); + } //because we want custom colors, can not use ChartFactory.createStackedXYAreaChart(, this is almost literal copy final XYPlot plot = createXYPlot(transportStream, viewContext, categoryTableXYDataset); @@ -195,16 +203,12 @@ private static XYPlot createXYPlot(final TransportStream transportStream, * @param noPIDs * @return */ - private static CategoryTableXYDataset createDataSet(final TransportStream transportStream, + private static CategoryTableXYDataset createCbrDataSet(final TransportStream transportStream, final ViewContext viewContext) { final int noPIDs=viewContext.getShown().size(); - final short[] used_pids = new short[noPIDs]; - final ChartLabel[] labels = new ChartLabel[noPIDs]; - for (int i = 0; i < noPIDs; i++) { - labels[i] = viewContext.getShown().get(i); - used_pids[i] = viewContext.getShown().get(i).getPid(); - } + final short[] used_pids = createUsedPidsArray(viewContext, noPIDs); + final ChartLabel[] labels = createChartLabels(viewContext, noPIDs); final int numberOfSteps = viewContext.getGraphSteps(); final CategoryTableXYDataset categoryTableXYDataset = new CategoryTableXYDataset(); @@ -226,6 +230,22 @@ private static CategoryTableXYDataset createDataSet(final TransportStream transp return categoryTableXYDataset; } + private static short[] createUsedPidsArray(final ViewContext viewContext, final int noPIDs) { + final short[] used_pids = new short[noPIDs]; + for (int i = 0; i < noPIDs; i++) { + used_pids[i] = viewContext.getShown().get(i).getPid(); + } + return used_pids; + } + + private static ChartLabel[] createChartLabels(final ViewContext viewContext, final int noPIDs) { + final ChartLabel[] labels = new ChartLabel[noPIDs]; + for (int i = 0; i < noPIDs; i++) { + labels[i] = viewContext.getShown().get(i); + } + return labels; + } + /** * @param transportStream * @param startPacketStep @@ -284,5 +304,47 @@ private void addLegendRadioButtons() { buttonPanel.add(offButton); } + /** + * @param transportStream + * @param viewContext + * @param noPIDs + * @return + */ + private static CategoryTableXYDataset createAvchdDataSet(final TransportStream transportStream, + final ViewContext viewContext) { + + final int noPIDs=viewContext.getShown().size(); + final short[] used_pids = createUsedPidsArray(viewContext, noPIDs); + final ChartLabel[] labels = createChartLabels(viewContext, noPIDs); + final int numberOfSteps = viewContext.getGraphSteps(); + + final CategoryTableXYDataset categoryTableXYDataset = new CategoryTableXYDataset(); + + long startSelectionTime = transportStream.getAVCHDPacketTime(viewContext.getStartPacket()); + long endSelectionTime = transportStream.getAVCHDPacketTime(viewContext.getEndPacket() - 1); + long selectionDuration = endSelectionTime - startSelectionTime; + + int packetIndex = viewContext.getStartPacket(); + long startStepPacketTime = startSelectionTime; + for (int step = 0; step < numberOfSteps; step++) { + final long endStepPacketTime = startSelectionTime + (selectionDuration * (step + 1) / numberOfSteps); + final int [] pidcount = new int [8192]; + while(packetIndex< viewContext.getEndPacket() && transportStream.getAVCHDPacketTime(packetIndex) <= endStepPacketTime) { + final int pid_current_packet=transportStream.getPacket_pid(packetIndex); + pidcount[pid_current_packet]++; + packetIndex++; + } + + for (int pidIndex = 0; pidIndex < used_pids.length; pidIndex++) { + if (endStepPacketTime > startStepPacketTime) { + final long bitRate = ((pidcount[used_pids[pidIndex]]) * (long) MPEGConstants.system_clock_frequency) * 8 * AVCHD_PACKET_LENGTH / (endStepPacketTime - startStepPacketTime) ; + categoryTableXYDataset.add(startStepPacketTime, bitRate, labels[pidIndex].getLabel()); + } + } + startStepPacketTime = endStepPacketTime; + } + return categoryTableXYDataset; + } + } From efc3c9bbf6ab913523523dfd3be607d9a96e5284 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Fri, 5 Jul 2024 18:51:24 +0200 Subject: [PATCH 11/23] packet No is always int --- src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java index 218b5d79..7b0c1790 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/PID.java @@ -106,8 +106,8 @@ private record ContinuityError(int lastPacketNo, int lastCCounter, int newPacket private int dup_found=0; // number of times current packet is duplicated. private PCR lastPCR; private PCR firstPCR; - private long lastPCRpacketNo = -1; - private long firstPCRpacketNo =-1; + private int lastPCRpacketNo = -1; + private int firstPCRpacketNo =-1; private long pcr_count =-1; protected TransportStream parentTransportStream = null; From 96a42fd92c53b71001809df7380f6b0e650e3f10 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Fri, 5 Jul 2024 19:39:11 +0200 Subject: [PATCH 12/23] AVCHD support for repetition rate in TableSection --- .../data/mpeg/AVCHDPacket.java | 2 +- .../data/mpeg/TransportStream.java | 35 ++++--------- .../data/mpeg/psi/AbstractPSITabel.java | 12 ++++- .../data/mpeg/psi/TableSection.java | 51 ++++++++++++------- 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index 56de12a3..53e71bda 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -92,7 +92,7 @@ public String getHTML() { s.append("
File Offset: ").append(packetOffset); } if(transportStream!=null){ - //s.append("
Time: ").append(transportStream.getPacketTime(packetNo)); + s.append("
Time: ").append(transportStream.getPacketTime(packetNo)); final short pid = transportStream.getPacket_pid(packetNo); s.append("
").append(escapeHtmlBreakLines(transportStream.getShortLabel(pid))).append("
"); } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index e56a5125..94c3e8e8 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -30,26 +30,10 @@ import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.sync_byte; import static nl.digitalekabeltelevisie.data.mpeg.descriptors.Descriptor.findGenericDescriptorsInList; -import static nl.digitalekabeltelevisie.util.Utils.df2pos; -import static nl.digitalekabeltelevisie.util.Utils.df3pos; -import static nl.digitalekabeltelevisie.util.Utils.getStreamTypeShortString; -import static nl.digitalekabeltelevisie.util.Utils.getUTCCalender; -import static nl.digitalekabeltelevisie.util.Utils.psiOnlyModus; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.TreeSet; +import static nl.digitalekabeltelevisie.util.Utils.*; + +import java.io.*; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -79,12 +63,8 @@ import nl.digitalekabeltelevisie.data.mpeg.pes.video265.H265Handler; import nl.digitalekabeltelevisie.data.mpeg.pes.video266.H266Handler; import nl.digitalekabeltelevisie.data.mpeg.pid.t2mi.T2miPidHandler; -import nl.digitalekabeltelevisie.data.mpeg.psi.GeneralPSITable; -import nl.digitalekabeltelevisie.data.mpeg.psi.NIT; -import nl.digitalekabeltelevisie.data.mpeg.psi.PMTs; -import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection; +import nl.digitalekabeltelevisie.data.mpeg.psi.*; import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection.Component; -import nl.digitalekabeltelevisie.data.mpeg.psi.TDTsection; import nl.digitalekabeltelevisie.data.mpeg.psi.handler.GeneralPsiTableHandler; import nl.digitalekabeltelevisie.data.mpeg.psi.nonstandard.M7Fastscan; import nl.digitalekabeltelevisie.data.mpeg.psi.nonstandard.ONTSection; @@ -1053,8 +1033,11 @@ public double getLength(){ } } - public String getPacketTime(final long packetNo){ + public String getPacketTime(final int packetNo){ String r = null; + if(isAVCHD()) { + return Utils.printPCRTime(getAVCHDPacketTime(packetNo)); + } if(getBitRate()!=-1){ //can't calculate time without a bitrate if(zeroTime==null){ diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/AbstractPSITabel.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/AbstractPSITabel.java index dd4a75d0..b44669d7 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/AbstractPSITabel.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/AbstractPSITabel.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2022 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. * @@ -31,6 +31,7 @@ import nl.digitalekabeltelevisie.controller.TreeNode; import nl.digitalekabeltelevisie.data.mpeg.PSI; +import nl.digitalekabeltelevisie.data.mpeg.TransportStream; public abstract class AbstractPSITabel implements TreeNode{ @@ -56,6 +57,7 @@ public void setParentPSI(final PSI parentPSI) { * @param modus */ public static void addSectionVersionsToJTree(final DefaultMutableTreeNode n, final TableSection tableSection, final int modus) { + n.add(tableSection.getJTreeNode(modus)); TableSection versions = tableSection.getNextVersion(); while(versions!=null){ // even show new versions @@ -81,7 +83,13 @@ public static TableSection updateSectionVersion(final TableSection newSection, f } if(last.equals(newSection)){ // already have an instance if this section, just update the stats on the existing section int previousPacketNo = last.getLast_packet_no(); - int distance = newSection.getPacket_no() - previousPacketNo; + TransportStream transportStream = newSection.getParentTransportStream(); + long distance ; + if(newSection.getParentTransportStream().isAVCHD()) { + distance = transportStream.getAVCHDPacketTime(newSection.getPacket_no()) - transportStream.getAVCHDPacketTime(previousPacketNo); + }else { + distance = newSection.getPacket_no() - previousPacketNo; + } if(distance>last.getMaxPacketDistance()){ last.setMaxPacketDistance(distance); } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/TableSection.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/TableSection.java index 85a47055..48403632 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/TableSection.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/psi/TableSection.java @@ -36,10 +36,7 @@ import nl.digitalekabeltelevisie.controller.KVP; import nl.digitalekabeltelevisie.controller.TreeNode; -import nl.digitalekabeltelevisie.data.mpeg.CRCcheck; -import nl.digitalekabeltelevisie.data.mpeg.PID; -import nl.digitalekabeltelevisie.data.mpeg.PSI; -import nl.digitalekabeltelevisie.data.mpeg.PsiSectionData; +import nl.digitalekabeltelevisie.data.mpeg.*; import nl.digitalekabeltelevisie.data.mpeg.TransportStream; import nl.digitalekabeltelevisie.util.Utils; @@ -80,8 +77,14 @@ public class TableSection implements TreeNode{ private int firstPacketNo=-1; private int lastPacketNo=-1; - private int minPacketDistance = Integer.MAX_VALUE; - private int maxPacketDistance = 0; + /** + * min distance between packets, in packets for CBR, in system_ ticks for AVCHD + */ + private long minPacketDistance = Long.MAX_VALUE; + /** + * max distance between packets, in packets for CBR, in system_ ticks for AVCHD + */ + private long maxPacketDistance = 0; private int occurrenceCount=-1; private int packetNo=-1; @@ -403,10 +406,18 @@ protected void addTableDetails(final int modus, final DefaultMutableTreeNode t) t.add(new DefaultMutableTreeNode(new KVP("occurrence_count", occurrenceCount, getRepetitionRate(occurrenceCount, lastPacketNo, firstPacketNo)))); if (occurrenceCount >= 2) { - t.add(new DefaultMutableTreeNode( - new KVP("min_packet_distance", minPacketDistance, getDistanceSecs(minPacketDistance)))); - t.add(new DefaultMutableTreeNode( - new KVP("max_packet_distance", maxPacketDistance, getDistanceSecs(maxPacketDistance)))); + if(getParentTransportStream().isAVCHD()) { + t.add(new DefaultMutableTreeNode( + new KVP("min_packet_distance in ticks", minPacketDistance, printPCRTime(minPacketDistance) ))); + t.add(new DefaultMutableTreeNode( + new KVP("max_packet_distance in ticks", maxPacketDistance, printPCRTime(maxPacketDistance)))); + + }else { + t.add(new DefaultMutableTreeNode( + new KVP("min_packet_distance in packets", minPacketDistance, getDistanceSecs(minPacketDistance)))); + t.add(new DefaultMutableTreeNode( + new KVP("max_packet_distance in packets", maxPacketDistance, getDistanceSecs(maxPacketDistance)))); + } } } t.add(new DefaultMutableTreeNode(new KVP("table_id", tableId, getTableType(tableId)))); @@ -452,7 +463,13 @@ private String getRepetitionRate(final int count,final int last, final int firs TransportStream parentTransportStream = getParentPID().getParentTransportStream(); final long bitrate=parentTransportStream.getBitRate(); if((bitrate>0)&&(count>=2)){ - final float repRate=((float)(last-first)*parentTransportStream.getPacketLenghth()*8)/((count-1)*bitrate); + float repRate; + if(parentTransportStream.isAVCHD()) { + final long timeDiff = parentTransportStream.getAVCHDPacketTime(last) - parentTransportStream.getAVCHDPacketTime(first); + repRate = ((float) timeDiff) / MPEGConstants.system_clock_frequency / (count - 1); + }else { + repRate = ((float)(last-first)*parentTransportStream.getPacketLenghth()*8)/((count-1)*bitrate); + } try (Formatter formatter = new Formatter()){ return "repetition rate: "+formatter.format("%3.3f seconds",repRate); } @@ -460,11 +477,11 @@ private String getRepetitionRate(final int count,final int last, final int firs return null; } - private String getDistanceSecs(final long last) { + private String getDistanceSecs(final long distanceInPackets) { TransportStream parentTransportStream = getParentPID().getParentTransportStream(); final long bitrate=parentTransportStream.getBitRate(); if(bitrate>0){ - final float repRate=((float)(last)*parentTransportStream.getPacketLenghth()*8)/(bitrate); + final float repRate=((float)(distanceInPackets)*parentTransportStream.getPacketLenghth()*8)/(bitrate); try (Formatter formatter = new Formatter()){ return "interval: "+formatter.format("%3.3f seconds",repRate); } @@ -593,19 +610,19 @@ public boolean equals(final Object obj) { return raw_data.equals(other.raw_data); } - public int getMinPacketDistance() { + public long getMinPacketDistance() { return minPacketDistance; } - public void setMinPacketDistance(int minPacketDistance) { + public void setMinPacketDistance(long minPacketDistance) { this.minPacketDistance = minPacketDistance; } - public int getMaxPacketDistance() { + public long getMaxPacketDistance() { return maxPacketDistance; } - public void setMaxPacketDistance(int maxPacketDistance) { + public void setMaxPacketDistance(long maxPacketDistance) { this.maxPacketDistance = maxPacketDistance; } From 0a41a09215998f7d6797baea2747eb04f553fef8 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sat, 6 Jul 2024 12:36:17 +0200 Subject: [PATCH 13/23] add fix for Humax ATS quirk, make configurable in GUI --- .../data/mpeg/TransportStream.java | 36 +++++++++++-- .../gui/EnableHumaxAtsFixAction.java | 50 +++++++++++++++++++ .../main/DVBinspector.java | 4 ++ .../util/PreferencesManager.java | 20 ++++++-- 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 94c3e8e8..915da8b6 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -138,6 +138,11 @@ public String getDescription() { private OffsetHelper offsetHelper = null; private RollOverHelper rollOverHelper = null; + + /** + * Get value once at creation of TS, because getting it for every call to getAVCHDPacketTime is a bit expensive + */ + private static boolean enabledHumaxAtsFix = false; /** * Starting point for all the PSI information in this TransportStream */ @@ -198,6 +203,7 @@ public TransportStream(final File file) throws NotAnMPEGFileException,IOExceptio packet_pid = new short [max_packets]; if(isAVCHD()) { packetATS = new int [max_packets]; + enabledHumaxAtsFix = PreferencesManager.isEnableHumaxAtsFix(); } offsetHelper = new OffsetHelper(max_packets,packetLength); rollOverHelper = new RollOverHelper(max_packets); @@ -1154,14 +1160,36 @@ private TSPacket readPacket(final int packetNo, final RandomAccessFile randomAcc } - // TODO implement quirks mode for Humax, where last 9 bitss only use values 0-299 (like PCR) - + /** + * returns time (in system ticks) for packet, starting from 0 for begin of file, based on ATS in TP_extra_header + * Only to be called for an AVCHD file + */ public long getAVCHDPacketTime(int packetNo) { - if(isAVCHD() && packetATS != null) { - return (rollOverHelper.getRollOver(packetNo) * 0x4000_0000) + packetATS[packetNo] - packetATS[0]; + if (isAVCHD() && packetATS != null) { + if (enabledHumaxAtsFix) { + return (rollOverHelper.getRollOver(packetNo) * ((0x4000_0000 >> 9) + 1) * 300) + + fixHumaxAts(packetATS[packetNo]) - fixHumaxAts(packetATS[0]); + } + return (rollOverHelper.getRollOver(packetNo) * 0x4000_0000) + packetATS[packetNo] - packetATS[0]; } throw new RuntimeException("Not an AVCHD File!"); } + + /** + * Humax PVR records partial TS with arrival time stamps in P_extra_header coded as if PCR; + * the last 9 bits are the extension, and have values 0 - 299. + * Then it roles over into the base. + * This method corrects the Humax ATS into a normal ATS + * + * Normal AVCHD files use continuous numbering with 30 bits + * + */ + private static int fixHumaxAts(int ats) { + int extension = ats & 0b1_1111_1111; // 9 bits + int base = (ats & 0x3FFF_FE00) >> 9; + + return base * 300 + extension; + } public PID getPID(final int p){ return pids[p]; diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java b/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java new file mode 100644 index 00000000..88c0cd7f --- /dev/null +++ b/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java @@ -0,0 +1,50 @@ +/** + * + * 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.gui; + +import java.awt.event.ActionEvent; + +import javax.swing.JCheckBoxMenuItem; + +import nl.digitalekabeltelevisie.main.DVBinspector; +import nl.digitalekabeltelevisie.util.PreferencesManager; + +public class EnableHumaxAtsFixAction extends AbstractSetPreferenceAction { + + public EnableHumaxAtsFixAction(final DVBinspector controller) { + super(controller, "Enable Humax ATS Fix"); + contr = controller; + } + + @Override + public void actionPerformed(final ActionEvent e) { + JCheckBoxMenuItem cb = (JCheckBoxMenuItem) e.getSource(); + PreferencesManager.setEnableHumaxAtsFix(cb.isSelected()); + askReloadStream(); + } +} \ No newline at end of file diff --git a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java index 3848b17c..4e2a671b 100644 --- a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java +++ b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java @@ -406,6 +406,10 @@ private JMenu createSettingsMenu() { enableM7Fastscan.setSelected(PreferencesManager.isEnableM7Fastscan()); settingsMenu.add(enableM7Fastscan); + final JCheckBoxMenuItem enableHumaxAtsFix = new JCheckBoxMenuItem(new EnableHumaxAtsFixAction(this)); + enableHumaxAtsFix.setMnemonic(KeyEvent.VK_H); + enableHumaxAtsFix.setSelected(PreferencesManager.isEnableHumaxAtsFix()); + settingsMenu.add(enableHumaxAtsFix); settingsMenu.addSeparator(); final JCheckBoxMenuItem enableGenericPSI = new JCheckBoxMenuItem(new EnableGenericPSIAction(this)); diff --git a/src/main/java/nl/digitalekabeltelevisie/util/PreferencesManager.java b/src/main/java/nl/digitalekabeltelevisie/util/PreferencesManager.java index a7c36a2b..6f82cbfe 100644 --- a/src/main/java/nl/digitalekabeltelevisie/util/PreferencesManager.java +++ b/src/main/java/nl/digitalekabeltelevisie/util/PreferencesManager.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2022 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. * @@ -57,6 +57,7 @@ public class PreferencesManager { private static final String ENABLE_DSMCC = "enable_dsmcc"; private static final String ENABLE_PCR_PTS = "enable_pcr_pts"; private static final String ENABLE_M7_FASTSCAN = "enable_m7_fastscan"; + private static final String ENABLE_HUMAX_ATS_FIX = "enable_humax_ats_fix"; private static final String SELECT_MPEG_FILE_FILTER = "select_mpeg_file_filter"; @@ -125,11 +126,11 @@ public static int getWindowY() { } public static int getWindowWidth() { - return prefs.getInt(PreferencesManager.WINDOW_WIDTH, 980); + return prefs.getInt(WINDOW_WIDTH, 980); } public static int getWindowHeight() { - return prefs.getInt(PreferencesManager.WINDOW_HEIGHT, 700); + return prefs.getInt(WINDOW_HEIGHT, 700); } public static void setWindowX(int x) { @@ -197,6 +198,19 @@ public static boolean isEnableM7Fastscan() { return getEnableM7Fastscan(); } + public static void setEnableHumaxAtsFix(boolean enabled) { + prefs.putBoolean(ENABLE_HUMAX_ATS_FIX, enabled); + } + + public static boolean getEnableHumaxAtsFix() { + return prefs.getBoolean(ENABLE_HUMAX_ATS_FIX, false); + } + + public static boolean isEnableHumaxAtsFix() { + return getEnableHumaxAtsFix(); + } + + public static void setSelectMpegFileFilter(boolean enabled) { prefs.putBoolean(SELECT_MPEG_FILE_FILTER, enabled); From deecc7f62aac651011366bf7bd62ebaa46e35897 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sat, 6 Jul 2024 15:19:26 +0200 Subject: [PATCH 14/23] remove roll_over from AVCHDPacket, keep that in TransportStream --- .../data/mpeg/AVCHDPacket.java | 28 +++---------------- .../data/mpeg/TransportStream.java | 5 ++-- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index 53e71bda..7ca959bf 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -44,16 +44,13 @@ public class AVCHDPacket extends TSPacket { byte[] tp_extra_header; - // TODO remove, the rollOverHelper In ts can handle all that is needed. - long roll_over; int arrivalTimestamp; - public AVCHDPacket(byte[] buf, int no, TransportStream ts, long roll_over) { + public AVCHDPacket(byte[] buf, int no, TransportStream ts) { super(Arrays.copyOfRange(buf,4,192), no, ts); tp_extra_header = Arrays.copyOf(buf,4); arrivalTimestamp = getInt(tp_extra_header,0,4,MASK_30BITS); - this.roll_over = roll_over; } @@ -76,14 +73,13 @@ public DefaultMutableTreeNode getJTreeNode(final int modus) { final DefaultMutableTreeNode t = new DefaultMutableTreeNode(new KVP(buildNodeLabel(),this)); final DefaultMutableTreeNode tpHeaderNode = new DefaultMutableTreeNode(new KVP("tp_extra_header",tp_extra_header,null)); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Copy_permission_indicator",getCopyPermissionIndicator(),null))); - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Roll-over",roll_over,null))); tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Arrival_time_stamp",arrivalTimestamp,printPCRTime(arrivalTimestamp)))); - tpHeaderNode.add(new DefaultMutableTreeNode(new KVP("Continuous ATS ",getTimeBase(),printPCRTime(getTimeBase())))); t.add(tpHeaderNode); addMainPacketDetails(modus, t); return t; } + @Override public String getHTML() { final StringBuilder s = new StringBuilder(); @@ -107,15 +103,7 @@ public String getHTML() { s.append("
Copy_permission_indicator: ").append(getCopyPermissionIndicator()); - s.append("
roll-over: ").append(roll_over); s.append("
Arrival_time_stamp: ").append(getArrivalTimestamp()).append(" (").append(printPCRTime(getArrivalTimestamp())).append(")"); - s.append("
Continuous ATS: ").append(getTimeBase()).append(" (").append(printPCRTime(getTimeBase())).append(")"); - int lowBits = getInt(tp_extra_header,0,4,MASK_9BITS); - s.append("
lowBits: ").append(lowBits); - if(lowBits >299) { - s.append("

lowBits > 299

"); - } - s.append("
"); addBasicPacketDetails(s, 4, coloring); @@ -130,15 +118,6 @@ public String getHTML() { } - public long getRoll_over() { - return roll_over; - } - - - public void setRoll_over(long roll_over) { - this.roll_over = roll_over; - } - /** * for AVCHD file time corresponds to TP_header ATS (plus roll over @@ -151,7 +130,8 @@ public long getTimeBase() { } + @Override public String toString() { - return super.toString() + " , arrivalTimestamp: "+arrivalTimestamp + " , roll_over: " + roll_over; + return super.toString() + " , arrivalTimestamp: " + arrivalTimestamp; } } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 915da8b6..26a8e5de 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -352,11 +352,10 @@ private void readAVCHDPackets(PositionPushbackInputStream fileStream) throws IOE fileStream.unread(nextBytes,0,next); } offsetHelper.addPacket(no_packets, offset); - final AVCHDPacket packet = new AVCHDPacket(buf, count, this,currentRollOver); + final AVCHDPacket packet = new AVCHDPacket(buf, count, this); final int arrivalTimestamp = packet.getArrivalTimestamp(); if (arrivalTimestamp < lastArrivalTimeStamp) { currentRollOver++; - packet.setRoll_over(currentRollOver); rollOverHelper.addPacket(count, currentRollOver); } lastArrivalTimeStamp = arrivalTimestamp; @@ -1148,7 +1147,7 @@ private TSPacket readPacket(final int packetNo, final RandomAccessFile randomAcc final int bytesRead = randomAccessFile.read(buf); if(bytesRead==packetLength){ if(isAVCHD()) { - packet = new AVCHDPacket(buf, packetNo,this,rollOverHelper.getRollOver(packetNo)); + packet = new AVCHDPacket(buf, packetNo,this); }else { packet = new TSPacket(buf, packetNo,this); } From e97cbf8030fe504f803d87150f4774490f905893 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 7 Jul 2024 13:50:23 +0200 Subject: [PATCH 15/23] refactored BarChart in prepartion for AVCHD support --- .../digitalekabeltelevisie/gui/BarChart.java | 151 ++++++++++-------- .../gui/BitRateChart.java | 2 +- 2 files changed, 86 insertions(+), 67 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java index 0a9ea72e..5ab042af 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java @@ -68,84 +68,103 @@ public BarChart(final TransportStream transportStream, final ViewContext viewCon public final void setTransportStream(final TransportStream transportStream, final ViewContext viewContext) { if(transportStream!=null){ - final int noPIDs = viewContext.getShown().size(); - final double[][] data = new double[3][noPIDs]; - final int steps = viewContext.getGraphSteps(); - - final short[] used_pids = new short[noPIDs]; - final ChartLabel[] labels = new ChartLabel[noPIDs]; - for (int i = 0; i < noPIDs; i++) { - labels[i] = new ChartLabel(transportStream.getShortLabel(viewContext.getShown().get(i).getPid()), - viewContext.getShown().get(i).getPid()); - used_pids[i] = viewContext.getShown().get(i).getPid(); - } - final ChartLabel[] stepLabels = new ChartLabel[3]; - stepLabels[0] = new ChartLabel("avg", (short) 0); - stepLabels[1] = new ChartLabel("min", (short) 1); - stepLabels[2] = new ChartLabel("max", (short) 2); - - final int startPacket = viewContext.getStartPacket(); - final int endPacket = viewContext.getEndPacket(); - final int noPackets = endPacket - startPacket; - - // AVG - final int[] pidcount = new int[8192]; - for (int r = startPacket; r < endPacket; r++) { - final int pid_current_packet = transportStream.getPacket_pid(r); - pidcount[pid_current_packet]++; - } + final CategoryDataset dataSet = createDataSet(transportStream, viewContext); + freeChart = ChartFactory.createBarChart(transportStream.getFile().getName() + " - stream:" + + transportStream.getStreamID(), "PID", "bitrate", dataSet, PlotOrientation.HORIZONTAL, true, true, + false); + setChart(freeChart); + }else{ // transportstream == null + freeChart = null; + setChart(GuiUtils.createTitleOnlyChart(GuiUtils.NO_TRANSPORTSTREAM_LOADED)); - for (int i = 0; i < used_pids.length; i++) { - if (transportStream.getBitRate() != -1) { - data[0][i] = (pidcount[used_pids[i]] * transportStream.getBitRate()) / (endPacket - startPacket); - } else { - data[0][i] = pidcount[used_pids[i]]; - } - } + } + } - // MIN/MAX - // initialize minima at maximum value - for (int i = 0; i < used_pids.length; i++) { - data[1][i] = Double.MAX_VALUE; + private static CategoryDataset createDataSet(final TransportStream transportStream, final ViewContext viewContext) { + + final short[] used_pids = BitRateChart.createUsedPidsArray(viewContext, viewContext.getShown().size()); + final ChartLabel[] labels = createPidChartLabels(transportStream, viewContext, viewContext.getShown().size()); + final ChartLabel[] avgMinMaxLabels = createAvgMinMaxLabels(); + + // AVG + final int[] pidCountAvg = new int[8192]; + for (int r = viewContext.getStartPacket(); r < viewContext.getEndPacket(); r++) { + final int pid_current_packet = transportStream.getPacket_pid(r); + pidCountAvg[pid_current_packet]++; + } + + final double[][] data = createCbrData(transportStream, viewContext, used_pids, pidCountAvg); + + + final CategoryDataset dataSet = DatasetUtils.createCategoryDataset(avgMinMaxLabels, labels, data); + return dataSet; + } + + private static double[][] createCbrData(final TransportStream transportStream, final ViewContext viewContext, + final short[] used_pids, final int[] pidCountAvg) { + final int steps = viewContext.getGraphSteps(); + final double[][] data = new double[3][viewContext.getShown().size()]; + + for (int i = 0; i < used_pids.length; i++) { + if (transportStream.getBitRate() != -1) { + data[0][i] = (pidCountAvg[used_pids[i]] * transportStream.getBitRate()) / (viewContext.getEndPacket() - viewContext.getStartPacket()); + } else { + data[0][i] = pidCountAvg[used_pids[i]]; } + } - for (int t = 0; t < steps; t++) { + // MIN/MAX + // initialize minima at maximum value + for (int i = 0; i < used_pids.length; i++) { + data[1][i] = Double.MAX_VALUE; + } - final int[] periodpidcount = new int[8192]; + for (int t = 0; t < steps; t++) { - final int startPacketStep = startPacket + (int) (((long) t * (long) noPackets) / steps); - final int endPacketStep = startPacket + (int) (((long) (t + 1) * (long) noPackets) / steps); + final int[] periodpidcount = new int[8192]; - for (int r = startPacketStep; r < endPacketStep; r++) { - final int pid_current_packet = transportStream.getPacket_pid(r); - periodpidcount[pid_current_packet]++; - } - for (int i = 0; i < used_pids.length; i++) { - final int periodCount = periodpidcount[used_pids[i]]; - if (transportStream.getBitRate() != -1 && endPacketStep > startPacketStep) { - final double bitRate = (periodCount * transportStream.getBitRate()) / (endPacketStep - startPacketStep); - if (bitRate < data[1][i]) { // new min found - data[1][i] = bitRate; - } - if (bitRate > data[2][i]) { // new max found - data[2][i] = bitRate; - } - } else { - data[1][i] = periodCount; - data[2][i] = periodCount; + final int startPacketStep = viewContext.getStartPacket() + (int) (((long) t * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); + final int endPacketStep = viewContext.getStartPacket() + (int) (((long) (t + 1) * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); + + for (int r = startPacketStep; r < endPacketStep; r++) { + final int pid_current_packet = transportStream.getPacket_pid(r); + periodpidcount[pid_current_packet]++; + } + for (int i = 0; i < used_pids.length; i++) { + final int periodCount = periodpidcount[used_pids[i]]; + if (transportStream.getBitRate() != -1 && endPacketStep > startPacketStep) { + final double bitRate = (periodCount * transportStream.getBitRate()) / (endPacketStep - startPacketStep); + if (bitRate < data[1][i]) { // new min found + data[1][i] = bitRate; } + if (bitRate > data[2][i]) { // new max found + data[2][i] = bitRate; + } + } else { + data[1][i] = periodCount; + data[2][i] = periodCount; } } - final CategoryDataset dataSet = DatasetUtils.createCategoryDataset(stepLabels, labels, data); - freeChart = ChartFactory.createBarChart(transportStream.getFile().getName() + " - stream:" - + transportStream.getStreamID(), "PID", "bitrate", dataSet, PlotOrientation.HORIZONTAL, true, true, - false); - setChart(freeChart); - }else{ // transportstream == null - freeChart = null; - setChart(GuiUtils.createTitleOnlyChart(GuiUtils.NO_TRANSPORTSTREAM_LOADED)); + } + return data; + } + + private static ChartLabel[] createAvgMinMaxLabels() { + final ChartLabel[] avgMinMaxLabels = new ChartLabel[3]; + avgMinMaxLabels[0] = new ChartLabel("avg", (short) 0); + avgMinMaxLabels[1] = new ChartLabel("min", (short) 1); + avgMinMaxLabels[2] = new ChartLabel("max", (short) 2); + return avgMinMaxLabels; + } + private static ChartLabel[] createPidChartLabels(final TransportStream transportStream, final ViewContext viewContext, + final int noPIDs) { + final ChartLabel[] labels = new ChartLabel[noPIDs]; + for (int i = 0; i < noPIDs; i++) { + labels[i] = new ChartLabel(transportStream.getShortLabel(viewContext.getShown().get(i).getPid()), + viewContext.getShown().get(i).getPid()); } + return labels; } } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java index e4e01db2..5be75141 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java @@ -230,7 +230,7 @@ private static CategoryTableXYDataset createCbrDataSet(final TransportStream tra return categoryTableXYDataset; } - private static short[] createUsedPidsArray(final ViewContext viewContext, final int noPIDs) { + static short[] createUsedPidsArray(final ViewContext viewContext, final int noPIDs) { final short[] used_pids = new short[noPIDs]; for (int i = 0; i < noPIDs; i++) { used_pids[i] = viewContext.getShown().get(i).getPid(); From cc088920482aa17e5a78db2ee667ff8dc60f73ed Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 7 Jul 2024 15:43:44 +0200 Subject: [PATCH 16/23] BarChart now supports AVCHD streams --- .../data/mpeg/MPEGConstants.java | 4 +- .../data/mpeg/TransportStream.java | 17 +-- .../digitalekabeltelevisie/gui/BarChart.java | 111 ++++++++++++++---- .../gui/BitRateChart.java | 6 +- 4 files changed, 102 insertions(+), 36 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java index 139c9f03..eb81c16e 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/MPEGConstants.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2012 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. * @@ -40,5 +40,7 @@ private MPEGConstants() { public final static int AVCHD_PACKET_LENGTH = 192; public final static int system_clock_frequency=27000000; + public final static int NO_PCR_PID=0x1FFF; + public static final int MAX_PIDS = 8192; } diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index 26a8e5de..f5a3f46c 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -28,6 +28,7 @@ package nl.digitalekabeltelevisie.data.mpeg; import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.MAX_PIDS; import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.sync_byte; import static nl.digitalekabeltelevisie.data.mpeg.descriptors.Descriptor.findGenericDescriptorsInList; import static nl.digitalekabeltelevisie.util.Utils.*; @@ -129,7 +130,7 @@ public String getDescription() { /** * 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. */ - private PID [] pids = new PID [8192]; + private PID [] pids = new PID [MAX_PIDS]; /** * for every TSPacket read, store it's packet_id. Used for bit rate calculations, and Grid View */ @@ -282,7 +283,7 @@ public void parseStream(final java.awt.Component component) throws IOException { try (PositionPushbackInputStream fileStream = getInputStream(component)) { no_packets = 0; - pids = new PID[8192]; + pids = new PID[MAX_PIDS]; psi = new PSI(); error_packets = 0; bitRate = -1; @@ -986,12 +987,12 @@ public int getNoPIDS() } public short [] getUsedPids(){ - final int no=getNoPIDS(); - final short [] r = new short[no]; - int i=0; - for(short pid=0; pid<8192;pid++){ - if(pids[pid]!=null){ - r[i++]=pid; + final int no = getNoPIDS(); + final short[] r = new short[no]; + int i = 0; + for (short pid = 0; pid < MAX_PIDS; pid++) { + if (pids[pid] != null) { + r[i++] = pid; } } return r; diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java index 5ab042af..3f5cd9dd 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BarChart.java @@ -28,9 +28,13 @@ import nl.digitalekabeltelevisie.controller.ChartLabel; import nl.digitalekabeltelevisie.controller.ViewContext; +import nl.digitalekabeltelevisie.data.mpeg.MPEGConstants; import nl.digitalekabeltelevisie.data.mpeg.TransportStream; import nl.digitalekabeltelevisie.gui.utils.GuiUtils; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.MAX_PIDS; + import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; @@ -80,71 +84,128 @@ public final void setTransportStream(final TransportStream transportStream, fina } } + private static double[][] createCbrData(final TransportStream transportStream, final ViewContext viewContext, + final short[] used_pids, final int[] pidCountAvg) { + final int steps = viewContext.getGraphSteps(); + final double[][] data = new double[3][viewContext.getShown().size()]; + + for (int i = 0; i < used_pids.length; i++) { + if (transportStream.getBitRate() != -1) { + data[0][i] = (pidCountAvg[used_pids[i]] * transportStream.getBitRate()) / (viewContext.getEndPacket() - viewContext.getStartPacket()); + } else { + data[0][i] = pidCountAvg[used_pids[i]]; + } + } + + // MIN/MAX + // initialize minima at maximum value + for (int i = 0; i < used_pids.length; i++) { + data[1][i] = Double.MAX_VALUE; + } + + for (int t = 0; t < steps; t++) { + + final int[] periodpidcount = new int[MAX_PIDS]; + + final int startPacketStep = viewContext.getStartPacket() + (int) (((long) t * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); + final int endPacketStep = viewContext.getStartPacket() + (int) (((long) (t + 1) * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); + + for (int r = startPacketStep; r < endPacketStep; r++) { + final int pid_current_packet = transportStream.getPacket_pid(r); + periodpidcount[pid_current_packet]++; + } + for (int i = 0; i < used_pids.length; i++) { + final int periodCount = periodpidcount[used_pids[i]]; + if (transportStream.getBitRate() != -1 && endPacketStep > startPacketStep) { + final double bitRate = (periodCount * transportStream.getBitRate()) / (endPacketStep - startPacketStep); + if (bitRate < data[1][i]) { // new min found + data[1][i] = bitRate; + } + if (bitRate > data[2][i]) { // new max found + data[2][i] = bitRate; + } + } else { + data[1][i] = periodCount; + data[2][i] = periodCount; + } + } + } + return data; + } + private static CategoryDataset createDataSet(final TransportStream transportStream, final ViewContext viewContext) { - final short[] used_pids = BitRateChart.createUsedPidsArray(viewContext, viewContext.getShown().size()); + final short[] usedPids = BitRateChart.createUsedPidsArray(viewContext, viewContext.getShown().size()); final ChartLabel[] labels = createPidChartLabels(transportStream, viewContext, viewContext.getShown().size()); final ChartLabel[] avgMinMaxLabels = createAvgMinMaxLabels(); // AVG - final int[] pidCountAvg = new int[8192]; + final int[] pidCountAvg = new int[MAX_PIDS]; for (int r = viewContext.getStartPacket(); r < viewContext.getEndPacket(); r++) { final int pid_current_packet = transportStream.getPacket_pid(r); pidCountAvg[pid_current_packet]++; } - final double[][] data = createCbrData(transportStream, viewContext, used_pids, pidCountAvg); + final double[][] data; + if(transportStream.isAVCHD()) { + data = createAvchdData(transportStream, viewContext, usedPids, pidCountAvg); + }else { + data = createCbrData(transportStream, viewContext, usedPids, pidCountAvg); + } final CategoryDataset dataSet = DatasetUtils.createCategoryDataset(avgMinMaxLabels, labels, data); return dataSet; } - private static double[][] createCbrData(final TransportStream transportStream, final ViewContext viewContext, - final short[] used_pids, final int[] pidCountAvg) { + private static double[][] createAvchdData(final TransportStream transportStream, final ViewContext viewContext, + final short[] usedPids, final int[] pidCountAvg) { final int steps = viewContext.getGraphSteps(); final double[][] data = new double[3][viewContext.getShown().size()]; - for (int i = 0; i < used_pids.length; i++) { - if (transportStream.getBitRate() != -1) { - data[0][i] = (pidCountAvg[used_pids[i]] * transportStream.getBitRate()) / (viewContext.getEndPacket() - viewContext.getStartPacket()); - } else { - data[0][i] = pidCountAvg[used_pids[i]]; - } + long startSelectionTime = transportStream.getAVCHDPacketTime(viewContext.getStartPacket()); + long endSelectionTime = transportStream.getAVCHDPacketTime(viewContext.getEndPacket() - 1); + long selectionDuration = endSelectionTime - startSelectionTime; + + for (int i = 0; i < usedPids.length; i++) { + data[0][i] = (pidCountAvg[usedPids[i]] * (double) MPEGConstants.system_clock_frequency) * 8 * AVCHD_PACKET_LENGTH / selectionDuration; } // MIN/MAX // initialize minima at maximum value - for (int i = 0; i < used_pids.length; i++) { + for (int i = 0; i < usedPids.length; i++) { data[1][i] = Double.MAX_VALUE; } - for (int t = 0; t < steps; t++) { - final int[] periodpidcount = new int[8192]; + int packetIndex = viewContext.getStartPacket(); + long startStepPacketTime = startSelectionTime; + + for (int step = 0; step < steps; step++) { + final long endStepPacketTime = startSelectionTime + (selectionDuration * (step + 1) / steps); - final int startPacketStep = viewContext.getStartPacket() + (int) (((long) t * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); - final int endPacketStep = viewContext.getStartPacket() + (int) (((long) (t + 1) * (long) (viewContext.getEndPacket() - viewContext.getStartPacket())) / steps); + final int[] periodpidcount = new int[MAX_PIDS]; - for (int r = startPacketStep; r < endPacketStep; r++) { - final int pid_current_packet = transportStream.getPacket_pid(r); + + while(packetIndex< viewContext.getEndPacket() && transportStream.getAVCHDPacketTime(packetIndex) <= endStepPacketTime) { + final int pid_current_packet=transportStream.getPacket_pid(packetIndex); periodpidcount[pid_current_packet]++; + packetIndex++; } - for (int i = 0; i < used_pids.length; i++) { - final int periodCount = periodpidcount[used_pids[i]]; - if (transportStream.getBitRate() != -1 && endPacketStep > startPacketStep) { - final double bitRate = (periodCount * transportStream.getBitRate()) / (endPacketStep - startPacketStep); + + for (int i = 0; i < usedPids.length; i++) { + if (endStepPacketTime > startStepPacketTime) { + final double bitRate = ((periodpidcount[usedPids[i]]) * (double) MPEGConstants.system_clock_frequency) * 8 * AVCHD_PACKET_LENGTH / (endStepPacketTime - startStepPacketTime) ; if (bitRate < data[1][i]) { // new min found data[1][i] = bitRate; } if (bitRate > data[2][i]) { // new max found data[2][i] = bitRate; } - } else { - data[1][i] = periodCount; - data[2][i] = periodCount; } } + startStepPacketTime = endStepPacketTime; + } return data; } diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java index 5be75141..5fadd627 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/BitRateChart.java @@ -28,6 +28,8 @@ package nl.digitalekabeltelevisie.gui; import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.AVCHD_PACKET_LENGTH; +import static nl.digitalekabeltelevisie.data.mpeg.MPEGConstants.MAX_PIDS; + import java.awt.BorderLayout; import java.text.FieldPosition; @@ -253,7 +255,7 @@ private static ChartLabel[] createChartLabels(final ViewContext viewContext, fin * @return */ private static int[] countPidOccurrencesInStep(final TransportStream transportStream, final int startPacketStep, final int endPacketStep) { - final int [] pidcount = new int [8192]; + final int [] pidcount = new int [MAX_PIDS]; for(int r = startPacketStep; r< endPacketStep;r++ ){ final int pid_current_packet=transportStream.getPacket_pid(r); pidcount[pid_current_packet]++; @@ -328,7 +330,7 @@ private static CategoryTableXYDataset createAvchdDataSet(final TransportStream t long startStepPacketTime = startSelectionTime; for (int step = 0; step < numberOfSteps; step++) { final long endStepPacketTime = startSelectionTime + (selectionDuration * (step + 1) / numberOfSteps); - final int [] pidcount = new int [8192]; + final int [] pidcount = new int [MAX_PIDS]; while(packetIndex< viewContext.getEndPacket() && transportStream.getAVCHDPacketTime(packetIndex) <= endStepPacketTime) { final int pid_current_packet=transportStream.getPacket_pid(packetIndex); pidcount[pid_current_packet]++; From 72ce9150602d25489d66d49b5d489096355ff011 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 11:20:49 +0200 Subject: [PATCH 17/23] make right panel single selection, added 1000 to STEP_OPTIONS --- src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java index 390b85b6..ee8327d8 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java @@ -2,7 +2,7 @@ * * http://www.digitalekabeltelevisie.nl/dvb_inspector * - * This code is Copyright 2009-2021 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. * @@ -95,7 +95,7 @@ public class PIDDialog extends JDialog private final PacketSelectionPanel packetSelectionStart; private final PacketSelectionPanel packetSelectionEnd; private final JComboBox stepsChooser; - public static final Integer[] STEP_OPTIONS = {1,2,5,10,20,50,100,200,500}; + public static final Integer[] STEP_OPTIONS = {1,2,5,10,20,50,100,200,500,1000}; public void enableButtons(){ @@ -463,6 +463,7 @@ public PIDDialog(final Frame aFrame, final ViewContext viewContext, final DVBins } rightList = new JList<>(rightListModel); + rightList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); final JPanel buttonPanel = new JPanel(); From 1db76f649e97406ab1bc7b75bfabf6278b1d73f8 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 11:21:15 +0200 Subject: [PATCH 18/23] added comments --- .../nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java | 6 +++++- .../java/nl/digitalekabeltelevisie/util/RollOverHelper.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java index 7ca959bf..773baec1 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/AVCHDPacket.java @@ -39,7 +39,11 @@ import nl.digitalekabeltelevisie.util.Utils; /** - * + * AVCHD and Blu-ray use same format for 192 byte TS packets, first 4 bytes are tp_extra_header. + * See Table 3-34 TP_extra_header. in "Advanced Access Content System (AACS) Blu-ray Disc Pre-recorded Book" (AACS_Spec_BD_Prerecorded_Final_0.951.pdf) + * + * See https://stackoverflow.com/questions/32354754/how-to-use-timestamps-for-seeking-in-m2ts-files + * */ public class AVCHDPacket extends TSPacket { diff --git a/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java b/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java index 3fdd3382..2b754b07 100644 --- a/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java +++ b/src/main/java/nl/digitalekabeltelevisie/util/RollOverHelper.java @@ -28,7 +28,7 @@ package nl.digitalekabeltelevisie.util; /** - * Keeps track of at roll-over for AVCHD packets (192 bytes) + * Keeps track of ats roll-over for AVCHD/Blu-ray packets (192 bytes) */ public class RollOverHelper { From 999dd33ef7c80be9049f8c694e5e93a722f85a3b Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 11:23:50 +0200 Subject: [PATCH 19/23] create RollOverHelper only for AVCHD streams --- .../nl/digitalekabeltelevisie/data/mpeg/TransportStream.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java index f5a3f46c..cbe2226c 100644 --- a/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java +++ b/src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java @@ -205,9 +205,9 @@ public TransportStream(final File file) throws NotAnMPEGFileException,IOExceptio if(isAVCHD()) { packetATS = new int [max_packets]; enabledHumaxAtsFix = PreferencesManager.isEnableHumaxAtsFix(); + rollOverHelper = new RollOverHelper(max_packets); } offsetHelper = new OffsetHelper(max_packets,packetLength); - rollOverHelper = new RollOverHelper(max_packets); } From 2b6d19f291a2970268c747bbaf79eee0ed94c55a Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 13:06:05 +0200 Subject: [PATCH 20/23] cleanup unused parameters --- .../nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java b/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java index 4e3ee356..1dcd8de0 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/PacketSelectionPanel.java @@ -44,7 +44,6 @@ import javax.swing.event.ChangeListener; import javax.swing.text.NumberFormatter; -import nl.digitalekabeltelevisie.data.mpeg.TransportStream; /** @@ -140,6 +139,7 @@ public Dimension getMaximumSize() { /** Updates the text field when the main data model is updated. */ + @Override public void stateChanged(final ChangeEvent e) { final NumberFormatter formatter = (NumberFormatter)textField.getFormatter(); @@ -157,6 +157,7 @@ public void stateChanged(final ChangeEvent e) { * Detects when the value of the text field (not necessarily the same * number as you'd get from getText) changes. */ + @Override public void propertyChange(final PropertyChangeEvent e) { if ("value".equals(e.getPropertyName())) { final Number value = (Number)e.getNewValue(); @@ -164,7 +165,7 @@ public void propertyChange(final PropertyChangeEvent e) { } } - public void setRangeValue(final int min, final int max, final int val,final TransportStream ts){ + public void setRangeValue(final int min, final int max, final int val){ slider.setMinimum(min); slider.setMaximum(max); slider.setValue(val); From bccb4f46a7a1f08af65cf7b89cf0daf4744cffc8 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 13:06:18 +0200 Subject: [PATCH 21/23] cleanup --- src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java index ee8327d8..98582b2c 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/PIDDialog.java @@ -660,8 +660,8 @@ public void resetLists(final ViewContext viewContex) { rightListModel.addElement(label); } - packetSelectionStart.setRangeValue(0, viewContex.getMaxPacket()-1, viewContex.getStartPacket(),viewContex.getTransportStream()); - packetSelectionEnd.setRangeValue(1, viewContex.getMaxPacket(), viewContex.getEndPacket(),viewContex.getTransportStream()); + packetSelectionStart.setRangeValue(0, viewContex.getMaxPacket()-1, viewContex.getStartPacket()); + packetSelectionEnd.setRangeValue(1, viewContex.getMaxPacket(), viewContex.getEndPacket()); for(int i=0; i Date: Sun, 4 Aug 2024 13:06:31 +0200 Subject: [PATCH 22/23] improve msg --- .../nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java b/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java index 88c0cd7f..08184517 100644 --- a/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java +++ b/src/main/java/nl/digitalekabeltelevisie/gui/EnableHumaxAtsFixAction.java @@ -37,7 +37,7 @@ public class EnableHumaxAtsFixAction extends AbstractSetPreferenceAction { public EnableHumaxAtsFixAction(final DVBinspector controller) { - super(controller, "Enable Humax ATS Fix"); + super(controller, "Enable Humax ATS Fix for 192 byte AVCHD/Blu-ray packets"); contr = controller; } From 26e622d243223f2954d96b8d8b2ac7ac487525e7 Mon Sep 17 00:00:00 2001 From: Eric Berendsen Date: Sun, 4 Aug 2024 13:08:42 +0200 Subject: [PATCH 23/23] add description AVCHD to packet size option --- src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java index 4e2a671b..b17f7de2 100644 --- a/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java +++ b/src/main/java/nl/digitalekabeltelevisie/main/DVBinspector.java @@ -356,7 +356,7 @@ private JMenu createSettingsMenu() { addPacketLengthMenuItem(packetLengthSubMenu, packetLengthMenuGroup, "auto (Recommended)", 0); for(int i: TransportStream.ALLOWED_PACKET_LENGTHS) { - addPacketLengthMenuItem(packetLengthSubMenu, packetLengthMenuGroup, ""+i, i); + addPacketLengthMenuItem(packetLengthSubMenu, packetLengthMenuGroup, i + (i==192?" (AVCHD/Blu-ray)":""), i); } settingsMenu.add(packetLengthSubMenu);