Analyze and Validate MPEG-TS Streams in C# .NET¶
Overview¶
This guide shows how to analyze and validate an MPEG-TS transport stream from C# using the Media Blocks SDK .NET TSAnalyzerBlock. You will:
- Analyze a local
.ts/.m2tsfile and read the final report. - Monitor a live
udp://orsrt://feed with periodic updates. - Read ETSI TR 101 290 results and raise an alert when the stream is non-compliant.
- Analyze a feed while you record it using passthrough mode.
For the full API reference (every setting and report field), see the MPEG-TS Stream Analyzer Block page.
Prerequisites¶
Install the Media Blocks SDK NuGet package and the platform runtime package:
VisioForge.DotNet.MediaBlocks- A platform runtime, e.g.
VisioForge.CrossPlatform.Core.Windows.x64on Windows.
Initialize the SDK once at startup:
using VisioForge.Core;
await VisioForgeX.InitSDKAsync();
The namespaces used throughout this guide:
using System;
using System.Linq;
using VisioForge.Core.MediaBlocks;
using VisioForge.Core.MediaBlocks.Sources;
using VisioForge.Core.MediaBlocks.Special;
using VisioForge.Core.Types.X;
using VisioForge.Core.Types.X.Sources;
using VisioForge.Core.Types.X.Special;
1. Analyze a file¶
For a file, run the pipeline to end-of-stream and read the final report. Connect the analyzer in Input mode (terminal):
var pipeline = new MediaBlocksPipeline();
var source = new BasicFileSourceBlock("stream.ts");
var analyzer = new TSAnalyzerBlock(TSAnalyzerMode.Input);
// Signal completion when the pipeline stops on its own (end-of-stream).
var completed = new TaskCompletionSource<bool>();
pipeline.OnStop += (s, e) => completed.TrySetResult(true);
pipeline.Connect(source.Output, analyzer.Input);
await pipeline.StartAsync();
await completed.Task; // wait for end-of-stream
await pipeline.StopAsync();
TSAnalyzerReport report = analyzer.GetReport();
Console.WriteLine($"Packet size: {report.PacketSize} | total: {report.TotalBitrateKbps:F0} kbps");
Console.WriteLine($"Programs: {report.Programs.Count} | PAT: {(report.HasPAT ? "yes" : "no")}");
foreach (var program in report.Programs)
{
var name = string.IsNullOrEmpty(program.ServiceName) ? "(no name)" : program.ServiceName;
Console.WriteLine($"Program {program.ProgramNumber} \"{name}\" (PMT {program.PmtPid}, PCR {program.PcrPid})");
foreach (var es in program.Streams)
{
var lang = string.IsNullOrEmpty(es.Language) ? "" : $" [{es.Language}]";
Console.WriteLine($" PID {es.Pid} {es.Kind} {es.Codec}{lang}");
}
}
2. Monitor a live stream¶
For a live udp:// or srt:// feed, subscribe to OnAnalysisUpdated and read each periodic snapshot. Set StatisticsInterval to control the cadence.
var pipeline = new MediaBlocksPipeline();
// Live UDP multicast (raw MPEG-TS, no demux)
var source = new UDPRAWMPEGTSSourceBlock(new UDPRAWMPEGTSSourceSettings("udp://239.0.0.1:1234"));
var analyzer = new TSAnalyzerBlock(
TSAnalyzerMode.Input,
new TSAnalyzerSettings { StatisticsInterval = TimeSpan.FromSeconds(1) });
analyzer.OnAnalysisUpdated += (sender, e) =>
{
if (e.IsFinal)
{
return; // end-of-stream report; periodic snapshots have IsFinal == false
}
TSAnalyzerReport report = e.Report;
Console.WriteLine(
$"{report.TotalBitrateKbps:F0} kbps total, " +
$"{report.EffectiveBitrateKbps:F0} kbps effective, " +
$"programs: {report.Programs.Count}");
};
pipeline.Connect(source.Output, analyzer.Input);
await pipeline.StartAsync();
// ... keep running while you monitor ...
To feed SRT instead of UDP, swap the source:
var srtSettings = await SRTSourceSettings.CreateAsync(new Uri("srt://server:9000"), ignoreMediaInfoReader: true);
var source = new SRTRAWSourceBlock(srtSettings);
Threading. Periodic
OnAnalysisUpdatedcallbacks run on a background timer thread. In a UI app, marshal to the UI thread before updating controls — e.g.Dispatcher.BeginInvoke(() => UpdateUI(e.Report));in WPF.
3. Read TR 101 290 and alert on errors¶
The TR 101 290 report groups errors by priority. A common pattern is to alert whenever a Priority 1 (critical) error appears, and to log the individual failing checks:
analyzer.OnAnalysisUpdated += (sender, e) =>
{
var tr = e.Report.Tr101290;
if (tr == null || tr.AllOk)
{
return; // TR 101 290 disabled, or the stream is fully compliant
}
if (tr.P1Count > 0)
{
RaiseAlert($"Critical TR 101 290 (P1) errors: {tr.P1Count}");
}
foreach (var check in tr.Checks.Where(c => c.Count > 0))
{
Console.WriteLine($"P{check.Priority} {check.Name}: {check.Count}");
}
};
tr.P1Count / P2Count / P3Count give you the per-priority totals; tr.Checks lets you drill into a specific failing measurement (for example PCR_repetition_error or Continuity_count_error). Use tr.AllOk as a single-line compliance gate.
4. Analyze while recording (passthrough)¶
To validate a feed and record it in the same pipeline, create the analyzer in InputOutput mode and connect its Output to a sink. The transport stream is forwarded unchanged, so the recording is a bit-exact copy:
var pipeline = new MediaBlocksPipeline();
var source = new UDPRAWMPEGTSSourceBlock(new UDPRAWMPEGTSSourceSettings("udp://239.0.0.1:1234"));
// Passthrough analyzer: forwards the stream while analyzing it
var analyzer = new TSAnalyzerBlock(TSAnalyzerMode.InputOutput);
analyzer.OnAnalysisUpdated += (s, e) => { /* monitor while recording */ };
var sink = new MPEGTSSinkBlock(new MPEGTSSinkSettings("recording.ts"));
pipeline.Connect(source.Output, analyzer.Input);
pipeline.Connect(analyzer.Output, sink.Input);
await pipeline.StartAsync();
Troubleshooting¶
HasPATis false / no programs. The input is probably not a valid MPEG-TS byte stream, or the packet size was misdetected. Force it viaTSAnalyzerSettings.PacketSize(Size188orSize192), or check the source URI.- Many
PCR_repetition_errorentries on a valid file. This is expected when the muxer emits PCR slower than the 40 ms TR 101 290 limit (common for file-oriented muxing). The stream still plays; it is simply not 40 ms-PCR compliant. GetReport()returns null. The block has not been built yet — call it afterStartAsync().- No multicast packets received. Verify
AutoJoinMulticastistrue(the default) and setMulticastInterfaceif the host has multiple network interfaces. - High CPU on a heavy stream. Disable stages you do not need via
TSAnalyzerSettings—ParseEPGis off by default; you can also turn offParseCodecDetailsorTrackPtsDts.
Frequently asked questions¶
How do I analyze a live UDP multicast MPEG-TS stream in C#?¶
Create a UDPRAWMPEGTSSourceBlock with a udp://group:port URI, connect its Output to a TSAnalyzerBlock in Input mode, and subscribe to OnAnalysisUpdated for periodic snapshots. See section 2.
Can I check ETSI TR 101 290 compliance from .NET?¶
Yes. With ValidateTR101290 enabled (the default), report.Tr101290 exposes the Priority 1/2/3 check list with per-check counts and pass/fail status, plus P1Count/P2Count/P3Count totals and an AllOk flag. See section 3.
Can I record a stream and analyze it at the same time?¶
Yes. Use TSAnalyzerMode.InputOutput and connect the analyzer's Output to a sink such as MPEGTSSinkBlock. The stream is forwarded unchanged. See section 4.
See also¶
- MPEG-TS Stream Analyzer Block — the complete block reference.
- MPEG-TS Analysis in C#: VisioForge vs ffprobe — positioning and feature comparison.