Documentation
¶
Overview ¶
Package avfoundation decodes video files on macOS through AVFoundation, with no cgo.
It exists because there is no realistic pure-Go alternative for the job: a software H.264 or HEVC decoder in Go will not keep up with 4K at 60 frames a second, while the hardware decoder in every Mac will do it without warming up. AVFoundation is the system's own front door to that decoder, and it brings demuxing and format support along with it. Everything here goes through github.com/ebitengine/purego, so a consumer still builds with CGO_ENABLED=0 — the constraint the fleet actually cares about is no cgo, not no operating system.
The model is a pull: Open a file and call Reader.NextFrame until it reports io.EOF. Frames come out as fast as they decode, carrying their presentation timestamps, and the caller owns the clock. That is the right shape for a renderer that has its own frame loop — an immersive viewer must draw when the display is ready, not when a player decides.
Frames are NOT copied. A Frame holds the decoder's own buffer locked, and its pixels stay valid until Frame.Release. At 4K that saves about 33 MB of copying per frame, which is the difference between comfortable and not.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnsupported is returned by every entry point on non-darwin platforms. ErrUnsupported = errors.New("avfoundation: unsupported on this platform (darwin only)") // ErrNoVideoTrack is returned by [Open] for a file with no video in it. ErrNoVideoTrack = errors.New("avfoundation: file has no video track") // ErrClosed is returned when a Reader is used after [Reader.Close]. ErrClosed = errors.New("avfoundation: reader is closed") // ErrReleased is returned by [Frame] accessors after [Frame.Release]. ErrReleased = errors.New("avfoundation: frame has been released") // ErrUnsupportedFormat is returned by [Open] for a pixel format the decoder // will not produce. See [Options.Format]. ErrUnsupportedFormat = errors.New("avfoundation: the decoder will not produce that pixel format") )
Errors reported by the package. They are stable and may be tested with errors.Is.
Functions ¶
This section is empty.
Types ¶
type Frame ¶
type Frame struct {
// Width and Height are this frame's dimensions in pixels.
Width, Height int
// Stride is the number of bytes per row, which is USUALLY more than
// Width*4: the decoder pads rows for alignment. Indexing by Width*4 instead
// of Stride produces a picture that shears progressively down the frame,
// which looks like a decode bug and is not one.
Stride int
// Format is the pixel layout, as requested when the reader was opened.
Format PixelFormat
// PTS is the presentation timestamp: when this frame should be shown,
// relative to the start of the file.
PTS time.Duration
// Pix is the frame's bytes, Stride*Height of them.
Pix []byte
// contains filtered or unexported fields
}
Frame is one decoded frame. Its pixels alias the decoder's buffer and are valid until Frame.Release — which the caller must call, once, for every frame it receives. Holding many unreleased frames will stall the decoder, because it is waiting for its own buffers back.
func (*Frame) Release ¶
func (f *Frame) Release()
Release hands the buffer back to the decoder. It is safe to call more than once, and a released Frame's Pix must not be read.
func (*Frame) ToRGBA ¶
ToRGBA copies the frame into an *image.RGBA, converting from BGRA if needed.
dst is reused when it is exactly the right size, so a render loop can hold one image and not allocate per frame; pass nil, or an image of the wrong size, to get a fresh one. It returns nil for a released frame.
type Info ¶
type Info struct {
// Width and Height are the coded dimensions in pixels.
Width, Height int
// FrameRate is the track's nominal rate in frames per second. It is nominal:
// variable-frame-rate material reports an average, so time anything that
// matters by a frame's own PTS rather than by counting frames.
FrameRate float64
// Duration is the track's duration.
Duration time.Duration
}
Info describes a file's video track, read when it is opened.
type OpenError ¶
OpenError describes a failure to open or start reading a file, carrying whatever AVFoundation said about it.
type Options ¶
type Options struct {
// Format is the pixel format to decode into. Zero means [BGRA].
Format PixelFormat
}
Options parametrise Open. The zero value asks for BGRA, which is what the decoder produces natively.
type PixelFormat ¶
type PixelFormat uint32
PixelFormat is a CoreVideo pixel format, which is a four-character code.
const ( // BGRA is 32-bit BGRA, 8 bits per channel. It is what the display pipeline // and Metal both prefer, so it is the default: asking for RGBA instead would // make something, somewhere, swap two bytes per pixel for nothing. BGRA PixelFormat = 0x42475241 // 'BGRA' // RGBA is 32-bit RGBA. It DESCRIBES a frame's layout but is NOT accepted as a // decode request: measured on macOS, an AVAssetReaderTrackOutput asked for // RGBA fails outright (reader status 3) rather than converting. Use // [Frame.ToRGBA] to convert a decoded BGRA frame instead. RGBA PixelFormat = 0x52474241 // 'RGBA' )
The formats this package can ask the decoder for.
func (PixelFormat) String ¶
func (f PixelFormat) String() string
String renders the format as its four-character code.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader decodes a file's first video track, in order, from the beginning.
It is NOT safe for concurrent use: one goroutine pulls frames. Seeking is not implemented yet — a reader plays through once.
func (*Reader) Close ¶
Close releases the decoder. Frames already handed out stay valid until they are individually released.
func (*Reader) Format ¶
func (r *Reader) Format() PixelFormat
Format returns the pixel format frames are decoded into.