-
Notifications
You must be signed in to change notification settings - Fork 0
Home
.NET library and tooling for parsing, filtering, converting, and restriping MXF, teletext, and subtitle formats used in broadcast workflows.
Repo: nathanpbutler/libopx
Type: .NET 9 library + CLI + GUI applications
| What you want to do | Command / API |
|---|---|
| Filter teletext by magazine/rows | opx filter -m 8 -r 20-22 input.vbi |
| Extract streams from MXF | opx extract -d -n -o out input.mxf |
| Restripe MXF timecodes | opx restripe -t 10:00:00:00 input.mxf |
| Convert between formats | opx convert input.vbi output.t42 |
| Parse lines (library) | FormatIO.Open("file.vbi").ParseLinesAsync() |
| Parse packets (library) | FormatIO.Open("file.mxf").ParsePacketsAsync() |
| Run Blazor GUI | dotnet run --project apps/opxBlazor |
| Run desktop restriper | dotnet run --project apps/simpleRestriper |
| Component | Path | Purpose |
|---|---|---|
| libopx (NuGet) | lib/ |
Core library -- format parsing, conversion, restriping |
| opx CLI | apps/opx/ |
Command-line tool wrapping the library |
| opxBlazor | apps/opxBlazor/ |
Blazor Server GUI for filtering and viewing teletext |
| simpleRestriper | apps/simpleRestriper/ |
Avalonia desktop app for batch MXF timecode restriping |
| Format | Extension | Type | Read | Write |
|---|---|---|---|---|
| VBI | .vbi |
Line-based | Yes | Yes |
| VBI Double | .vbid |
Line-based | Yes | Yes |
| T42 | .t42 |
Line-based | Yes | Yes |
| ANC | .bin |
Packet-based | Yes | -- |
| MXF | .mxf |
Packet-based | Yes | Restripe |
| TS | .ts |
Packet-based | Yes | -- |
| RCWT | .rcwt |
Output | -- | Yes |
| STL | .stl |
Output | -- | Yes |
-
.NET 9 SDK -- Runtime and build toolchain. SDK version pinned via
global.json(rollForward: latestMajor).
Zero external NuGet dependencies. Only build-time SourceLink for symbol generation.
- System.CommandLine (v2.0.2) -- Command-line argument parsing
- MudBlazor (v9.1.0) -- Material Design UI components
- Targets .NET 10.0
- Avalonia (v11.3.*) -- Cross-platform desktop UI framework
- Targets .NET 10.0
dotnet add package libopxgit clone https://github.com/nathanpbutler/libopx.git
cd libopx
dotnet build libopx.slndotnet publish apps/opx -c Release -r win-x64 --self-contained
dotnet publish apps/opx -c Release -r linux-x64 --self-contained
dotnet publish apps/opx -c Release -r osx-x64 --self-containedVerify: dotnet test tests/libopx.Tests.csproj -- all tests should pass.
No external configuration files. All settings are code-based constants or passed via CLI arguments / API parameters.
Key defaults defined in Constants.cs:
| Constant | Value | Purpose |
|---|---|---|
| Default magazine | 8 | Magazine filter when none specified |
| Caption rows | 1--24 | Row range for -c / caps mode |
| VBI line size | 720 bytes | Single-width VBI |
| VBI double line size | 1440 bytes | Double-width VBI |
| T42 line size | 42 bytes | Teletext packet size |
| KLV key size | 16 bytes | MXF key length |
opx filter -m 1 -r 0,23 input.vbi
cat input.vbi | opx filter -c
opx filter --pid 70 input.tsopx extract -k d,v input.mxf
opx extract -d -n -o output_base input.mxf
opx extract -d --klv input.mxfopx restripe -t 10:00:00:00 input.mxf
opx restripe -t 00:00:00:00 -pp input.mxfopx convert input.vbi output.t42
opx convert -c input.mxf output.stl
opx convert --pid 70 input.ts output.t42
opx convert -m 8 -r 20-22 input.t42 output.vbi// Async line parsing with filtering
using var io = FormatIO.Open("input.vbi")
.Filter(magazine: 8, rows: [20, 21, 22]);
await foreach (var line in io.ParseLinesAsync())
Console.WriteLine(line);
// Format conversion
using var converter = FormatIO.Open("input.vbi")
.Filter(useCaps: true)
.ConvertTo(Format.STL);
await converter.SaveToAsync("output.stl");
// MXF packet parsing with key filtering
using var mxf = FormatIO.Open("input.mxf")
.WithKeys(KeyType.Data);
await foreach (var packet in mxf.ParsePacketsAsync())
Console.WriteLine(packet);
// MXF restripe
FormatIO.Open("input.mxf").Restripe("10:00:00:00");dotnet run --project apps/opxBlazorOpen http://localhost:5000. Upload a file, set magazine/row/page filters, and view results in the data grid.
dotnet run --project apps/simpleRestriperDrag-drop MXF files, enter a new timecode (or check "Zero"), and click Restripe. Progress bars track each file.
dotnet test tests/libopx.Tests.csproj # All tests
dotnet test --filter "MemoryBenchmarkTests" # Memory profiling
dotnet test --filter "FormatIOTests" # Specific test classTest sample files are downloaded automatically from GitHub releases via SampleFiles.EnsureAsync(). Set OPX_SAMPLES_VERSION to pin a specific version (defaults to v1.0.0).
| Symptom | Likely cause | Fix |
|---|---|---|
| CS0618 warnings during build | Deprecated SMPTE APIs still referenced in MXF.cs and tests | Expected -- safe to ignore |
| Test failures on first run | Sample files not downloaded | Ensure network access for SampleFiles.EnsureAsync()
|
InvalidOperationException on convert |
Unsupported format conversion pair | Check supported conversion routes: VBI/T42 to RCWT/STL/VBI/T42 |
| MXF restripe fails | File opened read-only | Use FormatIO.Open(path).Restripe() which opens read-write internally |
| Timecode validation error | Drop-frame mismatch or out-of-range frames | Verify timecode format matches file's frame rate and drop-frame mode |
| TS parsing returns no lines | Wrong PID | Use --pid to specify the teletext PID, or omit for auto-detection via PAT/PMT |