Help us shape the future of Go! Take the 2026 Go Developer Survey

transcodebench

package
v0.2.31 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: GPL-3.0 Imports: 23 Imported by: 0

Documentation

Overview

Package transcodebench implements a reproducible benchmark harness that drives the real transcode.Manager (probe, decision, HLS sessions and ServeSegment) against a loopback range-capable HTTP source serving a local fixture file. It never builds ad-hoc ffmpeg command lines for the measured work: every measured encode/remux is a Manager session. Direct ffprobe use is limited to verifying the retained output after a run.

Index

Constants

View Source
const (
	ModeTranscode = "transcode"
	ModeRemux     = "remux"
)

Modes accepted by Config.Mode.

View Source
const SchemaVersion = 1

SchemaVersion is the version of the Result JSON document.

Variables

This section is empty.

Functions

func DeliveredMediaSeconds

func DeliveredMediaSeconds(n int, seg, requested time.Duration) float64

DeliveredMediaSeconds is the media time covered by n served segments, capped at the requested duration.

func ExpectedDimensions

func ExpectedDimensions(dec core.Decision, cfg Config, srcW, srcH int) (w, h int, ok bool)

ExpectedDimensions returns the exact output size implied by the source dimensions and the decision, mirroring transcode's outputSize scaling (aspect preserved, even sizes) for encodes and the untouched source size for stream copy. ok is false when the source size is unknown.

func IsHWEncoder

func IsHWEncoder(enc string) bool

IsHWEncoder reports whether an encoder name is a hardware encoder rather than a software libx* encoder or stream copy.

func RedactArgs

func RedactArgs(args []string) []string

RedactArgs returns args with credentials removed: values following -headers/-user_agent/-referer, Authorization/token material anywhere, and sensitive URL query values. The -i input itself is kept (it is a loopback bench URL) except for sensitive query parameters.

func SegmentCount

func SegmentCount(dur, seg time.Duration) int

SegmentCount is the number of whole segments needed to cover dur.

func Summarize

func Summarize(res *Result)

Summarize folds per-session results into totals. Pure; unit-tested.

func VideoEncoderFromArgs

func VideoEncoderFromArgs(args []string) string

VideoEncoderFromArgs returns the -c:v (or -c:v:0) encoder name, or "".

func WriteResult

func WriteResult(path string, res *Result) error

WriteResult writes res as indented JSON to path (atomically via rename).

Types

type Config

type Config struct {
	Input       string        // local fixture path (required)
	FFmpeg      string        // ffmpeg path/lookup hint; empty = Manager discovery
	FFprobe     string        // ffprobe path/lookup hint
	HWAccel     string        // none|auto|videotoolbox|nvenc|qsv|vaapi (default none)
	Mode        string        // transcode|remux (default transcode)
	Codec       string        // target video codec for transcode: h264|hevc (default h264)
	MaxHeight   int           // 0 = source height
	BitrateKbps int           // 0 = Manager decision's bitrate
	Concurrency int           // simultaneous sessions (default 1)
	Duration    time.Duration // media seconds to consume per session (required > 0)
	SegmentDur  time.Duration // HLS segment duration (default 4s)
	Paced       bool          // consume at roughly realtime pace
	ResultPath  string        // JSON result path; empty = stdout only in CLI
	OutputDir   string        // retain init/segments/concatenated output here when set
	Timeout     time.Duration // overall context timeout (default 10m)
	VAAPIDevice string
}

Config is the benchmark configuration. All fields are plain values so the CLI (and tests) can build one without flag parsing.

func (Config) Normalized

func (c Config) Normalized() Config

Normalized returns cfg with defaults applied.

func (Config) Validate

func (c Config) Validate() error

Validate reports configuration errors without touching any service.

type DecisionSummary

type DecisionSummary struct {
	Kind        string `json:"kind"`
	VideoCopy   bool   `json:"videoCopy"`
	AudioCopy   bool   `json:"audioCopy"`
	VideoCodec  string `json:"videoCodec"`
	AudioCodec  string `json:"audioCodec,omitempty"`
	Container   string `json:"container"`
	MaxHeight   int    `json:"maxHeight,omitempty"`
	BitrateKbps int    `json:"bitrateKbps,omitempty"`
	Reason      string `json:"reason,omitempty"`
}

DecisionSummary mirrors the explicit decision handed to StartHLS.

type Launch

type Launch struct {
	ID           int       `json:"id"`
	Kind         string    `json:"kind"` // "start" (long-running) or "run" (to completion)
	Path         string    `json:"path"`
	Args         []string  `json:"args"` // redacted
	StartedAt    time.Time `json:"startedAt"`
	DurationMs   int64     `json:"durationMs,omitempty"`
	ExitError    string    `json:"exitError,omitempty"`
	PID          int       `json:"pid,omitempty"`
	CPUUserMs    *int64    `json:"cpuUserMs,omitempty"`
	CPUSystemMs  *int64    `json:"cpuSystemMs,omitempty"`
	PeakRSSBytes *uint64   `json:"peakRssBytes,omitempty"` // individual encoder peak, not aggregate tree RSS
	Encoder      string    `json:"encoder,omitempty"`      // -c:v value, when present
	HWEncoder    bool      `json:"hwEncoder,omitempty"`
	LogTail      string    `json:"logTail,omitempty"`
}

Launch is one recorded Runner invocation. PID/CPU are present only when the underlying Process implements the optional interfaces interface{ PID() int } / interface{ CPUTime() (time.Duration, time.Duration) }; they are never invented when the API does not expose them.

type OutputProbe

type OutputProbe struct {
	Container   string          `json:"container,omitempty"`
	DurationSec float64         `json:"durationSec,omitempty"`
	Streams     []StreamSummary `json:"streams,omitempty"`
	Error       string          `json:"error,omitempty"`
	Verified    bool            `json:"verified"`
	Detail      string          `json:"detail,omitempty"`
}

OutputProbe is ffprobe verification of the retained output.

type Recorder

type Recorder struct {
	// contains filtered or unexported fields
}

Recorder wraps a transcode.Runner (ExecRunner by default) and records every launch: redacted argv, timing, exit error, captured log tail, and PID/CPU when the process exposes them.

func NewRecorder

func NewRecorder() *Recorder

func NewRecorderWith

func NewRecorderWith(inner transcode.Runner) *Recorder

NewRecorderWith wraps a specific inner runner (tests).

func (*Recorder) Run

func (r *Recorder) Run(ctx context.Context, cmd transcode.Command) error

Run implements transcode.Runner.

func (*Recorder) Snapshot

func (r *Recorder) Snapshot() []Launch

Snapshot returns a copy of all launches, finalizing any exited processes.

func (*Recorder) Start

func (r *Recorder) Start(cmd transcode.Command) (transcode.Process, error)

Start implements transcode.Runner.

type Result

type Result struct {
	SchemaVersion int       `json:"schemaVersion"`
	Kind          string    `json:"kind"`
	StartedAt     time.Time `json:"startedAt"`
	WallMs        int64     `json:"wallMs"` // total elapsed (setup+measurement+verification+teardown)
	// Timing splits WallMs so Speedup is never computed over setup/probe.
	Timing struct {
		SetupMs        int64 `json:"setupMs"`        // hash, Manager start, probe, decision
		MeasurementMs  int64 `json:"measurementMs"`  // barrier release -> last segment delivered (encoders then stopped)
		VerificationMs int64 `json:"verificationMs"` // ffprobe of retained output, after encoders stopped
	} `json:"timing"`
	Success bool   `json:"success"`
	Error   string `json:"error,omitempty"`

	Config struct {
		Mode        string  `json:"mode"`
		Codec       string  `json:"codec,omitempty"`
		HWAccel     string  `json:"hwAccel"`
		MaxHeight   int     `json:"maxHeight,omitempty"`
		BitrateKbps int     `json:"bitrateKbps,omitempty"`
		Concurrency int     `json:"concurrency"`
		DurationSec float64 `json:"durationSec"`
		SegmentSec  float64 `json:"segmentSec"`
		Paced       bool    `json:"paced"`
	} `json:"config"`

	Fixture struct {
		Path   string `json:"path"`
		SHA256 string `json:"sha256"`
		Size   int64  `json:"size"`
	} `json:"fixture"`

	Runtime struct {
		GoVersion   string   `json:"goVersion"`
		GOOS        string   `json:"goos"`
		GOARCH      string   `json:"goarch"`
		NumCPU      int      `json:"numCPU"`
		FFmpegPath  string   `json:"ffmpegPath,omitempty"`
		FFprobePath string   `json:"ffprobePath,omitempty"`
		FFmpegVer   string   `json:"ffmpegVersion,omitempty"`
		FFprobeVer  string   `json:"ffprobeVersion,omitempty"`
		HWDetected  string   `json:"hwDetected,omitempty"`
		HWEncoders  []string `json:"hwEncoders,omitempty"`
		HWFallback  bool     `json:"hwFallback,omitempty"` // requested HW not actually used
	} `json:"runtime"`

	Probe struct {
		Container   string          `json:"container"`
		DurationSec float64         `json:"durationSec"`
		BitrateKbps int             `json:"bitrateKbps,omitempty"`
		Streams     []StreamSummary `json:"streams,omitempty"`
	} `json:"probe"`

	Decision DecisionSummary `json:"decision"`

	Sessions []SessionResult `json:"sessions"`
	Launches []Launch        `json:"launches"`

	Totals struct {
		SessionsOK     int     `json:"sessionsOk"`
		SessionsFailed int     `json:"sessionsFailed"`
		Segments       int     `json:"segments"`
		Bytes          int64   `json:"bytes"`
		MediaSec       float64 `json:"mediaSec"`
		Speedup        float64 `json:"speedup,omitempty"` // mediaSec / wallSec (aggregate)
	} `json:"totals"`
}

Result is the versioned JSON document written to -result.

func Run

func Run(ctx context.Context, cfg Config, log *slog.Logger) (*Result, error)

Run executes the benchmark. It always returns a Result describing what happened; a non-nil error (and Result.Success == false) means the run failed. The caller should exit nonzero whenever Success is false.

type SessionResult

type SessionResult struct {
	ID           string       `json:"id"`
	Success      bool         `json:"success"`
	Error        string       `json:"error,omitempty"`
	StartupMs    int64        `json:"startupMs"` // barrier release -> first segment served
	WallMs       int64        `json:"wallMs"`    // barrier release -> last segment served
	Segments     int          `json:"segments"`  // segments successfully served
	MediaSec     float64      `json:"mediaSec"`  // delivered media seconds (capped at request)
	Bytes        int64        `json:"bytes"`     // segment bytes (init counted separately)
	InitBytes    int64        `json:"initBytes,omitempty"`
	PlaylistB    int          `json:"playlistBytes,omitempty"`
	OutputPath   string       `json:"outputPath,omitempty"` // retained concatenated output, when kept
	OutputSHA256 string       `json:"outputSha256,omitempty"`
	OutputProbe  *OutputProbe `json:"outputProbe,omitempty"`
	HWFallback   bool         `json:"hwFallback,omitempty"`
	// contains filtered or unexported fields
}

SessionResult is one concurrent session's measurements.

type StreamSummary

type StreamSummary struct {
	Type     string `json:"type"`
	Codec    string `json:"codec"`
	Profile  string `json:"profile,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
	Channels int    `json:"channels,omitempty"`
}

StreamSummary is a compact, JSON-friendly stream description.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL