Talk to any ONVIF camera from Go.
Find cameras on the network, read their streams, move them, and test against virtual ones when no hardware is around.
$ go get github.com/0x524a/onvif-go
// WS-Discovery on the local network → Probe NetworkVideoTransmitter ← ProbeMatches lobby-camera 192.168.1.21:8080 ← ProbeMatches dock-ptz 192.168.1.34 2 devices found in 412ms
One client for every vendor.
Context on every call, safe to share across goroutines, and an endpoint can be a full URL, host:port or just an IP. Call Initialize once and the client finds the media, PTZ and imaging services itself.
client, err := onvif.NewClient( "192.168.1.100", onvif.WithCredentials("admin", "password"), onvif.WithTimeout(30*time.Second), ) if err := client.Initialize(ctx); err != nil { /* ... */ } profiles, _ := client.GetProfiles(ctx) uri, _ := client.GetStreamURI(ctx, profiles[0].Token) fmt.Println(uri.URI) // rtsp://192.168.1.100:554/...
// pan right for two seconds, then stop velocity := &onvif.PTZSpeed{ PanTilt: &onvif.Vector2D{X: 0.5, Y: 0}, } timeout := "PT2S" err := client.ContinuousMove(ctx, token, velocity, &timeout) err = client.Stop(ctx, token, true, true) // recall a saved position presets, _ := client.GetPresets(ctx, token) err = client.GotoPreset(ctx, token, presets[0].Token, nil)
settings, _ := client.GetImagingSettings(ctx, videoSource) brightness, contrast := 60.0, 55.0 settings.Brightness = &brightness settings.Contrast = &contrast err := client.SetImagingSettings(ctx, videoSource, settings, true)
No camera on your desk? Run one.
The server package is a virtual multi-lens camera with Device, Media, PTZ and Imaging services. Add the WS-Discovery responder and your own client, VMS or CI job finds it like real hardware.
Give it a stable name and it keeps the same endpoint ID after every restart.
cfg := server.DefaultConfig() cfg.EndpointSeed = "lobby-camera" // same ID on every start ready := make(chan struct{}) cfg.Ready = ready srv, _ := server.New(cfg) go srv.Start(ctx) <-ready resp := discovery.NewResponder(&discovery.ResponderConfig{}) resp.Register(srv.DiscoveryDevice()) go resp.Start(ctx) // answers Probes, sends Hello and Bye
What it covers.
Typed requests and responses for the ONVIF services cameras actually ship, with WS-Security digest authentication on every call.
| Device | 98 APIs | Information, capabilities, network, users, certificates, Wi-Fi, storage, logs, firmware |
|---|---|---|
| Media | 14+ APIs | Profiles, RTSP and HTTP stream URIs, snapshots, encoder settings |
| PTZ | 13 APIs | Continuous, absolute and relative moves, presets, home position, status |
| Imaging | 7 APIs | Brightness, contrast, exposure, focus, white balance, wide dynamic range |
| Discovery | client + responder | Find devices on a chosen network interface, or announce your own |
| Events, Device I/O | included | Pull-point subscriptions, relays, digital inputs |
Command-line tools included.
Prebuilt binaries are attached to every release.
-op info, -op stream, -op discover.Tested against real cameras.
AxisHikvisionDahuaBoschHanwha
Responses captured from these vendors' devices are replayed in the test suite, so a fix for one camera does not break another. Supports ONVIF Profile S, T and G. Needs Go 1.25 or newer.