Skip to content
thesyncimPublic

About

Pure-Go media workflow runtime for validated, inspectable, in-process audio/video pipelines

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

1,148 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

goav

Media pipelines in pure Go. Decode, transform, encode, and mux inside your service:
the core needs no cgo, no FFmpeg, and no system libraries.

CI Go Reference Go 1.27+ License: Apache-2.0 Status: pre-v1

You describe media work as plain Go values, and goav plans it, builds the graph, and runs it. The codecs and containers are pure Go (VP8, VP9, AV1, Opus; WebM, Matroska, MP4), so your service still ships as one static binary.

go get github.com/thesyncim/goav@latest   # Go 1.27+
GOEXPERIMENT=simd go build ./...         # always: enables the SIMD codec paths

Build, test, and run with GOEXPERIMENT=simd. It switches the codecs onto Go 1.27's portable SIMD paths; without it they fall back to scalar code. On one machine (Apple M4 Max, 128x96 test clips) that cut codec benchmark time by roughly half; treat it as a direction, not a guarantee (measurements and scope).

Quick start

package main

import (
	"context"
	"log"
	"os"

	"github.com/thesyncim/goav"
	"github.com/thesyncim/goav/bundle"
	"github.com/thesyncim/goav/codec"
)

// Scale a WebM to 720p and re-encode it as VP9.
func main() {
	src, err := os.Open("in.webm")
	if err != nil {
		log.Fatal(err)
	}
	dst, err := os.Create("out.webm")
	if err != nil {
		log.Fatal(err)
	}
	video := goav.FileInput("in.webm", src).Video().
		Decode().
		Resize(1280, 720).
		Encode(codec.VP9(codec.Bitrate(2_000_000)))
	if err := bundle.Run(context.Background(), video.To(goav.Write("out.webm", dst))); err != nil {
		log.Fatal(err)
	}
}

goav.FileInput takes any io.Reader and goav.Write any io.Writer; bundle.Run closes the writer when the run ends.

No WebM handy? Make a test clip with the CLI.
GOEXPERIMENT=simd go run github.com/thesyncim/goav/cmd/goav@latest run \
  'testsrc video size=1920x1080 duration=2s ! encode vp9 ! file in.webm
   testsrc audio duration=2s ! encode opus ! file in.webm'

Fan out by reuse

Every operation returns a new goav.Stream, so a stream you use twice forks, and the work before the fork runs once. Here one decode feeds two renditions, and one Opus encode of the input's audio track is muxed into both files:

in := goav.FileInput("in.webm", src)
video := in.Video().Decode()
audio := in.Audio().Decode().Encode(codec.Opus())
hd, sd := goav.Write("hd.webm", hdFile), goav.Write("sd.webm", sdFile)

err := bundle.Run(ctx,
    video.Resize(1280, 720).Encode(codec.VP9()).As("hd").To(hd),
    video.Resize(640, 360).Encode(codec.VP9()).As("sd").To(sd),
    audio.To(hd, sd),
)

stream.To(...) makes an Output. bundle.Run runs Outputs together with the bundled codecs and containers; a runtime of your own runs them the same way: rt.Run(ctx, outputs...).

The same recipe as text, for a command line, a config file, or a control socket. It builds the identical graph (launch, CLI):

GOEXPERIMENT=simd go install github.com/thesyncim/goav/cmd/goav@latest
goav run 'v := file in.webm ! video ! decode
          v ! resize 1280x720 ! encode vp9 ! as hd ! file hd.webm
          v ! resize 640x360 ! encode vp9 ! as sd ! file sd.webm
          file in.webm ! audio ! decode ! encode opus ! file hd.webm, file sd.webm'

See the plan first

A recipe is data until it runs. bundle.Describe(outputs...) returns the exact graph a run would build, without opening anything, and graphrender.RenderURI(spec, "goav:graph") prints it. The quick start's nodes:

pipeline goav
  source in.webm [demux, protocol=file]
  stage select-video [select, type=video]
  stage decode-video [packets -> frames, type=video]
  stage resize-video [resize, 1280x720, exact]
  stage encode-video [frames -> packets, codec=vp9, backend=govpx (go)]
  stage out.webm [mux, protocol=file]

Errors name the fix

A mistake comes back before anything opens, as a *goav.BuildError with a stable code and the fix. Leave out the encoder and you get:

goav: cannot build job for video: decoded frames cannot be written to a muxed output without an encoder
Suggestions:
  - call .Encode(codec.VP8(...)), .Encode(codec.VP9(...)), or .Encode(codec.AV1(...)) before .To(goav.Write(...))
  - send decoded frames to goav.Sink(...)
  - leave out .Decode() to copy the packets: input.Video().To(output)

See Errors for matching on codes; graphrender also renders DOT and Mermaid.

What's in the box

Decode / demux Encode / mux
Video VP8, VP9, AV1, H.264 (-tags goav_goh264) VP8, VP9, AV1
Audio Opus Opus (in WebM, Matroska, or MP4)
Containers Matroska, WebM, IVF, MP4 Matroska, WebM, MP4 (progressive or fragmented), IVF, Annex B (H.264)

Plus Resize and Resample. bundle registers all of these; goav.New(...) builds a runtime with only the adapters you choose, and there is no global registry. AAC comes from libcodec (AudioToolbox, macOS) or the opt-in gplcodec (pure Go, arm64 only, GPL). Everything bundle links is permissive, except LGPL H.264 under its tag; see licenses.

Recipes

Need Shape
Remux without decoding in.To(goav.Write("out.mkv", w))
Audio and video in one file pass in.Video()…To(out) and in.Audio()…To(out) to one Run
Frames into your code in.Video().Decode().To(goav.Sink(component.SinkFunc("frames", fn)))
Mix, composite, switch goav.Mix(a, b), goav.Composite(cam, goav.At(screen.Resize(480, 270), 1420, 790)), goav.Select(a, b)
Package for HLS goav.Custom("live", hls.New("live.m3u8", hls.Dir(dir), hls.Window(6))); hls.NewLadder for renditions, hls.Parts with an hls.Server for LL-HLS, or goav run --serve :8080 '... ! hls live.m3u8 parts=250ms'
Change a running task task.Attach(ctx, task.Tap("live").Encode(codec.VP8()).To(preview))
Test a pipeline goavtest: deterministic sources, a recording sink, a fake clock

RTP and WebRTC, in and out, live in their own modules (RTP & WebRTC), and your own sources, codecs, and sinks plug in through small interfaces (Extension cookbook). More in Use cases, Operations, and examples/, including a browser WebRTC ladder and a native Gio control room.

Built for live services

  • One clock per task. Pacing, playout, pause and resume, seek, and rate share one timeline. Each fork can backpressure or drop on its own, and every drop is counted. See Flow control.
  • Change it while it runs. Attach and detach outputs, switch inputs, and drive it all over a control socket (Control plane).
  • Fast without assembly. Graph, codec, and filter stages allocate nothing per message, and GOEXPERIMENT=simd enables Go 1.27 SIMD codec paths (faster in our 128x96 microbenchmarks on one machine; not a general claim). See Performance.

Modules

Module Adds
github.com/thesyncim/goav recipes, planner, runtime; bundled adapters in bundle
goav/rtpav RTP in and out: jitter buffer, (de)packetizers, RTCP feedback (Pion)
goav/webrtcav WebRTC tracks in and out, WHEP and WHIP (Pion)
goav/playoutav scheduled packet, frame, and event playout
goav/player a playback window, synced to the speaker: play in programs, goav play FILE
goav/libcodec codecs in shared libraries and OS frameworks, no cgo: VideoToolbox, AudioToolbox, OpenH264
goav/gplcodec opt-in copyleft codecs: gplcodec.AAC(), a pure-Go AAC-LC decoder (GPL; your binary becomes GPL)
goav/cmd/goav the goav CLI: run, describe, explain, play, ctl (CLI)
goav/goavtest/expect go-cmp assertions for pipeline tests

The core module never pulls in Pion.

Status

Pre-v1: breaking changes can land until the first tag. See V1 scope and the roadmap. Not related to github.com/giorgisio/goav, a cgo binding to FFmpeg.


All docs · Architecture · Adapter authoring · RTP & WebRTC · vs GStreamer · Changelog · Contributing · Security

About

Pure-Go media workflow runtime for validated, inspectable, in-process audio/video pipelines

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages