feyris-tan ef86554f9a Import
2025-05-12 22:09:16 +02:00

393 lines
11 KiB
C#

using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.Storage;
using skyscraper5.UI.Overrides;
using skyscraper5.UI.StreamAcquisition;
namespace skyscraper5.UI
{
public partial class Form1 : Form, INodeEngine
{
public Form1()
{
InitializeComponent();
}
public Form1(StreamSource acquiredStream)
: this()
{
AcquiredStream = acquiredStream;
tsContext = new TsContext();
tsContext.OnPacketLoss += TsContext_OnPacketLoss;
skyscraperContext = new SkyscraperContext(tsContext, eventLogger, storage);
skyscraperContext.UiJunction = uiJunction;
}
private void TsContext_OnPacketLoss(uint pid, uint oldContinuity, uint newContinuity, long packetLossEvents)
{
continuityErrors = packetLossEvents;
}
public StreamSource AcquiredStream { get; }
private TsContext tsContext;
private SkyscraperContext skyscraperContext;
private ISkyscraperEventLogger eventLogger;
private IScraperStroage storage;
private Form1UiJunction uiJunction;
private DateTime windowOpenedTimestamp;
private TimeSpan windowOpenDuration;
private long continuityErrors;
private TeiCounter teiCounterFilter;
private PmtCounter pmtCounter;
private PacketsPerSecondCounter packetsPerSecondCounter;
private ScrambleCounter scrambleCounter;
private void Form1_Load(object sender, EventArgs e)
{
scrambleCounter = new ScrambleCounter();
packetsPerSecondCounter = new PacketsPerSecondCounter();
teiCounterFilter = new TeiCounter();
skyscraperContext.InitalizeFilterChain(teiCounterFilter, packetsPerSecondCounter, scrambleCounter);
uiJunction = new Form1UiJunction(this);
skyscraperContext.UiJunction = uiJunction;
windowOpenedTimestamp = DateTime.Now;
windowOpenDuration = new TimeSpan(0, 0, 0);
bottomLeft.Items[0].SubItems[1].Text = AcquiredStream.GetSourceName();
skyscraperContext.PatDecoder.OnValidSection += PsiDecoder_OnValidSection;
skyscraperContext.PatDecoder.OnCrcError += PsiDecoder_OnCrcError;
pmtCounter = new PmtCounter();
skyscraperContext.PmtDecoderTransformer = pmtCounter;
skyscraperContext.CatDecoder.OnValidSection += PsiDecoder_OnValidSection;
skyscraperContext.CatDecoder.OnCrcError += PsiDecoder_OnCrcError;
skyscraperContext.NitDecoder.OnValidSection += PsiDecoder_OnValidSection;
skyscraperContext.NitDecoder.OnCrcError += PsiDecoder_OnCrcError;
skyscraperContext.Pid0x11Decoder.OnValidSection += PsiDecoder_OnValidSection;
skyscraperContext.Pid0x11Decoder.OnCrcError += PsiDecoder_OnCrcError;
skyscraperContext.Pid0x12Decoder.OnValidSection += PsiDecoder_OnValidSection;
skyscraperContext.Pid0x12Decoder.OnCrcError += PsiDecoder_OnCrcError;
DrawBottomCenter();
pidListView_ColumnClick(this, new ColumnClickEventArgs(0));
AcquiredStream.StartSource(skyscraperContext);
}
private long patErrors, catErrors, nitErrors, sdtErrors, batErrors, eitErrors;
private void PsiDecoder_OnCrcError(PsiSection section, int pid, long available)
{
switch (section.TableId)
{
case 0: patErrors++; break;
case 1: catErrors++; break;
case 0x40: nitErrors++; break;
case 0x41: nitErrors++; break;
case 0x42: sdtErrors++; break;
case 0x46: sdtErrors++; break;
case 0x4a: batErrors++; break;
default:
if (section.TableId >= 0x4e && section.TableId <= 0x6f)
{
eitErrors++;
break;
}
throw new NotImplementedException();
}
}
private long patValids, catValids, nitValids, sdtValids, batValids, eitValids;
private void PsiDecoder_OnValidSection(PsiSection section, int pid, long available)
{
switch (section.TableId)
{
case 0: patValids++; break;
case 1: catValids++; break;
case 0x40: nitValids++; break;
case 0x41: nitValids++; break;
case 0x42: sdtValids++; break;
case 0x46: sdtValids++; break;
case 0x4a: batValids++; break;
default:
if (section.TableId >= 0x4e && section.TableId <= 0x6f)
{
eitValids++;
break;
}
throw new NotImplementedException();
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
AcquiredStream.StopSource();
}
private void timer1_Tick(object sender, EventArgs e)
{
windowOpenDuration = windowOpenDuration.Add(new TimeSpan(0, 0, 1));
bottomLeft.Items[1].SubItems[1].Text = windowOpenDuration.ToString();
DrawBottomCenter();
RenderPidList();
bottomLeft.Items[2].SubItems[1].Text = AcquiredStream.State.ToString();
}
private string bottomCenterTemplate;
private void DrawBottomCenter()
{
if (string.IsNullOrWhiteSpace(bottomCenterTemplate))
{
bottomCenterTemplate = bottomCenter.Text;
}
long patSections = patValids;
long pmtSections = pmtCounter.ValidSection; ;
long catSections = catValids;
long nitSections = nitValids;
long sdtSections = sdtValids;
long eitSections = eitValids;
long patCrcErrors = patErrors;
long pmtCrcErrors = pmtCounter.CrcErrors;
long catCrcErrors = catErrors;
long nitCrcErrors = nitErrors;
long sdtCrcErrors = sdtErrors;
long eitCrcErrors = eitErrors;
long continuityErrors = this.continuityErrors;
string muxBitrate = "???";
long teiErrors = this.teiCounterFilter.TransportErrors;
string lastSec = RenderPacketsPerSecond();
long syncLosses = 0;
long inBuffer = 0;
long outBuffer = 0;
bottomCenter.Text = String.Format(bottomCenterTemplate, patSections, pmtSections, catSections, nitSections, sdtSections, eitSections, patCrcErrors,
pmtCrcErrors, catCrcErrors, nitCrcErrors, sdtCrcErrors, eitCrcErrors, continuityErrors, muxBitrate, teiErrors, lastSec, syncLosses, inBuffer, outBuffer);
}
private char[] dataUnits = { 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q' };
private string RenderPacketsPerSecond()
{
if (!packetsPerSecondCounter.Ready)
{
return "???";
}
long packetsPerSecond = packetsPerSecondCounter.PacketsPerSecond;
long bytesPerSecond = packetsPerSecond * 188;
long bitsPerSecond = bytesPerSecond * 8;
if (bitsPerSecond < 1000)
{
return String.Format("{0} bits/s", bytesPerSecond);
}
int unitOffset = -1;
while (bitsPerSecond > 1000)
{
bitsPerSecond /= 1000;
unitOffset++;
}
return String.Format("{0} {1}bits/s", bitsPerSecond, dataUnits[unitOffset]);
}
private PidListViewItem[] listViewItems;
private Color scrambledColor = Color.FromArgb(255, 255, 128, 128);
private Color unscrambledColor = Color.FromArgb(255, 128, 255, 128);
private void RenderPidList()
{
if (listViewItems == null)
listViewItems = new PidListViewItem[0x2000];
ulong[] ulongs = tsContext.GetPidStatistics();
for (int i = 0; i < 0x2000; i++)
{
if (ulongs[i] != 0)
{
if (listViewItems[i] == null)
{
listViewItems[i] = new PidListViewItem(i);
pidListView.Items.Add(listViewItems[i]);
}
listViewItems[i].SetPackageStats(ulongs[i], packetsPerSecondCounter.TotalPacketsOverall);
listViewItems[i].BackColor = scrambleCounter.IsScrambled(i) ? scrambledColor : unscrambledColor;
}
if (uiJunction.PidToPrograms != null && uiJunction.SdtNames != null)
{
if (uiJunction.PidToPrograms.ContainsKey(i))
{
uint program = uiJunction.PidToPrograms[i];
if (uiJunction.SdtNames.ContainsKey(program))
{
listViewItems[i].ProgramName = uiJunction.SdtNames[program];
}
}
}
if (uiJunction.UsageLabels != null)
{
if (uiJunction.UsageLabels.ContainsKey(i))
{
if (listViewItems[i] != null)
{
listViewItems[i].UsageLabel = uiJunction.UsageLabels[i];
}
}
}
}
}
private PidListViewItemSorter lvwColumnSorter;
private void pidListView_ColumnClick(object sender, ColumnClickEventArgs e)
{
if (lvwColumnSorter == null)
{
lvwColumnSorter = new PidListViewItemSorter();
pidListView.ListViewItemSorter = lvwColumnSorter;
}
if (e.Column == lvwColumnSorter.SortColumn)
{
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
pidListView.Sort();
}
SkyscraperUiNode INodeEngine.EnsureNodeExists(params string[] path)
{
SkyscraperUiNode result = null;
if (IsDisposed)
return null;
Invoke(new Action(() => { result = EnsureNodeExistsEx(path); }));
return result;
}
private SkyscraperUiNode EnsureNodeExistsEx(params string[] path)
{
TreeNodeCollection rootNodes = treeView1.Nodes;
SkyscraperUiNode parent = null;
for (int i = 0; i < path.Length; i++)
{
SkyscraperUiNode foundNode = null;
if (i == 0)
{
foreach (TreeNode rootNode in rootNodes)
{
if (rootNode.Text.Equals(path[i]))
{
foundNode = (SkyscraperUiNode)rootNode;
break;
}
}
if (foundNode == null)
{
foundNode = new SkyscraperUiNode();
foundNode.Text = path[i];
rootNodes.Add(foundNode);
}
}
else
{
foreach (TreeNode childNode in parent.Nodes)
{
if (childNode.Text.Equals(path[i]))
{
foundNode = (SkyscraperUiNode)childNode;
break;
}
}
if (foundNode == null)
{
foundNode = new SkyscraperUiNode();
foundNode.Text = path[i];
parent.Nodes.Add(foundNode);
}
}
parent = foundNode;
}
return parent;
}
public void RunOnUiThread(Action action)
{
Invoke(action);
}
private void treeView1_AfterSelect_1(object sender, TreeViewEventArgs e)
{
SkyscraperUiNode node = e.Node as SkyscraperUiNode;
if (node == null)
return;
textBox1.Text = node.DetailedText;
}
public bool TestForNode(params string[] path)
{
TreeNodeCollection rootNodes = treeView1.Nodes;
SkyscraperUiNode parent = null;
for (int i = 0; i < path.Length; i++)
{
SkyscraperUiNode foundNode = null;
if (i == 0)
{
foreach (TreeNode rootNode in rootNodes)
{
if (rootNode.Text.Equals(path[i]))
{
foundNode = (SkyscraperUiNode)rootNode;
break;
}
}
if (foundNode == null)
{
return false;
}
}
else
{
foreach (TreeNode childNode in parent.Nodes)
{
if (childNode.Text.Equals(path[i]))
{
foundNode = (SkyscraperUiNode)childNode;
break;
}
}
if (foundNode == null)
{
return false;
}
}
parent = foundNode;
}
return true;
}
void INodeEngine.SetIcon(SkyscraperUiNode node, int index)
{
RunOnUiThread(() => {
node.ImageIndex = index;
node.SelectedImageIndex = index;
});
}
}
}