Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controls #21

Merged
merged 21 commits into from
Jan 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/getcontrols/getcontrols.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Example program that reads the list of available controls and prints them.
package main

import (
"flag"
"fmt"

"github.com/blackjack/webcam"
)

var device = flag.String("input", "/dev/video0", "Input video device")

func main() {
flag.Parse()
cam, err := webcam.Open(*device)
if err != nil {
panic(err.Error())
}
defer cam.Close()

fmap := cam.GetSupportedFormats()
fmt.Println("Available Formats: ")
for p, s := range fmap {
var pix []byte
for i := 0; i < 4; i++ {
pix = append(pix, byte(p>>uint(i*8)))
}
fmt.Printf("ID:%08x ('%s') %s\n ", p, pix, s)
for _, fs := range cam.GetSupportedFrameSizes(p) {
fmt.Printf(" %s", fs.GetString())
}
fmt.Printf("\n")
}

cmap := cam.GetControls()
fmt.Println("Available controls: ")
for id, c := range cmap {
fmt.Printf("ID:%08x %-32s Min: %4d Max: %5d\n", id, c.Name, c.Min, c.Max)
}
}
86 changes: 74 additions & 12 deletions v4l2.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ import (
"golang.org/x/sys/unix"
)

type controlType int

const (
c_int controlType = iota
c_bool
c_menu
)

type control struct {
id uint32
name string
c_type controlType
min int32
max int32
}

const (
V4L2_CAP_VIDEO_CAPTURE uint32 = 0x00000001
V4L2_CAP_STREAMING uint32 = 0x04000000
Expand All @@ -29,6 +45,28 @@ const (
V4L2_CID_PRIVATE_BASE uint32 = 0x08000000
)

const (
V4L2_CTRL_TYPE_INTEGER uint32 = 1
V4L2_CTRL_TYPE_BOOLEAN uint32 = 2
V4L2_CTRL_TYPE_MENU uint32 = 3
V4L2_CTRL_TYPE_BUTTON uint32 = 4
V4L2_CTRL_TYPE_INTEGER64 uint32 = 5
V4L2_CTRL_TYPE_CTRL_CLASS uint32 = 6
V4L2_CTRL_TYPE_STRING uint32 = 7
V4L2_CTRL_TYPE_BITMASK uint32 = 8
V4L2_CTRL_TYPE_INTEGER_MENU uint32 = 9

V4L2_CTRL_COMPOUND_TYPES uint32 = 0x0100
V4L2_CTRL_TYPE_U8 uint32 = 0x0100
V4L2_CTRL_TYPE_U16 uint32 = 0x0101
V4L2_CTRL_TYPE_U32 uint32 = 0x0102
)

const (
V4L2_CTRL_FLAG_DISABLED uint32 = 0x00000001
V4L2_CTRL_FLAG_NEXT_CTRL uint32 = 0x80000000
)

var (
VIDIOC_QUERYCAP = ioctl.IoR(uintptr('V'), 0, unsafe.Sizeof(v4l2_capability{}))
VIDIOC_ENUM_FMT = ioctl.IoRW(uintptr('V'), 2, unsafe.Sizeof(v4l2_fmtdesc{}))
Expand All @@ -37,6 +75,7 @@ var (
VIDIOC_QUERYBUF = ioctl.IoRW(uintptr('V'), 9, unsafe.Sizeof(v4l2_buffer{}))
VIDIOC_QBUF = ioctl.IoRW(uintptr('V'), 15, unsafe.Sizeof(v4l2_buffer{}))
VIDIOC_DQBUF = ioctl.IoRW(uintptr('V'), 17, unsafe.Sizeof(v4l2_buffer{}))
VIDIOC_G_CTRL = ioctl.IoRW(uintptr('V'), 27, unsafe.Sizeof(v4l2_control{}))
VIDIOC_S_CTRL = ioctl.IoRW(uintptr('V'), 28, unsafe.Sizeof(v4l2_control{}))
VIDIOC_QUERYCTRL = ioctl.IoRW(uintptr('V'), 36, unsafe.Sizeof(v4l2_queryctrl{}))
//sizeof int32
Expand Down Expand Up @@ -418,28 +457,51 @@ func waitForFrame(fd uintptr, timeout uint32) (count int, err error) {

}

func getControl(fd uintptr, id uint32) (int32, error) {
ctrl := &v4l2_control{}
ctrl.id = id
err := ioctl.Ioctl(fd, VIDIOC_G_CTRL, uintptr(unsafe.Pointer(ctrl)))
return ctrl.value, err
}

func setControl(fd uintptr, id uint32, val int32) error {
ctrl := &v4l2_control{}
ctrl.id = id
ctrl.value = val
return ioctl.Ioctl(fd, VIDIOC_S_CTRL, uintptr(unsafe.Pointer(ctrl)))
}

func getControls(fd uintptr) map[uint32]string {
query := &v4l2_queryctrl{}
var controls map[uint32]string
func queryControls(fd uintptr) []control {
controls := []control{}
var err error
for query.id = V4L2_CID_BASE; err == nil; query.id++ {
err = ioctl.Ioctl(fd, VIDIOC_QUERYCTRL, uintptr(unsafe.Pointer(query)))
if err == nil {
controls[query.id] = CToGoString(query.name[:])
}
}
err = nil
for query.id = V4L2_CID_PRIVATE_BASE; err == nil; query.id++ {
// Don't use V42L_CID_BASE since it is the same as brightness.
var id uint32
for err == nil {
id |= V4L2_CTRL_FLAG_NEXT_CTRL
query := &v4l2_queryctrl{}
query.id = id
err = ioctl.Ioctl(fd, VIDIOC_QUERYCTRL, uintptr(unsafe.Pointer(query)))
id = query.id
if err == nil {
controls[query.id] = CToGoString(query.name[:])
if (query.flags & V4L2_CTRL_FLAG_DISABLED) != 0 {
continue
}
var c control
switch query._type {
default:
continue
case V4L2_CTRL_TYPE_INTEGER, V4L2_CTRL_TYPE_INTEGER64:
c.c_type = c_int
case V4L2_CTRL_TYPE_BOOLEAN:
c.c_type = c_bool
case V4L2_CTRL_TYPE_MENU:
c.c_type = c_menu
}
c.id = id
c.name = CToGoString(query.name[:])
c.min = query.minimum
c.max = query.maximum
controls = append(controls, c)
}
}
return controls
Expand Down
27 changes: 27 additions & 0 deletions webcam.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ type Webcam struct {
streaming bool
}

type ControlID uint32

type Control struct {
aamcrae marked this conversation as resolved.
Show resolved Hide resolved
Name string
Min int32
Max int32
}

// Open a webcam with a given path
// Checks if device is a v4l2 device and if it is
// capable to stream video
Expand Down Expand Up @@ -126,6 +134,25 @@ func (w *Webcam) SetBufferCount(count uint32) error {
return nil
}

// Get a map of available controls.
func (w *Webcam) GetControls() map[ControlID]Control {
cmap := make(map[ControlID]Control)
for _, c := range queryControls(w.fd) {
cmap[ControlID(c.id)] = Control{c.name, c.min, c.max}
}
return cmap
}

// Get the value of a control.
func (w *Webcam) GetControl(id ControlID) (int32, error) {
return getControl(w.fd, uint32(id))
}

// Set a control.
func (w *Webcam) SetControl(id ControlID, value int32) error {
return setControl(w.fd, uint32(id), value)
}

// Start streaming process
func (w *Webcam) StartStreaming() error {
if w.streaming {
Expand Down