Tunnel & Transcode
NEW TRANSCODE STREAM continuously converts a live RTSP source — or any other continuous media source — into a browser-playable stream. Browsers cannot play raw RTSP directly; this is a real protocol constraint, not a design choice. Combined with DIRECTIVE TUNNEL, a camera or encoder with no public IP can be exposed and streamed to a browser end to end.
TRANSCODE STREAM — Live RTSP to Browser
NEW TRANSCODE STREAM FROM "/root/clip.mp4" SET ?stream
AFTER EMIT ?stream("rtsp_url")
(* Output: rtsp://transcode.ocalt.com/<token> *)
TRANSCODE STREAM ?stream STOP
What a Transcode Returns
Starting a stream returns a handle carrying token, rtsp_url and playback_url. The RTSP URL plays in VLC, ffmpeg, or any RTSP client; the playback URL is an HLS playlist for a browser. Both point at the same running stream — publishing happens once. Recording to a file returns token and path instead.
Hold on to the handle: TRANSCODE STREAM ?handle STOP is how a stream ends, and until it is stopped it keeps running and keeps consuming resources.
Sources and Destinations
A transcode reads from one place and writes to another. Both ends are flexible, which is what lets the same verb cover live streaming, recording, and format conversion.
Sources — a URL, including a tunnel URL pointing at a machine’s own port; or a path in your namespace (/root/..., /mounted/...).
Destinations — an RTSP endpoint, returned as rtsp_url in the form rtsp://transcode.ocalt.com/<token>; or a path in your namespace, using TO.
NEW TRANSCODE STREAM FROM "/root/clip.mp4" SET ?stream
AFTER EMIT ?stream("rtsp_url")
(* rtsp://transcode.ocalt.com/<token> — playable in VLC or any RTSP client *)
NEW TRANSCODE STREAM FROM "rtsp://transcode.ocalt.com/abc123" TO "/root/recordings/today.mp4" DURATION 30 MINUTES SET ?rec
AFTER EMIT ?rec("path")
(* Records for 30 minutes, then ends itself. TO may also point at /mounted/...
DURATION defaults to 5 minutes if omitted; being non-blocking, it can be set longer. *)
Stopping a Stream
DURATION is the normal way to bound a transcode — it runs for that long and ends itself. STOP is optional and used only to end one early: before its duration elapses, or when it was started with no duration at all. A stream that has a duration and is left alone needs no STOP.
NEW TRANSCODE STREAM FROM "/root/clip.mp4" DURATION 1 HOUR SET ?s
AFTER EMIT ?s("rtsp_url")
(* ... later, to end it before the hour is up ... *)
AFTER TRANSCODE STREAM ?s("id") STOP
DURATION or stop it yourself — otherwise a recording without a duration would run for the default five minutes and a live stream would end at the same ceiling. STOP takes the stream’s id, the same token returned when it started.Output Format — HLS or MSE
Both formats are supported via FORMAT. HLS is segment-based — simpler, universally supported, a few seconds of inherent latency. MSE is a live WebSocket feed, built on the same relay as SYNC CHANNEL — more plumbing, lower latency.
NEW TRANSCODE STREAM FROM "/root/clip.mp4" FORMAT "hls" SET ?stream
AFTER EMIT ?stream("playback_url")
(* A .m3u8 playlist URL — play with a <video> tag and hls.js, or natively on Safari *)
NEW TRANSCODE STREAM FROM "/root/clip.mp4" FORMAT "mse" SET ?stream
AFTER EMIT ?stream("connect_url")
(* A raw WebSocket endpoint delivering live media chunks via MediaSource Extensions,
lower latency than HLS at the cost of more client-side JavaScript *)
DIRECTIVE TUNNEL + TRANSCODE — Exposing a Camera with No Public IP
A home security camera or local encoder behind NAT has no reachable public address. DIRECTIVE TUNNEL exposes its RTSP port through the agent's existing outbound connection; TRANSCODE STREAM then converts the now-reachable feed into something a browser can actually play.
DIRECTIVE "laptop" SERVE "C:/downloads/test.mp4" SET ?src
AFTER DIRECTIVE "laptop" TUNNEL PORT ?src("port") SET ?tunnel
AFTER NEW TRANSCODE STREAM FROM ?tunnel("url") SET ?stream
AFTER EMIT ?stream("rtsp_url")
(* SERVE puts the file on a local port, TUNNEL makes that port reachable,
TRANSCODE reads it server-side. Nothing is installed and nothing is uploaded. *)
Transcoding a File Source
TRANSCODE STREAM is not limited to live RTSP sources — a static file already sitting in a Site Mode namespace can be streamed the same way, useful when a file needs to be served as a continuous stream rather than downloaded whole.
NEW TRANSCODE STREAM FROM "/root/sites/mysite/myvideo.mp4" FORMAT "hls" SET ?stream
AFTER EMIT ?stream("playback_url")
FORMAT applies to recordings, not to live streams. With TO, FORMAT chooses the codec the file is written in. Without it — a live RTSP stream — the source is carried as it is and FORMAT has no effect. Use QUALITY to change what a live stream carries.QUALITY and TIME
A transcode does not have to send the source as it is. QUALITY fixes the output resolution; TIME starts it somewhere other than the beginning.
NEW TRANSCODE STREAM FROM "/root/media/lecture.mkv" QUALITY "720p" SET ?stream
AFTER EMIT ?stream("url")
| QUALITY | Output |
|---|---|
"144p" / "240p" | Minimal bandwidth — preview and thumbnail work |
"360p" / "480p" | Watchable over a constrained connection |
"720p" | The usual choice for streaming a tunnelled source |
"1080p" | Full detail, at full bandwidth |
QUALITY sets the height and the width follows. A source smaller than the requested quality is not upscaled; it is sent as it is.NEW TRANSCODE STREAM FROM "/root/media/lecture.mkv" TIME "00:12:30" QUALITY "480p" SET ?stream
AFTER EMIT ?stream("url")
(* The stream begins twelve and a half minutes in *)
TIME moves the decision into the runtime: the transcode starts at that point, so the player receives a stream that genuinely begins there and has nothing to seek for.NEW TRANSCODE STREAM FROM "/root/media/lecture.mkv"
TIME "00:12:30" DURATION 90 SECONDS QUALITY "720p" SET ?clip
AFTER EMIT ?clip("url")