188 lines
4.5 KiB
Markdown
188 lines
4.5 KiB
Markdown
<img src="gopeg.webp" width="100%" alt="gopeg banner">
|
|
|
|
# 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:
|
|
|
|
```sh
|
|
# 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 `[]float32` interleaved 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 build` for all supported platforms
|
|
|
|
## Quick start
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
// 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
|
|
|
|
```go
|
|
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:
|
|
|
|
```sh
|
|
# 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
|
|
```
|
|
|
|
```sh
|
|
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.
|