encode

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package encode runs ffmpeg encoders with codec-specific settings: x264, x265 and SVT-AV1 on the CPU, or NVIDIA NVENC (see Hardware).

Index

Constants

This section is empty.

Variables

View Source
var ErrBurnSegment = errors.New("burn segment does not match the plan")

ErrBurnSegment is returned by Burn when a segment did not render the frames planned (a seek that landed after the segment's first frame): the segments are unusable, a single pass still is.

View Source
var ErrDecode = errors.New("decoding errors")

ErrDecode is returned by Decodes for a file ffmpeg reports errors on.

View Source
var ErrNoChunks = errors.New("chunked encode needs at least one chunk")

ErrNoChunks is returned when a chunked encode is asked for no chunk.

View Source
var ErrNoSegments = errors.New("digest needs at least one segment")

ErrNoSegments is returned when a digest is asked for no segment.

View Source
var ErrNoSubtitlesFilter = errors.New("ffmpeg has no subtitles filter (built without libass)")

ErrNoSubtitlesFilter is returned by CheckBurn when ffmpeg has no subtitles filter: it was built without libass.

View Source
var ErrStalled = errors.New("encoder stalled: its output stopped growing")

ErrStalled is returned for an encode whose output stopped growing for longer than the stall timeout (see WithStallTimeout), twice in a row.

View Source
var ErrUnknownBurnEncoder = errors.New("unknown overlay encoder")

ErrUnknownBurnEncoder is returned for an unknown burn encoder.

View Source
var ErrUnknownCodec = errors.New("unknown codec")

ErrUnknownCodec is returned for an unsupported codec name.

View Source
var ErrUnknownHardware = errors.New("unknown encoder implementation")

ErrUnknownHardware is returned for an unknown encoder implementation (Hardware).

Functions

This section is empty.

Types

type BurnEncoder

type BurnEncoder string

BurnEncoder is the H.264 encoder of a burn (BurnSpec.Encoder).

const (
	// BurnAuto encodes with VideoToolbox on macOS when it encodes a test
	// frame, with x264 otherwise (the zero value). NVENC is never chosen
	// automatically: it needs the GPU checks of an explicit request.
	BurnAuto BurnEncoder = ""
	// BurnX264 encodes with libx264 (BurnSpec.CRF and Preset).
	BurnX264 BurnEncoder = "x264"
	// BurnVideoToolbox encodes with Apple's hardware encoder
	// (h264_videotoolbox), at constant quality (Apple silicon).
	BurnVideoToolbox BurnEncoder = "videotoolbox"
	// BurnNVENC encodes with NVIDIA's hardware encoder (h264_nvenc), and
	// decodes with NVDEC.
	BurnNVENC BurnEncoder = "nvenc"
)

Burn encoders. A burn is a debug copy: the hardware encoders write it several times faster than x264, at a quality where the overlay's text stays crisp (see docs/overlay.md).

func ParseBurnEncoder

func ParseBurnEncoder(
	s string,
) (BurnEncoder, error)

ParseBurnEncoder reads a burn encoder: auto (or empty), x264, videotoolbox or nvenc.

func (BurnEncoder) Hardware

func (e BurnEncoder) Hardware() bool

Hardware reports whether e encodes on a hardware encoder.

func (BurnEncoder) String

func (e BurnEncoder) String() string

String returns the encoder name, "auto" for the zero value.

type BurnSegment

type BurnSegment struct {
	// From is when the segment's first frame is presented, on the source's
	// container timeline; To when the frame after its last one is (0: the
	// segment runs to the end).
	From, To media.Duration
	// Frames is the number of frames of the segment: a segment rendering
	// another count fails the burn with ErrBurnSegment.
	Frames int
	// Subtitles, when set, is the script of the segment instead of
	// BurnSpec.Subtitles: the same script, with only the events shown
	// during the segment, loads and renders faster.
	Subtitles string
}

BurnSegment is a run of consecutive frames of the source, rendered by its own ffmpeg (BurnSpec.Segments). Each ffmpeg keeps the source's timestamps (-copyts), seeks burnPreroll before the segment, decodes from the keyframe it lands on and keeps the frames presented from From to To: the segments hold every frame once whatever the keyframes, and the script draws on each frame what it draws in a single pass. The segments are joined without re-encoding, each one starting where the previous one's frames end, and the source's audio is added once.

type BurnSpec

type BurnSpec struct {
	// Source is the video; Subtitles the ASS script; Output the copy
	// written (H.264, 8-bit 4:2:0).
	Source, Subtitles, Output string
	// Height scales the copy to that height before the script is drawn
	// (0 keeps the source's): a smaller copy encodes faster, and libass
	// scales the script to it.
	Height int
	// Encoder is the H.264 encoder (BurnAuto: VideoToolbox on macOS, x264
	// elsewhere).
	Encoder BurnEncoder
	// CRF and Preset are the x264 settings (default 20, fast).
	CRF    float64
	Preset string
	// Segments, when there are two or more, render the copy in runs of
	// consecutive frames, Workers at once, joined without re-encoding (see
	// BurnSegment): one ffmpeg draws the overlay on a single thread, too
	// slowly to feed a hardware encoder.
	Segments []BurnSegment
	// Workers is how many segments render at once (0: the encoder's
	// default; 1 or less renders in a single pass, as x264 does by
	// default).
	Workers int
	// Start is the start of the source's timeline (its container's start
	// time), which ffmpeg subtracts from the timestamps its filters see in
	// a single pass: segments subtract it too, so that the script is the
	// same in both modes.
	Start media.Duration
	// AudioCodec is the codec of the source's first audio stream, "" when
	// it has none: its audio is copied when the output container can hold
	// it, encoded to AAC otherwise.
	AudioCodec string
	// FontsDir, when set, is searched for the script's fonts before the
	// system's.
	FontsDir string
	// Progress, when set, is called with the number of frames written so
	// far, about twice a second.
	Progress func(frames int)
}

BurnSpec describes a burn: a copy of a video with an ASS subtitle script drawn on its frames.

type Chunk

type Chunk struct {
	// Start is the index of the chunk's first frame.
	Start int `json:"start"`
	// Frames is the number of frames of the chunk.
	Frames int     `json:"frames"`
	CRF    float64 `json:"crf"`
	// Width and Height, when set, override the encode's resolution for the
	// chunk: per-shot resolution changes the resolution at chunk
	// boundaries (always keyframes).
	Width  int `json:"width,omitempty"`
	Height int `json:"height,omitempty"`
}

Chunk is a run of consecutive frames encoded with its own CRF. Chunked encoding is how per-shot settings reach every encoder the same way: x264 and x265 accept zones through their private parameters, but SVT-AV1 has no per-frame quantiser control reachable from ffmpeg. Each chunk is encoded separately (it starts with a keyframe) and the chunks are joined without re-encoding; decoding the joined file gives exactly the frames of the separate chunks for x264, x265 and SVT-AV1, whose headers do not depend on the CRF. Chunks starting on the fixed GOP grid keep the keyframes of every rung aligned, as ABR segmenting requires.

type ChunkSource

type ChunkSource struct {
	Path string
	// Rate is the frame rate of the video, which places the chunks in time.
	Rate media.Rational
	// Origin is the presentation time of the first frame of the video on
	// the container's timeline (bitstream.Report.Start), which chunks are
	// seeked on (absolute seeks): a chunk starts at Origin plus its frames'
	// time. Without it, a video starting after its audio would be seeked
	// from the container's start, and every chunk would start early by the
	// difference. A digest starts at 0.
	Origin media.Duration
}

ChunkSource is the video a chunked encode reads.

type Codec

type Codec struct {
	// Name is the user-facing name: h264, hevc or av1.
	Name string `json:"name"`
	// Encoder is the ffmpeg encoder.
	Encoder string `json:"encoder"`
	// Hardware is the encoder implementation: the CPU (empty) or NVENC.
	Hardware Hardware `json:"hardware,omitempty"`
	// DefaultPreset favours speed: the ladder is estimated from many encodes.
	DefaultPreset string `json:"-"`
	// MinCRF and MaxCRF bound the constant-quality scale.
	MinCRF float64 `json:"-"`
	MaxCRF float64 `json:"-"`
	// ProbeCRFs are the constant-quality values probed per resolution, from
	// high to low quality; together they span VMAF ~97 to ~40 at the right
	// resolution for most content.
	ProbeCRFs []float64 `json:"-"`
	// CRFStep is the granularity of the constant-quality scale.
	CRFStep float64 `json:"-"`
	// MaxRate is the highest VBV rate the encoder accepts (bits/s, 0 for no
	// limit): SVT-AV1 refuses maxrate above 100 Mb/s, which the 2× cap of a
	// top rung of grainy content can exceed.
	MaxRate int64 `json:"-"`
	// contains filtered or unexported fields
}

Codec describes how to drive one encoder.

func Lookup

func Lookup(
	name string,
) (Codec, error)

Lookup returns the CPU codec named name.

func LookupFor

func LookupFor(
	name string,
	hw Hardware,
) (Codec, error)

LookupFor returns the codec named name, encoded on hw. The codec is a copy the caller may change.

func (Codec) Args

func (c Codec) Args(
	p Params,
) []string

Args returns the ffmpeg output arguments for p, without input or output path.

func (Codec) ChunkCommandLine

func (c Codec) ChunkCommandLine(
	src ChunkSource,
	dst string,
	chunks []Chunk,
	p Params,
) string

ChunkCommandLine renders a copy-pasteable shell script encoding src chunk by chunk into dst (see EncodeChunks), then removing the chunk files.

func (Codec) CommandLine

func (c Codec) CommandLine(
	src, dst string,
	p Params,
) string

CommandLine renders a copy-pasteable ffmpeg command for p. NVENC commands also decode the source on the GPU (see InputArgs).

func (Codec) InputArgs

func (c Codec) InputArgs() []string

InputArgs are the input options of the commands rendered for the codec: NVENC commands decode the source with NVDEC too (frames are downloaded before the CPU scaler, so the encoder sees exactly what the ladder measured; ffmpeg falls back to software decoding for codecs NVDEC does not decode). Encodes run by the ladder read the raw digest and need no decoder.

func (Codec) QualityOption

func (c Codec) QualityOption() string

QualityOption is the ffmpeg option of the constant-quality value: -crf, or -cq for NVENC.

func (Codec) Step

func (c Codec) Step() float64

Step returns the granularity of the quality scale, half a step when the codec does not say.

func (Codec) Supports

func (c Codec) Supports(
	f Feature,
) bool

Supports reports whether the codec's encoder has feature f.

type CopyPart added in v1.2.0

type CopyPart struct {
	Source string
	// Origin is the presentation time of the source's first frame on its
	// container's timeline (see ChunkSource.Origin).
	Origin   media.Duration
	Segments []CopySegment
}

CopyPart is the part of a copy cut from one source.

type CopySegment added in v1.2.0

type CopySegment struct {
	Start    media.Duration
	Frames   int
	Duration media.Duration
}

CopySegment is a run of frames of a source: Frames frames from the keyframe shown at Start (a time of the video, from its first frame), which last Duration on the timeline of the source.

type CopySpec added in v1.2.0

type CopySpec struct {
	// Destination receives the segments, joined; its extension picks the
	// container.
	Destination string
	// Codec is the codec of the sources (ffprobe's name), which picks how
	// the segments are carried before they are joined.
	Codec string
	// Rate is the frame rate of the sources.
	Rate media.Rational
	// Parts are the sources, in the order of the file. They must share
	// their codec, geometry and frame rate.
	Parts []CopyPart
	// Segments is the number of segments over the parts, for Progress,
	// which is called with the count copied so far.
	Segments int
	Progress func(done int)
}

CopySpec describes a file made of segments of videos copied as they are, without re-encoding: whole GOPs, from a keyframe on.

type DigestPart added in v1.1.0

type DigestPart struct {
	Source   string
	Origin   media.Duration
	Segments []media.Interval
}

DigestPart is the part of a digest cut from one source: its segments, times of that source's video seeked at its Origin.

type DigestSpec

type DigestSpec struct {
	// Source is the file the segments are cut from; Destination receives
	// the digest.
	Source, Destination string
	Segments            []media.Interval
	// Rate is the source frame rate, restored on the concatenated timeline.
	Rate media.Rational
	// Origin is the presentation time of the source's first frame on its
	// container's timeline (see ChunkSource.Origin): the segments are
	// times of the video, from its first frame, and are seeked at Origin
	// plus their start.
	Origin media.Duration
	// BitDepth is 8 or 10.
	BitDepth int
	// Lossless keeps the digest compact (FFV1); otherwise it is raw video in
	// a NUT container, which costs nothing to decode for the many encodes
	// and measurements that read it.
	Lossless bool
	// Parts, when set, cut the digest from several sources, one after the
	// other, in place of Source, Origin and Segments: the digest of a
	// program. The sources must share their geometry, frame rate and pixel
	// format, which the concatenation does not convert.
	Parts []DigestPart
}

DigestSpec describes a digest: segments of a source (or of several, see Parts) concatenated at the source resolution in 4:2:0.

type FFmpeg

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

FFmpeg encodes with the ffmpeg binary.

func NewFFmpeg

func NewFFmpeg(
	bin string,
	opts ...Option,
) *FFmpeg

NewFFmpeg returns an FFmpeg running bin. It encodes, extracts digests, decodes and measures grain: consumers such as the ladder engine declare the narrow part they use.

func (*FFmpeg) Burn

func (f *FFmpeg) Burn(
	ctx context.Context,
	spec BurnSpec,
) error

Burn writes the copy spec describes. The frames keep their timestamps (no frame is dropped or duplicated), so the script's times, taken from the source, land on the frames they describe.

func (*FFmpeg) CheckBurn

func (f *FFmpeg) CheckBurn(
	ctx context.Context,
	encoder BurnEncoder,
) error

CheckBurn verifies that ffmpeg can burn subtitles with encoder: that it has the subtitles filter (libass), failing with ErrNoSubtitlesFilter otherwise, and, for a hardware encoder, that it encodes a few frames on this machine. BurnAuto is not tested: Burn falls back to x264 when the hardware fails.

func (*FFmpeg) Copy added in v1.2.0

func (f *FFmpeg) Copy(
	ctx context.Context,
	spec CopySpec,
) error

Copy writes spec.Destination: every segment is copied from its source into a file of its own, then the files are joined, without re-encoding anything. H.264 and HEVC segments travel as MPEG-TS, which carries their parameter sets with every keyframe: sources encoded with other settings then decode once joined. The frames of the result are the sources' own.

func (*FFmpeg) DecodeRaw

func (f *FFmpeg) DecodeRaw(
	ctx context.Context,
	src, dst string,
	withGrain bool,
) error

DecodeRaw decodes src to raw video in a NUT container at dst. withGrain false leaves AV1 film grain out (exported as side data instead of applied): the clean picture fidelity is scored against a denoised reference, since VMAF penalises synthesised grain for not matching the source's grain sample by sample.

func (*FFmpeg) Decodes added in v1.2.0

func (f *FFmpeg) Decodes(
	ctx context.Context,
	path string,
) error

Decodes decodes every frame of the video of path and returns ErrDecode, with what ffmpeg reported, when a frame does not decode: ffmpeg is asked to stop at the first error rather than conceal it.

func (*FFmpeg) Digest

func (f *FFmpeg) Digest(
	ctx context.Context,
	spec DigestSpec,
) error

Digest writes the digest spec describes.

func (*FFmpeg) Encode

func (f *FFmpeg) Encode(
	ctx context.Context,
	codec Codec,
	src, dst string,
	p Params,
) error

Encode encodes src into dst with codec and the settings of p.

func (*FFmpeg) EncodeChunks

func (f *FFmpeg) EncodeChunks(
	ctx context.Context,
	codec Codec,
	src ChunkSource,
	dst string,
	chunks []Chunk,
	p Params,
) error

EncodeChunks encodes src chunk by chunk, each with its own CRF and the other settings of p, and joins the chunks into dst.

func (*FFmpeg) EncodeRendition

func (f *FFmpeg) EncodeRendition(
	ctx context.Context,
	codec Codec,
	spec RenditionSpec,
) error

EncodeRendition writes the rendition spec describes. A rendition is a long encode: it is watched for stalls like every encode, and reports its progress in frames.

func (*FFmpeg) Noise

func (f *FFmpeg) Noise(
	ctx context.Context,
	path string,
	width, height, step int,
) (grain.Stats, error)

Noise measures the grain of path (frames of width×height), on grain.SampleFrames frames taken every step frames, decoded as they would be shown (AV1 film grain applied): ffmpeg decodes and scales, the pure estimator of package grain measures.

type Feature

type Feature int

Feature is an encoder capability callers such as the ladder engine depend on: they ask the codec (Codec.Supports) instead of guessing from its hardware or encoder name.

const (
	// FeatureFilmGrain is film grain synthesis (Params.FilmGrain): the
	// encoder denoises its input, codes the clean picture and signals grain
	// parameters the decoder adds back. SVT-AV1 only: av1_nvenc has none
	// reachable from ffmpeg.
	FeatureFilmGrain Feature = iota + 1
	// FeatureChunkJoin is chunked encoding (FFmpeg.EncodeChunks): chunks
	// encoded separately and joined without re-encoding decode exactly as
	// the separate chunks. Verified for x264, x265 and SVT-AV1 (see Chunk).
	FeatureChunkJoin
)

Encoder features.

type Hardware

type Hardware string

Hardware selects the implementation of a codec's encoder.

const (
	// HardwareCPU encodes with x264, x265 and SVT-AV1 (the zero value).
	HardwareCPU Hardware = ""
	// HardwareNVENC encodes with NVIDIA's hardware encoders (h264_nvenc,
	// hevc_nvenc, av1_nvenc). AV1 needs an Ada Lovelace or newer GPU.
	HardwareNVENC Hardware = "nvenc"
)

Encoder implementations.

func ParseHardware

func ParseHardware(
	s string,
) (Hardware, error)

ParseHardware reads an encoder implementation: cpu (or empty) or nvenc.

func (Hardware) String

func (h Hardware) String() string

String returns the implementation name, "cpu" for the zero value.

type Option

type Option func(*FFmpeg)

Option configures an FFmpeg.

func WithLogger

func WithLogger(
	logger *slog.Logger,
) Option

WithLogger logs to logger the fallbacks of automatic choices (a hardware encoder that does not work on this machine).

func WithStallTimeout

func WithStallTimeout(
	timeout time.Duration,
) Option

WithStallTimeout sets how long an encode may go without its output growing before it is stopped and tried once more (default 5 minutes).

type Params

type Params struct {
	Width, Height int
	CRF           float64
	Preset        string
	// GOP is the keyframe interval in frames (fixed, no scene-cut keyframes,
	// as ABR segmenting requires). 0 lets the encoder decide.
	GOP int
	// MaxRate and BufSize (bits/s, bits) cap the bitrate when set.
	MaxRate int64
	BufSize int64
	// BitDepth is 8 (default) or 10 (Main10 / 10-bit profiles).
	BitDepth int
	// FilmGrain is the SVT-AV1 film grain synthesis level (1–50; 0 off,
	// ignored by the other encoders).
	FilmGrain int
	// Signal is the colour signal the encode carries (HDR sources); the
	// zero value leaves it to the input frames.
	Signal Signal
	// contains filtered or unexported fields
}

Params are the settings of one encode.

type RenditionSpec

type RenditionSpec struct {
	// Source is the title; its Rate and Origin place the chunks.
	Source      ChunkSource
	Destination string
	Params      Params
	// Chunks, when set, are the chunks of a per-shot rendition covering
	// the whole title.
	Chunks []Chunk
	// Progress, when set, is called with the number of frames written so
	// far, about twice a second.
	Progress func(frames int)
}

RenditionSpec describes a rendition of a title: the whole title encoded with Params, or chunk by chunk with the CRFs of Chunks (a per-shot rendition).

type Signal

type Signal struct {
	Color        media.Color              `json:"color"`
	Mastering    *media.MasteringDisplay  `json:"masteringDisplay,omitempty"`
	ContentLight *media.ContentLightLevel `json:"contentLightLevel,omitempty"`
}

Signal is the colour signal an encode carries: its colour description, written in the bitstream (VUI, AV1 sequence header), and for HDR10 the static metadata of SMPTE ST 2086 and CTA-861.3 (SEI, AV1 metadata OBUs). The zero value carries nothing: the encoder writes whatever its input frames say, which is how SDR ladders have always been encoded.

func SignalOf

func SignalOf(
	v media.VideoStream,
) Signal

SignalOf is the signal of an HDR (PQ or HLG) video stream, to carry on its encodes, and the zero Signal for SDR ones. Unknown content light levels (0, 0) are left out.

func (Signal) IsZero

func (s Signal) IsZero() bool

IsZero reports whether the signal carries nothing.

Jump to

Keyboard shortcuts

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