main
swr was configured for planar FLTP output while decodeAudio handed it a single packed-buffer pointer, so the resampler never wrote into the Go slice and every AudioFrame came back as zeros. Switch the output format to packed FLT and pass the plane pointer through a C-allocated slot so cgo accepts the handoff. Extend TestDecodeFrames to fail on all-zero audio buffers. Assisted-by: AGENT: Claude Sonnet 4.5
gopeg
Go video decoding library with no runtime dependencies. FFmpeg is statically linked — import the package and get a single binary, no system installs required.
Installation
go get m8sh.su/x/gopeg
Requires CGO and a C compiler:
# arch/manjaro
sudo pacman -S gcc
# debian/ubuntu
sudo apt install gcc
Platforms
| Platform | Arch | Status |
|---|---|---|
linux/amd64 |
x86_64 | ✅ Supported |
linux/arm64 |
AArch64 | ✅ Supported |
windows/amd64 |
x86_64 | ✅ Supported |
darwin/amd64 |
x86_64 | ✅ Supported |
darwin/arm64 |
Apple Silicon | ✅ Supported |
web/wasm |
wasm32 | 🚧 Coming soon |
Supported formats
| Codecs | |
|---|---|
| Video | H.264, H.265/HEVC, AV1, VP9, VP8, MPEG-4 |
| Audio | AAC, MP3, Opus, Vorbis, FLAC, PCM |
| Containers | MP4, MKV, WebM, AVI, FLV, OGG, IVF, MPEGTS |
Features
- Decode video frames as
image.NRGBA— standard Go image type, no conversion needed - Decode audio frames as
[]float32interleaved PCM - Read from any
io.Reader— files, in-memory buffers, HTTP streams, pipes - Seeking supported when the reader implements
io.Seeker; works without it too - Zero runtime dependencies — all FFmpeg and dav1d libs statically linked
- Single
go buildfor all supported platforms
Quick start
package main
import (
"fmt"
"image/png"
"os"
"m8sh.su/x/gopeg"
)
func main() {
f, _ := os.Open("video.mp4")
defer f.Close()
dec, err := gopeg.NewDecoder(f)
if err != nil {
panic(err)
}
defer dec.Close()
meta := dec.Meta()
fmt.Printf("duration: %.2fs\n", meta.Duration.Seconds())
fmt.Printf("video: %dx%d %s @ %d/%d fps\n",
meta.Video.Width, meta.Video.Height,
meta.Video.CodecName,
meta.Video.FPSNum, meta.Video.FPSDen)
if meta.Audio != nil {
fmt.Printf("audio: %dHz %dch %s\n",
meta.Audio.SampleRate,
meta.Audio.Channels,
meta.Audio.CodecName)
}
for {
frame, err := dec.DecodeFrame()
if err != nil {
panic(err)
}
if frame == nil {
break // EOF
}
if frame.Video != nil {
f, _ := os.Create("frame.png")
png.Encode(f, frame.Video.Img)
f.Close()
}
if frame.Audio != nil {
fmt.Printf("audio pts=%v samples=%d\n",
frame.Audio.PTS,
len(frame.Audio.Samples)/frame.Audio.Channels)
}
}
}
API
// Open a decoder from any reader. If r also implements io.Seeker,
// FFmpeg will use it for random access where the format requires it.
func NewDecoder(r io.Reader) (*Decoder, error)
// Returns duration, video/audio stream info. Safe to call before decoding.
func (d *Decoder) Meta() Meta
// Decode the next video or audio frame. Returns nil, nil on EOF.
// Frame.Video and Frame.Audio are mutually exclusive per call.
func (d *Decoder) DecodeFrame() (*Frame, error)
// Release all FFmpeg resources. Safe to call multiple times.
func (d *Decoder) Close()
Types
type Meta struct {
Duration time.Duration
Video *VideoMeta // nil if no video stream
Audio *AudioMeta // nil if no audio stream
}
type VideoMeta struct {
Width, Height int
FPSNum, FPSDen int
CodecName string
}
type AudioMeta struct {
SampleRate int
Channels int
CodecName string
}
type Frame struct {
Video *VideoFrame
Audio *AudioFrame
}
type VideoFrame struct {
Img *image.NRGBA
PTS time.Duration
Duration time.Duration
}
type AudioFrame struct {
Samples []float32 // interleaved
Channels int
SampleRate int
PTS time.Duration
}
Building from source
The vendor/ directory contains prebuilt static libraries for all supported platforms. To rebuild from scratch, delete vendor/ and use the build script:
# arch/manjaro
sudo pacman -S gcc meson ninja nasm aarch64-linux-gnu-gcc mingw-w64-gcc
# debian/ubuntu
sudo apt install gcc meson ninja-build nasm gcc-aarch64-linux-gnu gcc-mingw-w64-x86-64
go run cmd/build/main.go
Script clones necessary repositories (default dav1d mirror and FFmpeg mirror), builds them into static libraries for linking with CGO with preset of required parameters and produces a vendor directory.
License
GPLv3 - this is free software. Contributions are welcome, feel free to open an issue.
Description
Go video decoding solution (no runtime dependencies)
75 MiB
0 Stars
1 Watchers
0 Forks