Skip to content
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
46 changes: 46 additions & 0 deletions v4l2.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package webcam
import (
"bytes"
"encoding/binary"
"fmt"
"unsafe"

"github.com/blackjack/webcam/ioctl"
Expand Down Expand Up @@ -75,6 +76,8 @@ 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_PARM = ioctl.IoRW(uintptr('V'), 21, unsafe.Sizeof(v4l2_streamparm{}))
VIDIOC_S_PARM = ioctl.IoRW(uintptr('V'), 22, unsafe.Sizeof(v4l2_streamparm{}))
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{}))
Expand Down Expand Up @@ -203,6 +206,26 @@ type v4l2_control struct {
value int32
}

type v4l2_fract struct {
numerator uint32
denominator uint32
}

type v4l2_streamparm_union struct {
capability uint32
output_mode uint32
time_per_frame v4l2_fract
extended_mode uint32
buffers uint32
reserved [4]uint32
data [200 - (10 * unsafe.Sizeof(uint32(0)))]byte
}

type v4l2_streamparm struct {
_type uint32
union v4l2_streamparm_union
}

func checkCapabilities(fd uintptr) (supportsVideoCapture bool, supportsVideoStreaming bool, err error) {

caps := &v4l2_capability{}
Expand Down Expand Up @@ -466,6 +489,29 @@ func setControl(fd uintptr, id uint32, val int32) error {
return ioctl.Ioctl(fd, VIDIOC_S_CTRL, uintptr(unsafe.Pointer(ctrl)))
}

func getFramerate(fd uintptr) (float32, error) {
param := &v4l2_streamparm{}
param._type = V4L2_BUF_TYPE_VIDEO_CAPTURE

err := ioctl.Ioctl(fd, VIDIOC_G_PARM, uintptr(unsafe.Pointer(param)))
if err != nil {
return 0, err
}
tf := param.union.time_per_frame
if tf.denominator == 0 || tf.numerator == 0 {
return 0, fmt.Errorf("Invalid framerate (%d/%d)", tf.denominator, tf.numerator)
}
return float32(tf.denominator) / float32(tf.numerator), nil
}

func setFramerate(fd uintptr, num, denom uint32) error {
param := &v4l2_streamparm{}
param._type = V4L2_BUF_TYPE_VIDEO_CAPTURE
param.union.time_per_frame.numerator = num
param.union.time_per_frame.denominator = denom
return ioctl.Ioctl(fd, VIDIOC_S_PARM, uintptr(unsafe.Pointer(param)))
}

func queryControls(fd uintptr) []control {
controls := []control{}
var err error
Expand Down
13 changes: 12 additions & 1 deletion webcam.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ package webcam

import (
"errors"
"golang.org/x/sys/unix"
"reflect"
"unsafe"

"golang.org/x/sys/unix"
)

// Webcam object
Expand Down Expand Up @@ -153,6 +154,16 @@ func (w *Webcam) SetControl(id ControlID, value int32) error {
return setControl(w.fd, uint32(id), value)
}

// Get the framerate.
func (w *Webcam) GetFramerate() (float32, error) {
return getFramerate(w.fd)
}

// Set FPS
func (w *Webcam) SetFramerate(fps float32) error {
return setFramerate(w.fd, 1000, uint32(1000*(fps)))
}

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