diff --git a/cmd/av1dae/main.go b/cmd/av1dae/main.go index a75421c..ba84e50 100644 --- a/cmd/av1dae/main.go +++ b/cmd/av1dae/main.go @@ -192,6 +192,7 @@ func processFile(ctx context.Context, inputPath string, cfg *types.Config, enc * MediaType: mediaType, CRF: crf, Preset: preset, + LP: cfg.Encoding.LP, DeleteOrigin: deleteOrigin, } diff --git a/config.example.yaml b/config.example.yaml index 1ed6a24..9f41854 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -11,6 +11,9 @@ encoding: bluray: crf: 29 preset: 3 + # SVT-AV1 logical-processor (thread) cap so a long encode can't pin every core. + # 0 = auto (use all cores). Applies to every profile. + lp: 0 paths: input: "./input" diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index f656f8e..9ce04a7 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -403,6 +403,17 @@ func (e *Encoder) encodeOpus(ctx context.Context, wavs []string, workDir string) return opusFiles, nil } +// svtav1Params builds the -svtav1-params value, appending lp=N (logical +// processors / encoder thread count) only when lp > 0. lp=0 lets SVT-AV1 +// auto-detect, preserving prior behavior. +func svtav1Params(lp int) string { + p := "film-grain=10:film-grain-denoise=1:scd=1:qm-min=4:qm-max=15:keyint=10s" + if lp > 0 { + p += fmt.Sprintf(":lp=%d", lp) + } + return p +} + func (e *Encoder) encodeVideo(ctx context.Context, input, workDir string, opusFiles []string, job *types.Job, metadata *types.Metadata, interlaced bool, streamLangs []StreamMetadata) error { outFile := filepath.Join(workDir, "output.mkv") @@ -418,7 +429,7 @@ func (e *Encoder) encodeVideo(ctx context.Context, input, workDir string, opusFi } } - svtParams := fmt.Sprintf("film-grain=10:film-grain-denoise=1:scd=1:qm-min=4:qm-max=15:keyint=10s") + svtParams := svtav1Params(job.LP) zscaleStr, newWidth, err := e.calculateZscaleWidth(ctx, input, 0) if err != nil { diff --git a/internal/encoder/encoder_test.go b/internal/encoder/encoder_test.go new file mode 100644 index 0000000..384cd41 --- /dev/null +++ b/internal/encoder/encoder_test.go @@ -0,0 +1,23 @@ +package encoder + +import ( + "strings" + "testing" +) + +func TestSvtav1Params(t *testing.T) { + const base = "film-grain=10:film-grain-denoise=1:scd=1:qm-min=4:qm-max=15:keyint=10s" + + if got := svtav1Params(0); got != base { + t.Errorf("lp=0 should not append lp:\n got %q\nwant %q", got, base) + } + if got := svtav1Params(-1); got != base { + t.Errorf("lp<0 should not append lp: got %q", got) + } + if got := svtav1Params(4); got != base+":lp=4" { + t.Errorf("lp=4: got %q, want suffix :lp=4", got) + } + if got := svtav1Params(4); !strings.HasPrefix(got, base) { + t.Errorf("lp set should keep the base params intact: got %q", got) + } +} diff --git a/pkg/types/types.go b/pkg/types/types.go index 9ba7886..117e4a9 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -16,6 +16,7 @@ type Job struct { Metadata *Metadata CRF int Preset int + LP int // SVT-AV1 logical processors; 0 = auto DeleteOrigin bool } @@ -46,6 +47,9 @@ type EncodingConfig struct { Bluray EncodingParams `yaml:"bluray"` WebDL EncodingParams `yaml:"webdl"` TVRip EncodingParams `yaml:"tvrip"` + // LP caps SVT-AV1's logical-processor (thread) count so a long encode can't + // pin every core. 0 = let SVT-AV1 auto-detect (default). Applies to all profiles. + LP int `yaml:"lp"` } type EncodingParams struct {