feat(stream): bitrate-sized readahead for play-while-download
The torrent reader used a static 5 MiB readahead — about 1.9s of a 20 Mbps 4K stream — so streaming a torrent while it downloaded outran the download and stalled. anacrolix's reader already prioritises the pieces in the readahead window ahead of the playhead (and re-prioritises on seek); the window was just too small. dynamicReadahead sizes it to ~30s of video (clamped 8-96 MiB, 24 MiB default when bitrate is unknown). The torrent provider probes the bitrate asynchronously so stream start never blocks on ffprobe; readers created after the probe resolves pick up the accurate size. Real 4K (20.7 Mbps) -> 73 MiB.
This commit is contained in:
parent
e4373454ba
commit
9c995fc4dd
6 changed files with 110 additions and 6 deletions
32
internal/engine/readahead.go
Normal file
32
internal/engine/readahead.go
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package engine
|
||||
|
||||
// Torrent stream readahead sizing.
|
||||
//
|
||||
// anacrolix's Reader (SetResponsive + SetReadahead) already prioritises the
|
||||
// pieces in a window ahead of the read position and re-prioritises on Seek —
|
||||
// so the playhead→piece-priority feedback is built in. The problem was the
|
||||
// window: a static 5 MiB is only ~1.6s of a 25 Mbps 4K stream, so playback
|
||||
// outran the download and stalled. Sizing the window by bitrate (~30s of video)
|
||||
// keeps a real buffer ahead of the playhead.
|
||||
const (
|
||||
readaheadSeconds = 30
|
||||
minReadahead = 8 << 20 // 8 MiB
|
||||
maxReadahead = 96 << 20 // 96 MiB — cap so a seek doesn't waste a huge fetch
|
||||
defaultReadahead = 24 << 20 // 24 MiB — when bitrate is unknown (still ~5x the old 5 MiB)
|
||||
)
|
||||
|
||||
// dynamicReadahead returns the bytes-ahead window for a torrent reader given the
|
||||
// stream's bitrate (bits/sec). Unknown/zero bitrate → a generous default.
|
||||
func dynamicReadahead(bitrateBps int64) int64 {
|
||||
if bitrateBps <= 0 {
|
||||
return defaultReadahead
|
||||
}
|
||||
ra := bitrateBps / 8 * readaheadSeconds
|
||||
if ra < minReadahead {
|
||||
return minReadahead
|
||||
}
|
||||
if ra > maxReadahead {
|
||||
return maxReadahead
|
||||
}
|
||||
return ra
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue