feat(stream): benchmark software encode ceiling at startup
Replace the guessed transcode ceiling (CPU->1080, GPU->2160) with a measured one. HW encoders still return 2160 instantly. A software-only host runs a bounded encode benchmark — 3s testsrc2 through the real libx264 superfast settings at 1080/720/480, top-down — and reports the rung it sustains at >=1.5x realtime (margin for real decode + busier content). Fixes risk 2: a weak NAS/old CPU that is ffmpeg-capable but can't keep up with a 1080p software encode no longer advertises a 1080 ceiling, so decideStreamPlan routes oversized sources to an external player instead of a stuttering transcode. Floors at 480; each probe is timeout-bounded so a wedged ffmpeg can't stall daemon startup.
This commit is contained in:
parent
005a4380dd
commit
ef3b190e0b
3 changed files with 167 additions and 4 deletions
52
internal/engine/encode_benchmark_test.go
Normal file
52
internal/engine/encode_benchmark_test.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBenchmarkMaxTranscodeHeight_HardwareSkipsProbe(t *testing.T) {
|
||||
// Hardware encoders return 2160 without touching ffmpeg — pass a bogus path
|
||||
// to prove no subprocess runs.
|
||||
for _, hw := range []HWAccel{HWAccelNVENC, HWAccelQSV, HWAccelVAAPI, HWAccelVideoToolbox} {
|
||||
got := BenchmarkMaxTranscodeHeight(context.Background(), "/nonexistent/ffmpeg", hw)
|
||||
if got != 2160 {
|
||||
t.Errorf("hw=%s: got %d, want 2160", hw, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchmarkMaxTranscodeHeight_NoFFmpegKeepsDefault(t *testing.T) {
|
||||
if got := BenchmarkMaxTranscodeHeight(context.Background(), "", HWAccelNone); got != 1080 {
|
||||
t.Errorf("empty ffmpeg path: got %d, want 1080 (historical default)", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchmarkMaxTranscodeHeight_SoftwareReturnsValidRung(t *testing.T) {
|
||||
ffmpeg, err := exec.LookPath("ffmpeg")
|
||||
if err != nil {
|
||||
t.Skip("ffmpeg not on PATH — software benchmark needs a real encoder")
|
||||
}
|
||||
got := BenchmarkMaxTranscodeHeight(context.Background(), ffmpeg, HWAccelNone)
|
||||
switch got {
|
||||
case 1080, 720, 480:
|
||||
// any rung is valid; the exact one depends on the host's CPU.
|
||||
default:
|
||||
t.Errorf("software ceiling = %d, want one of {1080,720,480}", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeasureEncodeRealtimeFactor_RealEncoder(t *testing.T) {
|
||||
ffmpeg, err := exec.LookPath("ffmpeg")
|
||||
if err != nil {
|
||||
t.Skip("ffmpeg not on PATH")
|
||||
}
|
||||
factor, ok := measureEncodeRealtimeFactor(context.Background(), ffmpeg, benchmarkRung{height: 480, width: 854})
|
||||
if !ok {
|
||||
t.Fatal("480p probe failed to run on a host with ffmpeg")
|
||||
}
|
||||
if factor <= 0 {
|
||||
t.Errorf("realtime factor = %.2f, want > 0", factor)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue