stash/pkg/ffmpeg/codec.go
Nodude 900305685c pkg/ffmpeg: refactor codec args and hardware API
Move the per-codec CodecInit flag groups to VideoCodec.ExtraArgs and add
ExtraArgsHQ(preset, crf) for quality-oriented encoding. Neither emits
-c:v; callers set that explicitly.

Rename hw* methods to HW*, change HWCanFullHWTranscode /
HWMaxResFilter to take path/width/height primitives, and flip the
HWCodec*Compatible helpers to take a default codec.

Merge ScaleMaxLM into a single 5-arg ScaleMax.
2026-04-22 19:57:34 +02:00

193 lines
3.8 KiB
Go

package ffmpeg
import "strconv"
type VideoCodec struct {
Name string // The full name of the codec including profile/quality
CodeName string // The core codec name without profile/quality suffix
}
func makeVideoCodec(name string, codename string) VideoCodec {
return VideoCodec{name, codename}
}
func (c VideoCodec) Args() []string {
if c.CodeName == "" {
return nil
}
return []string{"-c:v", string(c.CodeName)}
}
var (
// Software codec's
VideoCodecLibX264 = makeVideoCodec("x264", "libx264")
VideoCodecLibWebP = makeVideoCodec("WebP", "libwebp")
VideoCodecBMP = makeVideoCodec("BMP", "bmp")
VideoCodecMJpeg = makeVideoCodec("Jpeg", "mjpeg")
VideoCodecVP9 = makeVideoCodec("VPX-VP9", "libvpx-vp9")
VideoCodecVPX = makeVideoCodec("VPX-VP8", "libvpx")
VideoCodecLibX265 = makeVideoCodec("x265", "libx265")
VideoCodecCopy = makeVideoCodec("Copy", "copy")
)
type AudioCodec string
func (c AudioCodec) Args() []string {
if c == "" {
return nil
}
return []string{"-c:a", string(c)}
}
var (
AudioCodecAAC AudioCodec = "aac"
AudioCodecLibOpus AudioCodec = "libopus"
AudioCodecCopy AudioCodec = "copy"
)
func (c VideoCodec) ExtraArgs() (args Args) {
switch c {
// CPU Codecs
case VideoCodecLibX264:
args = append(args,
"-pix_fmt", "yuv420p",
"-preset", "veryfast",
"-crf", "25",
"-sc_threshold", "0",
)
case VideoCodecVP9:
args = append(args,
"-pix_fmt", "yuv420p",
"-deadline", "realtime",
"-cpu-used", "5",
"-row-mt", "1",
"-crf", "30",
"-b:v", "0",
)
// HW Codecs
case VideoCodecN264:
args = append(args,
"-rc", "vbr",
"-cq", "15",
)
case VideoCodecN264H:
args = append(args,
"-tune", "hq",
"-profile", "high",
"-rc", "vbr",
"-rc-lookahead", "60",
"-surfaces", "64",
"-spatial-aq", "1",
"-aq-strength", "15",
"-cq", "15",
"-coder", "cabac",
"-b_ref_mode", "middle",
)
case VideoCodecI264, VideoCodecIVP9:
args = append(args,
"-global_quality", "20",
"-preset", "faster",
)
case VideoCodecI264C:
args = append(args,
"-q", "20",
"-preset", "faster",
)
case VideoCodecV264, VideoCodecVVP9:
args = append(args,
"-qp", "20",
)
case VideoCodecA264:
args = append(args,
"-quality", "speed",
)
case VideoCodecM264:
args = append(args,
"-realtime", "1",
)
case VideoCodecO264:
args = append(args,
"-preset", "superfast",
"-crf", "25",
)
}
return args
}
func (c VideoCodec) ExtraArgsHQ(preset string, crf int) (args Args) {
switch c {
// CPU Codecs
case VideoCodecLibX264:
args = append(args,
"-pix_fmt", "yuv420p",
"-profile:v", "high",
"-level", "4.2",
"-preset", preset,
"-crf", strconv.Itoa(crf),
"-sc_threshold", "0",
"-threads", "4",
"-sws_flags", "lanczos",
)
case VideoCodecVP9:
args = append(args,
"-pix_fmt", "yuv420p",
"-deadline", "good",
"-cpu-used", "0",
"-row-mt", "1",
"-crf", strconv.Itoa(crf),
"-b:v", "0",
"-threads", "4",
)
// HW Codecs - fixed HQ quality.
case VideoCodecN264:
args = append(args,
"-rc", "vbr",
"-cq", "10",
)
case VideoCodecN264H:
args = append(args,
"-tune", "hq",
"-profile", "high",
"-rc", "vbr",
"-rc-lookahead", "60",
"-surfaces", "64",
"-spatial-aq", "1",
"-aq-strength", "15",
"-cq", "10",
"-coder", "cabac",
"-b_ref_mode", "middle",
)
case VideoCodecI264, VideoCodecIVP9:
args = append(args,
"-global_quality", "15",
"-preset", "slow",
)
case VideoCodecI264C:
args = append(args,
"-q", "15",
"-preset", "slow",
)
case VideoCodecV264, VideoCodecVVP9:
args = append(args,
"-qp", "15",
)
case VideoCodecA264:
args = append(args,
"-quality", "quality",
)
case VideoCodecM264:
args = append(args,
"-realtime", "0",
)
case VideoCodecO264:
args = append(args,
"-preset", "slow",
"-crf", strconv.Itoa(crf),
)
}
return args
}