almost complete implementation
This commit is contained in:
@@ -1,3 +1,187 @@
|
||||
<img src="gopeg.webp" width="100%" alt="gopeg banner">
|
||||
|
||||
# gopeg
|
||||
|
||||
Complete go video decoding solution.
|
||||
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
|
||||
```
|
||||
|
||||
The script dav1d sources from [gav1d](https://github.com/d1nch8g/gav1d) (fork for AV1 decoder) to home directory if not present, builds static libs for all targets, and populates `vendor/`.
|
||||
|
||||
## License
|
||||
|
||||
GPLv3 - this is free software. Contributions are welcome, feel free to open an issue.
|
||||
|
||||
Reference in New Issue
Block a user