feat(hls): pre-segmentación delantada — 2 s segments + async session start (0.9.10)
First-frame latency drops by another 1-2 s on cold-cache plays: 1. HLS segment duration halved from 4 s to 2 s. seg-0 lands in ~half the wait time — the player paints the first frame as soon as it arrives. Software encodes on 4K go from ~3 s wait to ~1.5 s; HW encoders shave ~0.5 s. Trade-off: 2× segment count per source (~3600 segments for a 2 h movie instead of ~1800), but each is half the size on disk. Within HLS spec — Apple recommends 6 s, but 2 s is valid; LL-HLS uses 1-2 s. 2. Cache from 0.9.9 self-heals: cached entries used 4 s segments; VerifyComplete now expects a different highest segment index and invalidates them, triggering a re-encode on next play. No manual cleanup needed. 3. OnStreamSession daemon callback now runs StartHLSSession in a goroutine. Sync HTTP responses return immediately (~50 ms instead of waiting for the ~0.3-1 s ffprobe). Other pending actions in the same sync cycle (new tasks, deletes) no longer wait for the transcoder warmup. Browser HEAD probes already have a 30 s retry budget that covers the brief gap between playerSessionRegistry.add and streamSrv.HLS().Register. Helpers added (engine.segmentDurationFor / segmentStartSec / segmentCountForDuration) so a future short-first-segment variant or non-uniform layout can slot in without touching every call site. Internal: -hls_init_time was investigated but discarded — ffmpeg's implementation treats it as a min duration, not a target, so it couldn't deliver a uniformly 2 s first segment on top of a 4 s steady state. Uniform 2 s is simpler and gets the same first-frame win.
This commit is contained in:
parent
bf8ed0d928
commit
0b2462c82a
5 changed files with 96 additions and 27 deletions
|
|
@ -115,10 +115,11 @@ func TestRenderVideoPlaylist(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRenderVideoPlaylistShortFinalSegment(t *testing.T) {
|
||||
// 9.5s total, 4s segments → 3 segs of 4/4/1.5
|
||||
out := renderVideoPlaylist(9.5, 3)
|
||||
// 9.5s total, 2s segments → 5 segs of 2/2/2/2/1.5
|
||||
segCount := segmentCountForDuration(9.5)
|
||||
out := renderVideoPlaylist(9.5, segCount)
|
||||
if !strings.Contains(out, "#EXTINF:1.500,") {
|
||||
t.Errorf("expected final segment 1.5s in playlist, got:\n%s", out)
|
||||
t.Errorf("expected final segment 1.5s in playlist (segCount=%d), got:\n%s", segCount, out)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue