tstrans
Python bindings (via PyO3) for the ts-transformer Rust workspace.
Status:
tstranscovers file inspection + construction (Demuxer/Muxer/MuxerFileSink), typed KLV decode + encode for ST 0601 / ST 0102 / ST 0605 / ST 0903 (withVTargetPack), codec parsers for H.264 / H.265 / H.266 / AV1 / AAC / MPEG-2 audio, optional pandas DataFrame adapters + NumPy snapshot views viapip install tstrans[pandas], and live transports: SRT (tstrans.srt— Sender / Receiver / Builder / Socket / Listener / MuxSender / DemuxReceiver + Managed* auto-reconnect + ReconnectPolicy), RTP + RTSP (tstrans.rtp— Sender / Receiver / MuxSender / DemuxReceiver / RtspClient / RtspServer / MountHandle), raw UDP / TCP / RIST (tstrans.udp/tstrans.tcp/tstrans.rist), and HLS publishing (tstrans.hls). Minimum Python 3.10.
Install
pip install tstrans
Optional extras for DataFrame / NumPy integration:
pip install 'tstrans[pandas]'
Quickstart
Inspect a .ts file:
from tstrans.io import parse_file, probe
from tstrans.mpegts import DemuxEvent
# Quick summary
r = probe("capture.ts")
print(r.video_codecs, r.audio_codecs, r.has_klv)
# Full event stream
for event in parse_file("capture.ts"):
match event:
case DemuxEvent.Video(pts=p, codec=c, raw=b):
print(f"Video {c.name} pts={p.ms}ms len={len(b)}")
case DemuxEvent.Metadata(pts=p, payload=b):
print(f"KLV pts={p.ms}ms len={len(b)}")
Build a .ts file (single-program H.264):
from tstrans.mpegts import (
Muxer,
MuxerConfigBuilder,
MuxerProgramConfigBuilder,
Pts90khz,
VideoCodec,
)
prog = (
MuxerProgramConfigBuilder(program_number=1, pmt_pid=0x100)
.add_video(0x101, VideoCodec.H264)
.build()
)
cfg = MuxerConfigBuilder().add_program(prog).build()
m = Muxer(cfg)
with m.write_file("out.ts") as proxy:
proxy.push_video(nal_bytes, pts=Pts90khz.from_raw(900_000), key_frame=True)
RTP + RTSP transport
tstrans.rtp ships RTP-over-UDP and a full RTSP client + server. Available
by default in published wheels — no extra needed (pip install tstrans
already includes it). The Rust-side rtp cargo feature is on by default;
source builds that don't need it can opt out with
maturin develop --no-default-features for a smaller binary.
Connect to a camera and iterate demuxed events:
from tstrans.rtp import RtspClient, RtspClientConfig
from tstrans.mpegts import DemuxEvent
cfg = RtspClientConfig(url="rtsp://camera.local/live")
with RtspClient.connect(cfg) as session:
demux = session.into_demux_receiver()
for event in demux:
if isinstance(event, DemuxEvent.Video):
handle(event.raw)
Publish a stream from your own RTSP server:
from tstrans.rtp import RtspServer, RtspServerConfig
from tstrans.mpegts import MuxerProgramConfigBuilder, Pts90khz, VideoCodec
program = (
MuxerProgramConfigBuilder(1, 0x100)
.add_video(0x101, VideoCodec.H264)
.build()
)
with RtspServer.start(RtspServerConfig(bind_addr="0.0.0.0:8554")) as server:
mount = server.add_unicast_mount("/live", program)
mount.push_video(nal_bytes, pts=Pts90khz.from_raw(0), key_frame=True)
The full surface — Sender / Receiver for raw RTP, MuxSender /
DemuxReceiver for one-call mux/demux convenience, RtspClient /
RtspSession with Basic + Digest auth and TCP-interleaved fallback,
RtspServer + MountHandle with five push methods (each with a _to
multi-stream twin) and multicast mounts — is documented in the per-class
docstrings and the python/tstrans/rtp.pyi type stubs (checked against the
runtime by mypy.stubtest in CI).
SRT transport
tstrans.srt ships full SRT (Secure Reliable Transport) bindings on top
of libsrt 1.5.7 — classes spanning low-level Builder / Socket /
Listener primitives, high-level Sender / Receiver for raw bytes,
MuxSender / DemuxReceiver for one-call mux/demux convenience, and
ManagedSender / ManagedReceiver / ManagedMuxSender /
ManagedDemuxReceiver for auto-reconnect-with-gap-buffer ergonomics.
Available by default in published wheels — no extra needed
(pip install tstrans already includes it). The Rust-side srt cargo
feature is on by default; source builds that don't need SRT can opt
out with maturin develop --no-default-features for a smaller binary
that drops the libsrt + mbedTLS link.
Hello world — caller-side send + listener-side receive:
import threading
import tstrans.srt
# Listener side (run on one host / thread):
def listen_side() -> None:
with tstrans.srt.Receiver.from_url("srt://0.0.0.0:9000?mode=listener") as rx:
chunk = rx.recv_bytes(max_len=1500)
print(f"received {len(chunk)} bytes; sync byte = {chunk[0]:#04x}")
threading.Thread(target=listen_side, daemon=True).start()
# Caller side (the other host / thread):
with tstrans.srt.Sender.from_url("srt://127.0.0.1:9000?mode=caller") as tx:
payload = (b"\x47" + b"\x00" * 187) * 7 # one 1316-byte TS bundle
tx.send_bytes(payload)
Full mux + demux example — push H.264 NALs + KLV blobs from the caller,
iterate DemuxEvents on the listener:
import threading
import tstrans.srt
from tstrans.mpegts import (
DemuxEvent, KlvStreamType, MuxerProgramConfigBuilder, Pts90khz, VideoCodec,
)
program = (
MuxerProgramConfigBuilder(program_number=1, pmt_pid=0x100)
.add_video(0x101, VideoCodec.H264)
.add_klv(0x102, KlvStreamType.SYNCHRONOUS_METADATA, carries_pts=True)
.build()
)
def consumer() -> None:
with tstrans.srt.DemuxReceiver.from_url("srt://:9001?mode=listener") as rx:
for event in rx:
if isinstance(event, DemuxEvent.Video):
print(f"video pts={event.pts.ms}ms nals={len(event.parse())}")
elif isinstance(event, DemuxEvent.Metadata):
print(f"klv pts={event.pts.ms}ms len={len(event.payload)}")
threading.Thread(target=consumer, daemon=True).start()
with tstrans.srt.MuxSender.from_url(
"srt://127.0.0.1:9001?mode=caller", program
) as tx:
# tx.send_video / tx.send_klv handle bundling, PSI emission, and
# ts-packet framing transparently.
tx.send_video(nal_bytes, pts=Pts90khz.from_raw(0), key_frame=True)
tx.send_klv(klv_ls_bytes, pts=Pts90khz.from_raw(0))
Builder + Socket promotion for fine-grained control (passphrase,
custom latency, stream id, congestion mode):
import tstrans.srt
# Caller side with encryption + a custom SRT latency.
sock = (
tstrans.srt.Builder("srt://127.0.0.1:9000?mode=caller")
.passphrase("hunter-too-long-thanks!!") # >= 10 chars
.latency_ms(200)
.stream_id("cam-01")
.caller()
.connect()
)
sender = sock.into_sender() # consumes the Socket
sender.send_bytes(b"...")
sender.close()
Auto-reconnect with ManagedReceiver — wraps the underlying SRT
transport in a tst_pipeline::ManagedRecvTransport that catches
connection breaks and re-binds + re-accepts per a ReconnectPolicy;
reconnect_attempts() counts the reconnects. (ManagedDemuxReceiver
also surfaces each reconnect as a DemuxEvent.ReconnectDiscontinuity.)
import tstrans.srt
from tstrans.srt import BackoffStrategy, ReconnectPolicy
policy = ReconnectPolicy(
max_attempts=5,
backoff=BackoffStrategy.exponential(base_ms=100, max_ms=10_000),
)
with tstrans.srt.ManagedReceiver.from_url(
"srt://:9000?mode=listener", policy=policy
) as rx:
while True:
try:
chunk = rx.recv_bytes(max_len=1500)
print(f"received {len(chunk)} bytes; "
f"reconnects so far = {rx.reconnect_attempts()}")
except KeyboardInterrupt:
break
The full surface — Sender / Receiver for raw bytes, MuxSender /
DemuxReceiver for one-call mux/demux, Builder / Socket /
Listener for low-level construction, ManagedSender /
ManagedReceiver / ManagedMuxSender / ManagedDemuxReceiver for
auto-reconnect, plus ReconnectPolicy / BackoffStrategy /
OverflowPolicy policy types and SocketStats / SrtStats /
CancelHandle — is documented in the per-class docstrings and the
python/tstrans/srt.pyi type stubs (checked against the runtime by
mypy.stubtest in CI).
See also
docs/languages/python.md is the full Python guide, including the DataFrame / NumPy integration.
Metadata
Release files for tstrans 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tstrans-0.7.0.tar.gz | 7.1 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| tstrans-0.7.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| tstrans-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| tstrans-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| tstrans-0.7.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 23.4 MB
Release files / tstrans-0.7.0.tar.gz
| Download URL | tstrans-0.7.0.tar.gz |
|---|---|
| Size | 7.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
727ca79c2594359731acb1af0ef35890fce6202c010c9e3715e447bb32a8c28d
|
|
BLAKE2b-256 checksum How to use checksums |
87335d3ea8c207da68fe45bf6719d4fc92bda9af9c3ad3d9c9ccc1a91126c3a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / tstrans-0.7.0-cp310-abi3-win_amd64.whl
| Download URL | tstrans-0.7.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 4.3 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
df4ff4c13f9bb5f186d0065dc4c6dd4c2019413061d6a8fb8c3c370b59b7f93e
|
|
BLAKE2b-256 checksum How to use checksums |
2180bb1bdb0317a2d790f154e554c6d1b5414a850753900ff9b20d2a7e35cb51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / tstrans-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl
| Download URL | tstrans-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 4.3 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
09efaf21b13fe5a442fa8c5a254b36cbc00b2592d1b80bddde01cea7a3c54ea6
|
|
BLAKE2b-256 checksum How to use checksums |
c3a424c18390f4ca99ad8c0236474d04538d03cf41920524793748554b37d53c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / tstrans-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl
| Download URL | tstrans-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 4.1 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
38a4abb61cc4c7e6598409334c11b0ba1ce13b15e0dd011e5c6aec341152554d
|
|
BLAKE2b-256 checksum How to use checksums |
b2a8f5c7c49e42a84bec566405670cd9396a6ad20d076cb0d366ff598d40723c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / tstrans-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | tstrans-0.7.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 3.6 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
143cc746d194b68ef6140bb0038f0f405d7dea36fcb6f61e529e84a3771dd50d
|
|
BLAKE2b-256 checksum How to use checksums |
8efa164865a4ad1c6d0d991bef537c401a4851e776506986c56fdd4744e39b5d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency log