1a69fcfd04
- Updated the installation script to clarify that production wrappers do not include fixed test secrets, improving user guidance for local testing. - Modified the jiggablend-manager and jiggablend-runner scripts to remove fixed test configurations, emphasizing the use of local test credentials via `make init-test`. - Enhanced error handling in the runner script to ensure that an API key is provided, improving security and user feedback. - Added new flags and options for the runner, including sandboxing capabilities and GPU ray tracing control, enhancing flexibility for users. - Improved README documentation to reflect changes in usage and configuration, ensuring users have clear instructions for setup and execution.
106 lines
3.9 KiB
Go
106 lines
3.9 KiB
Go
package encoding
|
|
|
|
// Pipeline: Blender outputs only EXR (linear). Encode is EXR only: linear -> sRGB -> HLG (video), 10-bit, full range.
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// CRFH264 is the Constant Rate Factor for H.264 encoding (lower = higher quality, range 0-51)
|
|
CRFH264 = 15
|
|
// CRFAV1 is the Constant Rate Factor for AV1 encoding (lower = higher quality, range 0-63)
|
|
CRFAV1 = 30
|
|
// CRFVP9 is the Constant Rate Factor for VP9 encoding (lower = higher quality, range 0-63)
|
|
CRFVP9 = 30
|
|
)
|
|
|
|
// tonemapFilter returns the production filter for EXR input (linear → sRGB → HLG, bt709).
|
|
// This is the single source of truth used by BuildCommand and BuildPass1Command.
|
|
// zscale numeric values: primaries 1=bt709, matrix 1=bt709, transfer 8=linear / 13=sRGB / 18=HLG.
|
|
func tonemapFilter(useAlpha bool) string {
|
|
filter := "format=gbrpf32le,zscale=transferin=8:transfer=13:primariesin=1:primaries=1:matrixin=0:matrix=1:rangein=full:range=full,zscale=transferin=13:transfer=18:primariesin=1:primaries=1:matrixin=1:matrix=1:rangein=full:range=full"
|
|
if useAlpha {
|
|
return filter + ",format=yuva420p10le"
|
|
}
|
|
return filter + ",format=yuv420p10le"
|
|
}
|
|
|
|
// SoftwareEncoder implements software encoding (libx264, libaom-av1, libvpx-vp9).
|
|
type SoftwareEncoder struct {
|
|
codec string
|
|
}
|
|
|
|
func (e *SoftwareEncoder) Name() string { return "software" }
|
|
func (e *SoftwareEncoder) Codec() string { return e.codec }
|
|
|
|
func (e *SoftwareEncoder) Available() bool {
|
|
return true // Software encoding is always available
|
|
}
|
|
|
|
func (e *SoftwareEncoder) buildBaseArgs(config *EncodeConfig) []string {
|
|
pixFmt := "yuv420p10le"
|
|
if config.UseAlpha {
|
|
pixFmt = "yuva420p10le"
|
|
}
|
|
colorPrimaries, colorTrc, colorspace, colorRange := "bt709", "arib-std-b67", "bt709", "pc"
|
|
|
|
var codecArgs []string
|
|
switch e.codec {
|
|
case "libaom-av1":
|
|
codecArgs = []string{"-crf", strconv.Itoa(CRFAV1), "-b:v", "0", "-tiles", "2x2", "-g", "240"}
|
|
case "libvpx-vp9":
|
|
codecArgs = []string{"-crf", strconv.Itoa(CRFVP9), "-b:v", "0", "-row-mt", "1", "-g", "240"}
|
|
default:
|
|
codecArgs = []string{"-preset", "veryslow", "-crf", strconv.Itoa(CRFH264), "-profile:v", "high10", "-level", "5.2", "-tune", "film", "-keyint_min", "24", "-g", "240", "-bf", "2", "-refs", "4"}
|
|
}
|
|
|
|
args := []string{"-y", "-f", "image2", "-start_number", fmt.Sprintf("%d", config.StartFrame), "-framerate", fmt.Sprintf("%.2f", config.FrameRate),
|
|
"-color_trc", "linear", "-color_primaries", "bt709"}
|
|
args = append(args, "-i", config.InputPattern, "-c:v", e.codec, "-pix_fmt", pixFmt, "-r", fmt.Sprintf("%.2f", config.FrameRate), "-color_primaries", colorPrimaries, "-color_trc", colorTrc, "-colorspace", colorspace, "-color_range", colorRange)
|
|
|
|
// FFmpeg 6+ treats yuva420p10le as experimental for libvpx-vp9 / libaom-av1
|
|
if config.UseAlpha && (e.codec == "libvpx-vp9" || e.codec == "libaom-av1") {
|
|
args = append(args, "-strict", "experimental")
|
|
}
|
|
|
|
args = append(args, "-vf", tonemapFilter(config.UseAlpha))
|
|
args = append(args, codecArgs...)
|
|
return args
|
|
}
|
|
|
|
func (e *SoftwareEncoder) BuildCommand(config *EncodeConfig) *exec.Cmd {
|
|
args := e.buildBaseArgs(config)
|
|
|
|
if config.TwoPass {
|
|
// For 2-pass, this builds pass 2 command
|
|
args = append(args, "-pass", "2")
|
|
}
|
|
|
|
args = append(args, config.OutputPath)
|
|
|
|
if config.TwoPass {
|
|
log.Printf("Build Software Pass 2 command: ffmpeg %s", strings.Join(args, " "))
|
|
} else {
|
|
log.Printf("Build Software command: ffmpeg %s", strings.Join(args, " "))
|
|
}
|
|
cmd := exec.Command("ffmpeg", args...)
|
|
cmd.Dir = config.WorkDir
|
|
return cmd
|
|
}
|
|
|
|
// BuildPass1Command builds the first pass command for 2-pass encoding.
|
|
func (e *SoftwareEncoder) BuildPass1Command(config *EncodeConfig) *exec.Cmd {
|
|
args := e.buildBaseArgs(config)
|
|
args = append(args, "-pass", "1", "-f", "null", "/dev/null")
|
|
|
|
log.Printf("Build Software Pass 1 command: ffmpeg %s", strings.Join(args, " "))
|
|
cmd := exec.Command("ffmpeg", args...)
|
|
cmd.Dir = config.WorkDir
|
|
return cmd
|
|
}
|