Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
56c66fa
Add local Maven build helper
znbsf May 16, 2026
cf9c4af
Add initial ATSC PSIP table support
znbsf May 16, 2026
7638de1
Add ATSC virtual channel table support
znbsf May 16, 2026
a94cfd6
Add ATSC VCT descriptor decoding
znbsf May 16, 2026
523bf15
Use ATSC virtual channel names for service labels
znbsf May 16, 2026
d009bd3
Add ATSC caption service descriptor
znbsf May 16, 2026
5ed3905
Add ATSC content advisory descriptor
znbsf May 16, 2026
bf64884
Add ATSC genre descriptor
znbsf May 16, 2026
f85386b
Add MGT-driven ATSC EIT parsing
znbsf May 16, 2026
edd278b
Add MGT-driven ATSC ETT parsing
znbsf May 16, 2026
acba286
Label ATSC PSIP PIDs from MGT
znbsf May 16, 2026
52e73b6
Add ATSC PSIP table views
znbsf May 16, 2026
f5d3571
Use ATSC VCT names for PAT programs
znbsf May 16, 2026
6654457
Add ATSC Rating Region Table parsing
znbsf May 17, 2026
0a8cf4f
Handle ATSC RRT in generic PSI handler
znbsf May 17, 2026
be54232
Show ATSC channel names in EIT and ETT tables
znbsf May 17, 2026
55de2a1
Show ATSC rating names in content advisory descriptors
znbsf May 17, 2026
13c4445
Remove trailing blank line from gitignore
znbsf May 17, 2026
585351f
Add ATSC AC-3 audio descriptors
znbsf May 17, 2026
3db74e2
Add ATSC time-shifted and component name descriptors
znbsf May 17, 2026
239e0f6
Add ATSC DCC and control descriptors
znbsf May 17, 2026
0a41d23
Add ATSC private information descriptor
znbsf May 17, 2026
4888b6b
Show ATSC VCT version tables
znbsf May 18, 2026
a4fece9
Group ATSC PSIP tables by complete version
znbsf May 18, 2026
8932d50
Show empty ATSC EIT section summaries
znbsf May 18, 2026
00c1e05
Add ATSC program and EPG summary tables
znbsf May 20, 2026
9696220
Add ATSC EIT timeline view
znbsf May 20, 2026
c930870
Add ATSC EIT tree grid views
znbsf May 20, 2026
f2fb6f8
Add ATSC MGT PSIP guide table
znbsf May 20, 2026
ef23134
Limit ATSC private audio handlers to PSIP streams
znbsf May 20, 2026
baa27a6
Fix ATSC PSIP versioned summaries
znbsf May 21, 2026
0716148
Clean up PR-only local files
znbsf May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
dependency-reduced-pom.xml
23 changes: 14 additions & 9 deletions src/main/java/nl/digitalekabeltelevisie/controller/KVP.java
Original file line number Diff line number Diff line change
Expand Up @@ -501,15 +501,20 @@ public KVP addImageSource(ImageSource imageSource, String label) {
return this;
}

public KVP addTableSource(TableSource tableSource, String label) {
detailViews.add(new DetailView(tableSource, label));
return this;
}

public KVP addXMLSource(XMLSource xmlSource, String label) {
detailViews.add(new DetailView(xmlSource, label));
return this;
}
public KVP addTableSource(TableSource tableSource, String label) {
detailViews.add(new DetailView(tableSource, label));
return this;
}

public KVP addTableSourceFirst(TableSource tableSource, String label) {
detailViews.add(0, new DetailView(tableSource, label));
return this;
}

public KVP addXMLSource(XMLSource xmlSource, String label) {
detailViews.add(new DetailView(xmlSource, label));
return this;
}

@Override
public Object getUserObject() {
Expand Down
55 changes: 34 additions & 21 deletions src/main/java/nl/digitalekabeltelevisie/data/mpeg/PSI.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@
*
*/

package nl.digitalekabeltelevisie.data.mpeg;

import nl.digitalekabeltelevisie.controller.KVP;
import nl.digitalekabeltelevisie.data.mpeg.dsmcc.DSMCCs;
import nl.digitalekabeltelevisie.data.mpeg.psi.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.ses.SGT;
import nl.digitalekabeltelevisie.util.PreferencesManager;
package nl.digitalekabeltelevisie.data.mpeg;

import java.util.Optional;

import nl.digitalekabeltelevisie.controller.KVP;
import nl.digitalekabeltelevisie.data.mpeg.dsmcc.DSMCCs;
import nl.digitalekabeltelevisie.data.mpeg.psi.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.atsc.ATSCTables;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.ses.SGT;
import nl.digitalekabeltelevisie.util.PreferencesManager;

/**
* Container for all PSI related data
Expand Down Expand Up @@ -60,10 +63,11 @@ public class PSI {
private final AITs ait_table = new AITs(this);
private final RCTs rct_table = new RCTs(this);
private final DSMCCs dsm_table = new DSMCCs(this);
private final SCTE35 scte35_table = new SCTE35(this);
private final DFITs dfit_table = new DFITs(this);

private final M7Fastscan m7fastscan = new M7Fastscan(this);
private final SCTE35 scte35_table = new SCTE35(this);
private final DFITs dfit_table = new DFITs(this);
private final ATSCTables atsc = new ATSCTables(this);

private final M7Fastscan m7fastscan = new M7Fastscan(this);

private final SGT sgt = new SGT(this);

Expand All @@ -88,11 +92,12 @@ public KVP getJTreeNode(final int modus){
t.add(ait_table.getJTreeNode(modus));
t.add(rct_table.getJTreeNode(modus));
t.add(dsm_table.getJTreeNode(modus));
t.add(scte35_table.getJTreeNode(modus));
t.add(dfit_table.getJTreeNode(modus));
if(PreferencesManager.isEnableM7Fastscan()) {
t.add(m7fastscan.getJTreeNode(modus));
}
t.add(scte35_table.getJTreeNode(modus));
t.add(dfit_table.getJTreeNode(modus));
t.add(atsc.getJTreeNode(modus));
if(PreferencesManager.isEnableM7Fastscan()) {
t.add(m7fastscan.getJTreeNode(modus));
}
t.add(sgt.getJTreeNode(modus));
return t;
}
Expand Down Expand Up @@ -185,7 +190,15 @@ public DFITs getDfit_table() {
public TSDT getTsdt() {
return tsdt;
}
public SGT getSgt() {
return sgt;
}
}
public SGT getSgt() {
return sgt;
}
public ATSCTables getAtsc() {
return atsc;
}

public Optional<String> getServiceNameOptional(final int serviceId) {
return sdt.getServiceNameForActualTransportStreamOptional(serviceId)
.or(() -> atsc.getServiceNameOptional(serviceId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import nl.digitalekabeltelevisie.data.mpeg.descriptors.*;
import nl.digitalekabeltelevisie.data.mpeg.descriptors.DataBroadcastIDDescriptor.OUIEntry;
import nl.digitalekabeltelevisie.data.mpeg.psi.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection.Component;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.ses.SGTsection;
import nl.digitalekabeltelevisie.util.PreferencesManager;
import nl.digitalekabeltelevisie.data.mpeg.descriptors.*;
import nl.digitalekabeltelevisie.data.mpeg.descriptors.DataBroadcastIDDescriptor.OUIEntry;
import nl.digitalekabeltelevisie.data.mpeg.psi.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection.Component;
import nl.digitalekabeltelevisie.data.mpeg.psi.atsc.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.ses.SGTsection;
import nl.digitalekabeltelevisie.util.PreferencesManager;
import nl.digitalekabeltelevisie.util.Utils;


Expand Down Expand Up @@ -167,11 +168,25 @@ private void updatePSI(final int pid) {
transportStream.getPsi().getNit().update(new NITsection(this,parentPID));
}else if((tableId==0x4A)&&(pid==0x11)){
transportStream.getPsi().getBat().update(new BATsection(this,parentPID));
}else if((0x4E<=tableId)&&(tableId<=0x6F)&&(pid==0x12)){
transportStream.getPsi().getEit().update(new EITsection(this,parentPID));
}else if((pid==0x14) &&(tableId==0x70)){
transportStream.getPsi().getTdt().update(new TDTsection(this,parentPID));
}else if((pid==0x14) &&(tableId==0x73)){
}else if((0x4E<=tableId)&&(tableId<=0x6F)&&(pid==0x12)){
transportStream.getPsi().getEit().update(new EITsection(this,parentPID));
}else if((pid==ATSCTables.BASE_PID) && (tableId==0xC7)){
transportStream.getPsi().getAtsc().update(new MGTsection(this,parentPID));
}else if((pid==ATSCTables.BASE_PID) && (tableId==0xC8)){
transportStream.getPsi().getAtsc().update(new TVCTsection(this,parentPID));
}else if((pid==ATSCTables.BASE_PID) && (tableId==0xC9)){
transportStream.getPsi().getAtsc().update(new CVCTsection(this,parentPID));
}else if((pid==ATSCTables.BASE_PID) && (tableId==0xCA)){
transportStream.getPsi().getAtsc().update(new RRTsection(this,parentPID));
}else if((tableId==0xCB) && transportStream.getPsi().getAtsc().isAtscEitPid(pid)){
transportStream.getPsi().getAtsc().update(new ATSCEITsection(this,parentPID));
}else if((tableId==0xCC) && transportStream.getPsi().getAtsc().isAtscEttPid(pid)){
transportStream.getPsi().getAtsc().update(new ATSCETTsection(this,parentPID));
}else if((pid==ATSCTables.BASE_PID) && (tableId==0xCD)){
transportStream.getPsi().getAtsc().update(new STTsection(this,parentPID));
}else if((pid==0x14) &&(tableId==0x70)){
transportStream.getPsi().getTdt().update(new TDTsection(this,parentPID));
}else if((pid==0x14) &&(tableId==0x73)){
transportStream.getPsi().getTot().update(new TOTsection(this,parentPID));
}else if((pid==0x11) &&((tableId==0x42)||(tableId==0x46))){
transportStream.getPsi().getSdt().update(new SDTsection(this,parentPID));
Expand Down
127 changes: 78 additions & 49 deletions src/main/java/nl/digitalekabeltelevisie/data/mpeg/TransportStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@
import nl.digitalekabeltelevisie.data.mpeg.pes.video266.H266Handler;
import nl.digitalekabeltelevisie.data.mpeg.pid.t2mi.T2miPidHandler;
import nl.digitalekabeltelevisie.data.mpeg.psi.*;
import nl.digitalekabeltelevisie.data.mpeg.psi.EITsection.Event;
import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection.Component;
import nl.digitalekabeltelevisie.data.mpeg.psi.handler.GeneralPsiTableHandler;
import nl.digitalekabeltelevisie.data.mpeg.psi.EITsection.Event;
import nl.digitalekabeltelevisie.data.mpeg.psi.PMTsection.Component;
import nl.digitalekabeltelevisie.data.mpeg.psi.atsc.ATSCTables;
import nl.digitalekabeltelevisie.data.mpeg.psi.atsc.MGTsection;
import nl.digitalekabeltelevisie.data.mpeg.psi.handler.GeneralPsiTableHandler;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.M7Fastscan;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.ONTSection;
import nl.digitalekabeltelevisie.data.mpeg.psi.m7fastscan.OperatorFastscan;
Expand Down Expand Up @@ -553,17 +555,18 @@ private String getSummary(int modus) {

sb.append("<ol>");

for (Integer programNumber : serviceIds) {
PMTsection[] sections = pmts.get(programNumber);

sb.append("<li>program: ")
.append("<a href=\"root/psi/pmts/program:")
.append(programNumber)
.append("\">")
.append(programNumber)
.append("</a>");
psi.getSdt().getServiceNameForActualTransportStreamOptional(programNumber).ifPresent(s -> sb.append(" (").append(s).append(')'));
sb.append("<br/>");
for (Integer programNumber : serviceIds) {
PMTsection[] sections = pmts.get(programNumber);
Optional<String> serviceName = getServiceNameOptional(programNumber);

sb.append("<li>program: ")
.append("<a href=\"root/psi/pmts/program:")
.append(programNumber)
.append("\">")
.append(programNumber)
.append("</a>");
serviceName.ifPresent(s -> sb.append(" (").append(s).append(')'));
sb.append("<br/>");

PMTsection pmtSection = sections[0];
sb.append("<ol>");
Expand Down Expand Up @@ -731,24 +734,25 @@ private void namePIDs() {
for (short i = 0; i <=0x1f; i++) {
setLabelMakerBase(i, getFixedLabel(i));
}

setLabelMakerBase(8191,"NULL Packets (Stuffing)");

// now the streams referenced from the CAT
if(pids[1]!=null){

setLabelMakerBase(8191,"NULL Packets (Stuffing)");
labelAtscPsipTables();

// now the streams referenced from the CAT
if(pids[1]!=null){
for(CADescriptor caDescriptor:findGenericDescriptorsInList(psi.getCat().getDescriptorList(), CADescriptor.class)){
addLabelMakerComponent(caDescriptor.getCaPID(), "EMM", "CA_ID:"+ caDescriptor.getCaSystemID()+ " ("+ getCASystemIDString(caDescriptor.getCaSystemID())+")");
}
}

// now all services, starting with PMTs themselves, then referenced ES
for(PMTsection[] pmt: psi.getPmts()){
PMTsection pmtSection = pmt[0];
while(pmtSection!=null){
int service_id=pmtSection.getProgramNumber();
String service_name = psi.getSdt().getServiceNameForActualTransportStreamOptional(service_id).orElse("Service "+service_id);
labelPmtForProgram(pmtSection, service_name);
for(PMTsection[] pmt: psi.getPmts()){
PMTsection pmtSection = pmt[0];
while(pmtSection!=null){
int service_id=pmtSection.getProgramNumber();
String service_name = getServiceNameOptional(service_id).orElse("Service "+service_id);

labelPmtForProgram(pmtSection, service_name);
labelEcmForProgram(pmtSection, service_name);
labelComponentsForProgram(pmtSection, service_name);
labelPcrForProgram(pmtSection, service_name);
Expand All @@ -763,10 +767,27 @@ private void namePIDs() {
labelM7FastscanTables();
}


}

private void setGeneralPsiTableHandlers() {

}

private void labelAtscPsipTables() {
setLabelMakerBase(ATSCTables.BASE_PID, "ATSC PSIP");
MGTsection mgtSection = psi.getAtsc().getMgt().getMgtSection();
if (mgtSection == null) {
return;
}
for (MGTsection.TableTypeEntry entry : mgtSection.getTableTypeEntries()) {
int pid = entry.getTableTypePid();
setLabelMakerBase(pid, "ATSC PSIP");
addLabelMakerComponent(pid, "ATSC table", MGTsection.getTableTypeDescription(entry.getTableType()));
}
}

private Optional<String> getServiceNameOptional(final int serviceId) {
return psi.getServiceNameOptional(serviceId);
}

private void setGeneralPsiTableHandlers() {
if(PreferencesManager.isEnableGenericPSI()) {
for (PID pid : pids) {
if((pid!=null)&&(pid.getType()==PID.PSI)) {
Expand Down Expand Up @@ -959,26 +980,34 @@ private static ComponentType findComponentType(List<Descriptor> componentDescrip
return null;
}

private GeneralPidHandler determinePesHandlerByStreamType(Component component,
int streamType) {
int componentElementaryPID = component.getElementaryPID();
PID pid = pids[componentElementaryPID];
if ((pid != null) && (!pid.isScrambled()) && (pid.getType() == PID.PES)){
return switch(streamType){
case 1,2 -> new Video138182Handler();
case 3,4 -> new Audio138183Handler(getAncillaryDataIdentifier(component));
case 0x11 -> new Audio144963Handler();
private GeneralPidHandler determinePesHandlerByStreamType(Component component,
int streamType) {
int componentElementaryPID = component.getElementaryPID();
PID pid = pids[componentElementaryPID];
if ((pid != null) && (!pid.isScrambled()) && (pid.getType() == PID.PES)){
if (psi.getAtsc().hasPsipTables()) {
if (streamType == 0x81) {
return new AC3Handler();
}
if (streamType == 0x87) {
return new EAC3Handler();
}
}
return switch(streamType){
case 1,2 -> new Video138182Handler();
case 3,4 -> new Audio138183Handler(getAncillaryDataIdentifier(component));
case 0x11 -> new Audio144963Handler();
case 0x1B -> new Video14496Handler();
case 0x20 -> new Video14496Handler(); //MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10
case 0x24 -> new H265Handler();
case 0x27 -> new TEMIPesHandler();
case 0x33 -> new H266Handler();
case 0x32 -> new JpegXsHandler();
default -> new GeneralPesHandler();
};
}
return null;
}
case 0x20 -> new Video14496Handler(); //MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10
case 0x24 -> new H265Handler();
case 0x27 -> new TEMIPesHandler();
case 0x33 -> new H266Handler();
case 0x32 -> new JpegXsHandler();
default -> new GeneralPesHandler();
};
}
return null;
}

private static int getAncillaryDataIdentifier(Component component) {
List<AncillaryDataDescriptor> ancillaryDataDescriptors = findGenericDescriptorsInList(component.getComponentDescriptorList(), AncillaryDataDescriptor.class);
Expand Down
Loading