ffdecode

package
v1.0.260758 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package ffdecode wraps ffmpeg subprocesses for raw audio/video decode — shared between apps/amp (audio only) and apps/vid (video, plus a separate ffmpeg process for the video's own audio track). Never a linked decoder library, on purpose: keeps the desktop binary itself free of format-specific code, matching the GUI-TUI Bridge's Xvfb — a soft runtime dependency, only needed if you actually use the feature.

Index

Constants

View Source
const (
	SampleRate = 48000
	Channels   = 2
)

SampleRate/Channels match internal/audio's fixed output format — decode straight to what the shared oto.Context expects, no separate resample step.

Variables

This section is empty.

Functions

func Available

func Available() bool

Available reports whether ffmpeg is on PATH — checked once by callers before decoding, for a clear error instead of a raw exec failure.

Types

type AudioEvent

type AudioEvent struct {
	Ended bool
	Err   error
}

AudioEvent is how an AudioStream's feeder goroutine reports back — never by touching caller state directly (see AudioStream's doc comment for why); drain this from whatever single-threaded path owns your app state, exactly like every other background-goroutine result channel in this codebase (apps/calendar/sync.go, apps/settings/calendar_page.go).

type AudioStream

type AudioStream struct {
	PCM chan []int16
	// contains filtered or unexported fields
}

AudioStream decodes one file's audio track to raw PCM via an ffmpeg subprocess. PCM delivers interleaved int16 samples at SampleRate/ Channels.

func DecodeAudio

func DecodeAudio(path string, onChunk func([]int16), events chan<- AudioEvent) (*AudioStream, error)

DecodeAudio launches ffmpeg on path and begins feeding PCM into the returned stream's PCM channel. events receives exactly one AudioEvent when the track ends (Ended=true) or decode fails (Err set). onChunk, if non-nil, sees each chunk synchronously in the feeder goroutine, before it's sent to PCM — callers needing per-chunk work (Amp's visualizer) should keep that work cheap and do their own synchronization, since it runs on a different goroutine than whatever's reading PCM. Passed in here rather than set on the returned struct: it must be fixed before the feeder goroutine starts, not mutated after — setting it post-construction would race that goroutine's first read of it (confirmed by go test -race while writing this).

func DecodeAudioAt

func DecodeAudioAt(path string, seek time.Duration, onChunk func([]int16), events chan<- AudioEvent) (*AudioStream, error)

DecodeAudioAt is DecodeAudio starting from seek into the file (0 for the beginning) — an input-side `-ss` seek, ffmpeg's fast, keyframe-ish seek rather than a precise decode-and-discard one. Vid uses this for scrubbing; Amp always seeks to zero via plain DecodeAudio.

func (*AudioStream) Stop

func (s *AudioStream) Stop()

Stop kills the ffmpeg subprocess and unblocks feed if it's stuck mid-send with nothing left to drain it. Safe to call more than once, and safe to call after decode has already finished on its own.

type VideoEvent

type VideoEvent struct {
	Ended bool
	Err   error
}

VideoEvent is how a VideoStream's feeder goroutine reports back — same drain-from-your-single-threaded-path contract as AudioEvent.

type VideoFrame

type VideoFrame struct {
	Pix  []byte
	W, H int
}

VideoFrame is one decoded frame: raw RGB24 (3 bytes/pixel, no alpha), W*H*3 bytes, row-major.

func (VideoFrame) Image

func (f VideoFrame) Image() image.Image

Image returns f as an image.Image — wraps Pix directly, no copy, for feeding straight into internal/gfx.EncodeHalfBlockFit.

type VideoStream

type VideoStream struct {
	Frames chan VideoFrame
	// contains filtered or unexported fields
}

VideoStream decodes one file's video track to raw RGB24 frames via an ffmpeg subprocess, pre-scaled to w x h pixels at fps — scaling in ffmpeg rather than after decode keeps the pipe's byte volume (and the per-frame conversion cost) down to roughly what the terminal can actually show, instead of piping full source resolution just to downsample it a moment later.

func DecodeVideo

func DecodeVideo(path string, w, h, fps int, events chan<- VideoEvent) (*VideoStream, error)

DecodeVideo launches ffmpeg on path and begins feeding frames into the returned stream's Frames channel. events receives exactly one VideoEvent when the video ends (Ended=true) or decode fails (Err set).

func DecodeVideoAt

func DecodeVideoAt(path string, seek time.Duration, w, h, fps int, events chan<- VideoEvent) (*VideoStream, error)

DecodeVideoAt is DecodeVideo starting from seek into the file (0 for the beginning) — see DecodeAudioAt's doc comment; Vid uses this for scrubbing.

func (*VideoStream) Stop

func (s *VideoStream) Stop()

Stop kills the ffmpeg subprocess and unblocks feed if it's stuck mid-send with nothing left to drain it. Safe to call more than once, and safe to call after decode has already finished on its own.

Jump to

Keyboard shortcuts

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