mirror of
https://github.com/gen2brain/cam2ip.git
synced 2026-01-10 00:28:32 +00:00
Add support for YUYV/YUY2 format
This commit is contained in:
@@ -6,9 +6,10 @@ package camera
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/korandiz/v4l"
|
||||
"github.com/korandiz/v4l/fmt/mjpeg"
|
||||
|
||||
im "github.com/gen2brain/cam2ip/image"
|
||||
)
|
||||
@@ -17,12 +18,14 @@ import (
|
||||
type Camera struct {
|
||||
opts Options
|
||||
camera *v4l.Device
|
||||
config v4l.DeviceConfig
|
||||
ycbcr *image.YCbCr
|
||||
}
|
||||
|
||||
// New returns new Camera for given camera index.
|
||||
func New(opts Options) (camera *Camera, err error) {
|
||||
camera = &Camera{}
|
||||
camera.opts = opts
|
||||
func New(opts Options) (c *Camera, err error) {
|
||||
c = &Camera{}
|
||||
c.opts = opts
|
||||
|
||||
devices := v4l.FindDevices()
|
||||
if len(devices) < opts.Index+1 {
|
||||
@@ -31,40 +34,65 @@ func New(opts Options) (camera *Camera, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
camera.camera, err = v4l.Open(devices[opts.Index].Path)
|
||||
c.camera, err = v4l.Open(devices[opts.Index].Path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: %w", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if camera.camera == nil {
|
||||
if c.camera == nil {
|
||||
err = fmt.Errorf("camera: can not open camera %d", opts.Index)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
config, err := camera.camera.GetConfig()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: %w", err)
|
||||
configs, e := c.camera.ListConfigs()
|
||||
if e != nil {
|
||||
err = fmt.Errorf("camera: can not list configs: %w", e)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
config.Format = mjpeg.FourCC
|
||||
config.Width = int(opts.Width)
|
||||
config.Height = int(opts.Height)
|
||||
formats := make([]uint32, 0)
|
||||
for _, config := range configs {
|
||||
formats = append(formats, config.Format)
|
||||
}
|
||||
|
||||
err = camera.camera.SetConfig(config)
|
||||
c.config, err = c.camera.GetConfig()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: %w", err)
|
||||
err = fmt.Errorf("camera: can not get config: %w", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = camera.camera.TurnOn()
|
||||
if slices.Contains(formats, mjpgFourCC) {
|
||||
c.config.Format = mjpgFourCC
|
||||
} else if slices.Contains(formats, yuyvFourCC) {
|
||||
c.config.Format = yuyvFourCC
|
||||
} else {
|
||||
err = fmt.Errorf("camera: unsupported format %d", c.config.Format)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
c.config.Width = int(opts.Width)
|
||||
c.config.Height = int(opts.Height)
|
||||
|
||||
err = c.camera.SetConfig(c.config)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: %w", err)
|
||||
err = fmt.Errorf("camera: format %d: can not set config: %w", c.config.Format, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if c.config.Format == yuyvFourCC {
|
||||
c.ycbcr = image.NewYCbCr(image.Rect(0, 0, int(c.opts.Width), int(c.opts.Height)), image.YCbCrSubsampleRatio422)
|
||||
}
|
||||
|
||||
err = c.camera.TurnOn()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: format %d: can not turn on: %w", c.config.Format, err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -76,16 +104,35 @@ func New(opts Options) (camera *Camera, err error) {
|
||||
func (c *Camera) Read() (img image.Image, err error) {
|
||||
buffer, err := c.camera.Capture()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: can not grab frame: %w", err)
|
||||
err = fmt.Errorf("camera: format %d: can not grab frame: %w", c.config.Format, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
img, err = im.NewDecoder(buffer).Decode()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: %w", err)
|
||||
switch c.config.Format {
|
||||
case yuy2FourCC, yuyvFourCC:
|
||||
data, e := io.ReadAll(buffer)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("camera: format %d: can not read buffer: %w", c.config.Format, e)
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
e = yuy2ToYCbCr422(data, c.ycbcr)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("camera: format %d: can not retrieve frame: %w", c.config.Format, e)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
img = c.ycbcr
|
||||
case mjpgFourCC:
|
||||
img, err = im.NewDecoder(buffer).Decode()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("camera: format %d: can not decode frame: %w", c.config.Format, err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if c.opts.Rotate != 0 {
|
||||
@@ -97,7 +144,7 @@ func (c *Camera) Read() (img image.Image, err error) {
|
||||
}
|
||||
|
||||
if c.opts.Timestamp {
|
||||
img, err = im.Timestamp(img, "")
|
||||
img, err = im.Timestamp(img, c.opts.TimeFormat)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -106,7 +153,7 @@ func (c *Camera) Read() (img image.Image, err error) {
|
||||
// Close closes camera.
|
||||
func (c *Camera) Close() (err error) {
|
||||
if c.camera == nil {
|
||||
err = fmt.Errorf("camera: camera is not opened")
|
||||
err = fmt.Errorf("camera: close: camera is not opened")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user