Skip to main content

tstrans

Python bindings (via PyO3) for the ts-transformer Rust workspace.

Status: tstrans covers file inspection + construction (Demuxer / Muxer / MuxerFileSink), typed KLV decode + encode for ST 0601 / ST 0102 / ST 0605 / ST 0903 (with VTargetPack), codec parsers for H.264 / H.265 / H.266 / AV1 / AAC / MPEG-2 audio, optional pandas DataFrame adapters + NumPy snapshot views via pip 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.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tstrans 0.8.0
File Size Uploaded
tstrans-0.8.0.tar.gz 7.3 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for tstrans 0.8.0
File
tstrans-0.8.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
tstrans-0.8.0-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details
tstrans-0.8.0-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details
tstrans-0.8.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details

Total release size: 24.1 MB

Release files / tstrans-0.8.0.tar.gz

Download URL tstrans-0.8.0.tar.gz
Size 7.3 MB
Tags Source
SHA-256 checksum
How to use checksums
c221ec4c826b4b2086d8a0a4504e61914da482018d7afc2e2d271a69b1450bfa
BLAKE2b-256 checksum
How to use checksums
a2b82391cf4bfd39d1dffdedca874e06e8a9da64a699c205e535b364f4a6251e
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 14, 2026.

Transparency log

Release files / tstrans-0.8.0-cp310-abi3-win_amd64.whl

Download URL tstrans-0.8.0-cp310-abi3-win_amd64.whl
Size 4.4 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
4384a55ddc5e7ec5e893ed7d7e08b85d0813466838ef9507a560354a60d8439f
BLAKE2b-256 checksum
How to use checksums
d986edecb471baac6ce23b75213785a345a405d284501ad1dda1dcfc4fc89286
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 14, 2026.

Transparency log

Release files / tstrans-0.8.0-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL tstrans-0.8.0-cp310-abi3-manylinux_2_28_x86_64.whl
Size 4.4 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
e833e7dfb3997cd63e3fba8ffb1f6be729edf60306fbbcb835f7eb601834b6b7
BLAKE2b-256 checksum
How to use checksums
5a4818a0701abcbf37e52a7c65f892f349110b31aad18dad347c086a303aa141
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 14, 2026.

Transparency log

Release files / tstrans-0.8.0-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL tstrans-0.8.0-cp310-abi3-manylinux_2_28_aarch64.whl
Size 4.2 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
22fcfc831b11c4789f01a0112ff0984a207354256c7c71acce01f16933648a81
BLAKE2b-256 checksum
How to use checksums
c57565d7cb76966a0b207df651f3598705db161a1d4c69d0baea980e6aad9e15
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 14, 2026.

Transparency log

Release files / tstrans-0.8.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL tstrans-0.8.0-cp310-abi3-macosx_11_0_arm64.whl
Size 3.7 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
b749d655f25757805bdbfb147eac78a5f6946e08e7b2701180dc1eaade0fbe68
BLAKE2b-256 checksum
How to use checksums
91d0692bbb094996d68fb8a669f915b2c95cda6dad963c1747c9249735cce523
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 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.0 This release

5 release files

0.7.0

5 release files

0.6.0

5 release files

0.5.1

5 release files

0.5.0

5 release files

0.4.0

5 release files

0.3.0

5 release files

0.2.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page