From 906da946fdaaaeb47bed97daf609d1a8df3ab33d Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Fri, 11 Sep 2026 21:42:11 +0000 Subject: [PATCH] Raw 1080p and 4K transport streams play, go live, and reach a browser A `.ts` file off a capture card, a receiver or an IPTV recorder is how most high-definition television arrives, and it was the one shape of media nixamp could not take. The library walk skipped it, the router read it as a song and sent back its soundtrack, and what did reach a browser was re-encoded when it did not need to be. - A library lists transport streams. `.m2ts`, `.mts`, `.m2t`, `.trp` and `.tp` are taken on their names; a `.ts` is opened and asked, because it is as often a TypeScript file as it is 4K television and a checkout is not a playlist. Three sync bytes at one packet's spacing, at 188, 192 or 204, and from any offset, since a recording cut mid-stream does not start on a packet boundary. The answer is remembered: it is asked once per track per listing. - A transport stream is read further into before anything decides what is in it -- 20 MB and 10 seconds rather than ffprobe's default -- and decoded with `+genpts+discardcorrupt`, because a 4K recording can carry seconds of null padding and no timestamps on its first frames. - H.264 is copied at whatever size it is. 1080p and 4K cost the same to copy as 720p, so a 4K recording is watched and put on the air without an encoder running at all. Only the transport stream's ADTS audio is redone, as before. - H.265 is copied when the client says it can decode one -- Safari, phones, televisions -- with the `hvc1` tag every player wants rather than the `hev1` ffmpeg writes. The browser says so for itself in the URL (`?hevc=1`); it is never guessed from a user agent. Where it cannot, the re-encode comes down to 1080p: measured here, 4K through libx264 -preset veryfast runs at 0.52x real time and 1080p at 1.65x, and an encode slower than real time is not a stream. A channel has one encode and a whole audience, so it re-encodes H.265 by default; NIXAMP_HEVC_CHANNELS=1 copies it through. - A channel's backlog is six seconds again rather than four megabytes. Four megabytes is six seconds of 720p and under one second of copied 4K, which puts a joiner on the live edge with no cushion -- the play-wait-play loop the backlog exists to prevent. The cap now follows the rate the channel is measured running at, between the old floor and a 48 MB ceiling, and the rate is only believed after a window has closed: the burst at the start of a pull is not a bitrate. - An H.265 channel is packaged into fMP4 HLS segments rather than transport ones, keyed off what the channel emits rather than what its source holds. HLS in TS is defined for H.264 only, and Safari -- the browser that needs HLS and the one that decodes H.265 -- plays an HEVC channel packaged as TS as sound over a black screen. - In the browser, a picked `.ts` is media rather than something filtered out of the list, and goes to the mpegts.js engine instead of a