transcode

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package transcode wraps ffmpeg and ffprobe for local audio files.

Callers pass file paths; the package resolves the ffmpeg/ffprobe binaries, limits concurrent processes when configured, captures bounded stderr for diagnostics, and terminates the process, or its process group where supported, when a context is canceled.

A Command is just an argument list, so command construction can be tested without starting ffmpeg. A Spec selects the target Codec, optional bitrate, and pre-encode audio filters. Loudness normalization and cuts are passed in as filters so they can run in the same encode as the format conversion.

Processing uses seekable files, not pipes, because several muxers need seeks while writing. Outputs are staged next to the destination path and renamed into place only after ffmpeg exits successfully. CodecCopy is the no-encode mode; FLAC, ALAC, and WAV decode and encode with lossless codecs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Codec

type Codec uint8

Codec identifies an output audio encoding. CodecCopy stream-copies the source audio into a container. The lossless codecs (FLAC, ALAC, WAV) still decode and encode; they are not stream copies.

const (
	CodecCopy   Codec = iota // stream copy / remux (the only no-re-encode path)
	CodecFLAC                // lossless re-encode (.flac)
	CodecALAC                // lossless re-encode (Apple Lossless in .m4a)
	CodecWAV                 // lossless PCM (.wav)
	CodecMP3                 // libmp3lame (V0 by default, CBR when a bitrate is set)
	CodecAAC                 // native AAC in .m4a
	CodecOpus                // libopus (.opus)
	CodecVorbis              // libvorbis (.ogg)
)

func (Codec) Extension

func (c Codec) Extension() string

Extension returns the canonical file extension (without a dot) for c, or "" for CodecCopy (whose container follows the source).

func (Codec) IsLossless

func (c Codec) IsLossless() bool

IsLossless reports whether c uses a stream copy or a lossless encoder. For CodecWAV, Transcode probes the source and picks the PCM encoder with wavEncoder; sources that do not report a usable depth use the 16-bit fallback.

func (Codec) String

func (c Codec) String() string

type Command

type Command struct {
	Args []string
}

Command is a built ffmpeg invocation. Args excludes the binary name.

func (Command) String

func (c Command) String() string

type ProbeFormat

type ProbeFormat struct {
	FormatName string
	Duration   time.Duration
	Size       int64
	BitRate    int
}

ProbeFormat describes the container.

type ProbeResult

type ProbeResult struct {
	Format  ProbeFormat
	Streams []ProbeStream
}

ProbeResult is the parsed subset of ffprobe's -show_format -show_streams JSON: container metadata plus per-stream codec details.

func (ProbeResult) AudioStream

func (p ProbeResult) AudioStream() (ProbeStream, bool)

AudioStream returns the first audio stream and true, or a zero stream and false when the result carries no audio. Probe rejects no-audio inputs with waxerr.ErrUnsupportedInput, so a result obtained from Probe always has one; this accessor is for inspecting a ProbeResult directly.

type ProbeStream

type ProbeStream struct {
	Index      int
	CodecType  string // "audio", "video", ...
	CodecName  string // e.g. "opus", "aac", "flac"
	SampleRate int    // Hz (audio)
	Channels   int
	BitRate    int
	Duration   time.Duration

	// SampleFmt is ffprobe's sample_fmt (for example "s16", "s32", or "fltp").
	// BitsPerSample is the coded PCM depth. BitsPerRawSample is the source depth
	// reported by some lossless codecs, such as a 24-bit FLAC. A zero value means
	// ffprobe did not report the field.
	SampleFmt        string
	BitsPerSample    int
	BitsPerRawSample int
}

ProbeStream describes one media stream.

type Result

type Result struct {
	Output string // final output path
	Size   int64  // output size in bytes (0 if it could not be stat'd)
	Codec  Codec  // codec the output was encoded with
}

Result reports a completed transcode.

type RunError

type RunError struct {
	Binary   string
	Args     []string
	ExitCode int
	Stderr   string
	Err      error
}

RunError reports a non-zero ffmpeg/ffprobe exit and includes a bounded stderr tail for diagnosis.

func (*RunError) Error

func (e *RunError) Error() string

func (*RunError) Unwrap

func (e *RunError) Unwrap() error

type RunResult

type RunResult struct {
	Stdout []byte
	Stderr []byte
}

RunResult holds captured output from an ffmpeg run. Stderr is a bounded tail.

type Runner

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

Runner executes ffmpeg and ffprobe. It resolves the binaries once, bounds the number of concurrent processes, captures a bounded tail of stderr for diagnostics, and terminates the process on context cancellation. On Unix it uses a process group so helper children are signaled with the ffmpeg process. Runner is safe for concurrent use.

func NewRunner

func NewRunner(cfg RunnerConfig) (*Runner, error)

NewRunner resolves the ffmpeg and ffprobe binaries and returns a Runner. It returns a wrapped waxerr.ErrFFmpegNotFound if either binary cannot be located.

func (*Runner) FFmpegPath

func (r *Runner) FFmpegPath() string

FFmpegPath returns the resolved ffmpeg binary path.

func (*Runner) FFprobePath

func (r *Runner) FFprobePath() string

FFprobePath returns the resolved ffprobe binary path.

func (*Runner) Probe

func (r *Runner) Probe(ctx context.Context, input string) (ProbeResult, error)

Probe runs ffprobe on a local input and returns the parsed result. ffprobe failures, malformed JSON, and media with no audio stream are reported as waxerr.ErrUnsupportedInput.

func (*Runner) ProbeURL

func (r *Runner) ProbeURL(ctx context.Context, url string, headers http.Header) (ProbeResult, error)

ProbeURL probes a remote input with the supplied HTTP headers. This is used for signed media URLs whose User-Agent or token headers must match the resolver. Empty headers behave like Probe. ProbeURL can block on the network, so callers should pass a bounded context.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, cmd Command) (RunResult, error)

Run executes ffmpeg with cmd's arguments. A non-zero exit becomes a *RunError carrying the stderr tail; a canceled context returns ctx.Err() after the child process has been stopped.

func (*Runner) Transcode

func (r *Runner) Transcode(ctx context.Context, input, output string, spec Spec) (Result, error)

Transcode reads input, applies spec.Filters, encodes per spec, and writes the result to output. The output is staged in a temp file in output's directory and atomically renamed into place on success; on failure or cancellation the temp is removed and any existing file at output is left untouched.

Input must be a seekable local file. A stream copy (CodecCopy) combined with filters is rejected with waxerr.ErrIncompatibleSpec before any process starts.

type RunnerConfig

type RunnerConfig struct {
	// FFmpegPath and FFprobePath override the binaries; empty looks them up in
	// PATH by name.
	FFmpegPath  string
	FFprobePath string
	// ShutdownGrace is how long a canceled process is given to exit after SIGTERM
	// before it is force-killed (default 5s).
	ShutdownGrace time.Duration
	// MaxProcs bounds concurrent ffmpeg/ffprobe processes (0 = unlimited). It
	// guards local CPU independently from network parallelism.
	MaxProcs int
	// Logger receives debug logs. Nil discards them.
	Logger *slog.Logger
}

RunnerConfig configures a Runner. The binary paths are looked up in PATH when left empty.

type Spec

type Spec struct {
	Codec   Codec
	Bitrate int
	// Filters is a comma-joined -af chain for linear audio filters such as
	// loudnorm. It is mutually exclusive with FilterComplex.
	Filters []string
	// FilterComplex is a complete -filter_complex graph. The graph must read the
	// source audio from [0:a:0] and write the final audio to [out]; buildCommand
	// maps [out] as the only output stream. Use it for labeled or multi-input
	// graphs such as concat/acrossfade. It is mutually exclusive with Filters and
	// cannot be used with CodecCopy.
	FilterComplex string
}

Spec describes a transcode. Codec selects the output codec, Bitrate overrides lossy preset defaults in bits/sec, and the optional filter fields run before encoding. The zero value is a stream copy with no filters.

Jump to

Keyboard shortcuts

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