{"id":41783760,"url":"https://github.com/nathanpbutler/libopx","last_synced_at":"2026-01-25T04:07:22.684Z","repository":{"id":307935841,"uuid":"1030573067","full_name":"nathanpbutler/libopx","owner":"nathanpbutler","description":"MXF and Teletext caption processing library","archived":false,"fork":false,"pushed_at":"2026-01-19T23:11:19.000Z","size":1671,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-20T05:20:56.005Z","etag":null,"topics":["captions","mxf","smpte","smpte-timecode","subtitles","t42","teletext","vbi"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nathanpbutler.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-08-01T22:03:13.000Z","updated_at":"2026-01-19T23:11:17.000Z","dependencies_parsed_at":"2025-08-03T06:25:35.695Z","dependency_job_id":"aedd1ae5-34f2-4369-9a61-345010af95ac","html_url":"https://github.com/nathanpbutler/libopx","commit_stats":null,"previous_names":["nathanpbutler/libopx"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/nathanpbutler/libopx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanpbutler%2Flibopx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanpbutler%2Flibopx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanpbutler%2Flibopx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanpbutler%2Flibopx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nathanpbutler","download_url":"https://codeload.github.com/nathanpbutler/libopx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanpbutler%2Flibopx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28742983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-25T02:46:29.005Z","status":"ssl_error","status_checked_at":"2026-01-25T02:44:29.968Z","response_time":113,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["captions","mxf","smpte","smpte-timecode","subtitles","t42","teletext","vbi"],"created_at":"2026-01-25T04:07:22.622Z","updated_at":"2026-01-25T04:07:22.677Z","avatar_url":"https://github.com/nathanpbutler.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libopx\n\n[![NuGet](https://img.shields.io/nuget/v/libopx?style=flat-square)](https://www.nuget.org/packages/libopx)\n[![GitHub Release](https://img.shields.io/github/v/release/nathanpbutler/libopx?style=flat-square)](https://github.com/nathanpbutler/libopx/releases)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/nathanpbutler/libopx/ci.yml?branch=main\u0026style=flat-square)](https://github.com/nathanpbutler/libopx/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)\n[![.NET](https://img.shields.io/badge/.NET-9-blue?style=flat-square)](https://dotnet.microsoft.com/download/dotnet/9.0)\n\nA .NET 9 C# library for parsing and extracting data from MXF (Material Exchange Format) files and their ancillary data streams (ANC), raw Vertical Blanking Interval (VBI), Teletext packet stream (T42), and MPEG-TS (Transport Stream) files, with SMPTE timecode and Teletext caption support.\n\n## Why \"opx\"?\n\nThe **opx** in libopx is a play on both MXF's \"Operational Pattern\" designations, such as **OP-1a** and **OP-Atom**, and the Free TV Australia \"Operational Practice\" standards **OP-42** and **OP-47** for closed captions and Teletext subtitles (the primary focus of this library).\n\n## Features\n\n- **Multi-format support**: MXF, ANC, VBI, T42, and MPEG-TS file parsing\n- **Format and Subtitle conversion**: Automatic VBI ↔ T42 conversion, plus RCWT (Raw Captions With Time) and EBU STL output\n- **MPEG-TS teletext extraction**: Automatic PAT/PMT parsing with DVB teletext support\n- **Teletext filtering**: Magazine and row-based filtering with Unicode mapping\n- **SMPTE timecode**: Full timecode calculations with various frame rates\n- **MXF processing**: Stream extraction and demuxing capabilities\n- **CLI tool**: Unified `opx` command-line interface for easy access to all features\n\nConvert between HD and SD T42 and VBI formats or vice versa. You can even pipe that data to other applications like `ffmpeg` or `mpv`.\n\n## Examples\n\n**Piping Teletext Data**: Extract ancillary data from an MXF file, convert it to vertical blanking interval (VBI) format, and pipe it directly to `mpv` for display:\n\n![Piping Example](https://raw.githubusercontent.com/nathanpbutler/libopx/main/assets/mpv-piping-example.jpg)\n\n**ANSI Escaped Teletext**: Supports parsing and filtering of teletext data with ANSI escape sequences:\n\n![VHS Teletext Comparison](https://raw.githubusercontent.com/nathanpbutler/libopx/main/assets/filtering.png)\n\n## Quick Start\n\n### Installation\n\nAdd the package reference to your project file from [NuGet.org](https://www.nuget.org/packages/libopx).\n\n```bash\ndotnet add package libopx\n```\n\nOr download the latest release from [GitHub Releases](https://github.com/nathanpbutler/libopx/releases).\n\n### Using the CLI Tool\n\n```bash\n# Filter teletext data by magazine and rows\nopx filter -m 8 -r 20,22 input.vbi\n\n# Filter MPEG-TS teletext (auto-detects PIDs)\nopx filter input.ts\n\n# Filter MPEG-TS with specific PID\nopx filter --pid 70 input.ts\n\n# Convert between formats (auto-detected from extension)\nopx convert input.vbi output.t42\n\n# Convert MPEG-TS to T42\nopx convert --pid 70 input.ts output.t42\n\n# Convert to EBU STL subtitle format\nopx convert -c input.mxf output.stl\n\n# Extract specific streams from MXF files (data, video, audio, etc.)\nopx extract -k d,v input.mxf\n```\n\n### Using the Library\n\n**New in v2.4.0:** FormatIO fluent API provides a unified, simplified interface for all teletext operations.\n\n```csharp\nusing nathanbutlerDEV.libopx;\n\n// Parse and filter teletext data (auto-detects format from extension)\nusing var io = FormatIO.Open(\"input.vbi\");\nforeach (var line in io.ParseLines(magazine: 8, rows: [20, 22]))\n{\n    Console.WriteLine(line.Text);\n}\n\n// Filter and convert in one pass\nusing var io2 = FormatIO.Open(\"input.vbi\")\n    .Filter(magazine: 8, rows: [20, 22])\n    .ConvertTo(Format.T42);\nio2.SaveTo(\"output.t42\");\n\n// Parse MPEG-TS with PID filtering\nusing var io3 = FormatIO.Open(\"input.ts\")\n    .WithPIDs(70);\nforeach (var line in io3.ParseLines(magazine: 8))\n{\n    Console.WriteLine(line.Text);\n}\n\n// Convert to EBU STL subtitle format\nusing var io4 = FormatIO.Open(\"input.mxf\");\nawait io4.ConvertTo(Format.STL)\n    .Filter(magazine: 8, rows: [20, 21, 22, 23, 24])\n    .SaveToAsync(\"output.stl\");\n```\n\n**Migration Note:** The old API (`new VBI()`, `new T42()`, etc.) is deprecated but still works in v2.4.0 with warnings. It will be removed in v3.0.0. See [CHANGELOG.md](CHANGELOG.md) for migration details.\n\n## Documentation\n\n- **[Library Documentation](lib/README.md)** - Detailed API reference and usage examples\n- **[CLI Tool Documentation](apps/opx/README.md)** - Complete command reference and examples\n\n## Project Structure\n\n```plaintext\nlibopx/            # Root directory\n├── .github/       # GitHub configuration\n│   └── workflows/ # CI workflows\n├── apps/opx/      # CLI tool\n├── assets/        # Images and media samples for documentation\n├── docs/          # Documentation files\n├── lib/           # Main library\n│   ├── Core/      # Core functionality\n│   ├── Enums/     # Enumerations\n│   ├── Formats/   # Format parsers (MXF, ANC VBI, T42, TS)\n│   ├── Handlers/  # Data handlers\n│   └── SMPTE/     # SMPTE metadata system\n├── scripts/       # Development scripts\n└── tests/         # xUnit test suite\n    ├── Core/      # Core tests\n    ├── Formats/   # Format parser tests\n    └── Handlers/  # Data handler tests\n```\n\n## Development\n\n```bash\n# Clone and build\ngit clone https://github.com/nathanpbutler/libopx\ncd libopx\ndotnet build\n\n# Run tests\ndotnet test\n```\n\n## Requirements\n\n- .NET 9 or later\n- Supported platforms: Windows, Linux, macOS\n\n## Dependencies\n\n- System.CommandLine (v2.0.0) (command-line parsing)\n- xUnit (testing)\n- coverlet (code coverage)\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Ensure all tests pass\n6. Submit a pull request\n\n## License\n\nMIT - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- **[vhs-teletext](https://github.com/ali1234/vhs-teletext)** - Software to recover teletext data from VHS recordings (inspiration for `filter` command)\n- **[MXFInspect](https://github.com/Myriadbits/MXFInspect)** - Tool for displaying the internal structure of MXF files (was super helpful for understanding MXF parsing and the intricacies of SMPTE timecodes)\n- **[bmxtranswrap](https://github.com/bbc/bmx)** - BBC's MXF processing library and utilities (inspiration for `extract` command)\n- **[SubtitleEdit](https://github.com/SubtitleEdit/subtitleedit)** - An incredibly useful C# library and software for subtitle editing and processing\n- **[CCExtractor](https://github.com/CCExtractor/ccextractor)** - Closed caption and subtitle extraction and processing\n- **[ffmpeg](https://ffmpeg.org/)** - The swiss army knife of multimedia processing\n\n## Support\n\nFor questions and support, please [open an issue](https://github.com/nathanpbutler/libopx/issues).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanpbutler%2Flibopx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnathanpbutler%2Flibopx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanpbutler%2Flibopx/lists"}