Why I built scte35-injector
If you’re working with video streams, especially MPEG-TS (transport streams), you may have heard of SCTE-35. It’s a widely used standard to embed cue-messages in video streams, indicating where to splice in content commonly for ad breaks, program boundaries, blackouts, or regional content insertion.
Lately I spent a lot of time with SCTE-35 and SCTE-250, with event handling and program control flow in live streams. There is a constant need for test assets, and I needed ways to fabricate them. While there are existing SCTE-35 tools and libraries to parse or manipulate these cues like threefive, tsp or SuperKabuki, I found myself needing a simpler command-line tool to inspect or inject SCTE-35 cues in MPEG-TS files without depending on heavy tools or libs. Thus, scte35-injector was born: a lightweight CLI tool written in Rust for exactly that.
In short: I wanted a “TSDuck-style” utility but focused specifically on SCTE-35, easy to use, and reliable.
What scte35-injector does
scte35-injector is a command-line tool that can:
- List existing SCTE-35 cues in a given MPEG-TS file (by detecting cues in PSI or PES tables).
- Inject new cues*: insert new base64-encoded
splice_info_sectionmessages at specified timestamps. You can control where (on the TS timeline) to insert packets, and optionally rewrite the internalsplice_timeinside the cue. - Auto-add an SCTE-35 PID if none exists: the tool will allocate a free PID ≥ 0x30, rewrite the PMT accordingly (with CRC, correct descriptor), and update continuity counters as needed.
- Work incrementally: it processes TS packets as a stream. No full-file buffering, so even large transport-streams can be handled efficiently.
- Run tests: the repo includes unit, edge and end-to-end tests, as well as sample fixture files under
test-assets/, to ensure correct behavior.
It’s cross-platform, and doesn’t require FFmpeg or other heavy multimedia dependencies. That was a conscious design decision to keep it minimal and robust.
Tradeoffs & Limitations
- The tool is offline only: designed for file-based TS processing. It’s not a live-streaming inserter (so no real-time ad-insertion out of the box).
- No bitrate shaping / null-packet padding: injecting packets may change stream bitrate. If you need strict bit-rate constraints, external padding may be required.
- No built-in support for multi-program TS. For streams with multiple programs or services, scte35-injector may not (yet) be suitable.
These tradeoffs are part of the design: I wanted something simple, predictable, and maintainable rather than a full-featured streaming solution.
How to Use It
scte35-injector --input input.ts \
--output output.ts \
--cue "00:00:25.000@00:00:30.000=/DAWAAAAAAAAAP/wBQb+Qjo1vQAAuwxz9A=="
This command will: at 25 seconds (on the TS timeline), insert SCTE-35 packets, rewriting the internal splice_time to 30 seconds (so downstream players/readers see the cue as “splice at 00:00:30”).
If you only want to list cues in a file:
scte35-injector --input input.ts --list-cues
It will print out existing cues (if any) with their PTS and base64 payloads.