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

[RSDK-9754] Remove webcam discovery logic #4720

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
85 changes: 0 additions & 85 deletions components/camera/videosource/webcam.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"image"
"path/filepath"
"strings"
"sync"
"time"

Expand All @@ -20,7 +19,6 @@ import (
"github.com/pion/mediadevices/pkg/prop"
"github.com/pkg/errors"
"go.uber.org/multierr"
pb "go.viam.com/api/component/camera/v1"
goutils "go.viam.com/utils"

"go.viam.com/rdk/components/camera"
Expand All @@ -39,101 +37,18 @@ var intrinsics []byte

var data map[string]transform.PinholeCameraIntrinsics

// getVideoDrivers is a helper callback passed to the registered Discover func to get all video drivers.
func getVideoDrivers() []driver.Driver {
return driver.GetManager().Query(driver.FilterVideoRecorder())
}

func init() {
resource.RegisterComponent(
camera.API,
ModelWebcam,
resource.Registration[camera.Camera, *WebcamConfig]{
Constructor: NewWebcam,
Discover: func(ctx context.Context, logger logging.Logger, extra map[string]interface{}) (interface{}, error) {
return Discover(ctx, getVideoDrivers, logger)
},
})
if err := json.Unmarshal(intrinsics, &data); err != nil {
logging.Global().Errorw("cannot parse intrinsics json", "error", err)
}
}

// getProperties is a helper func for webcam discovery that returns the Media properties of a specific driver.
// It is NOT related to the GetProperties camera proto API.
func getProperties(d driver.Driver) (_ []prop.Media, err error) {
// Need to open driver to get properties
if d.Status() == driver.StateClosed {
errOpen := d.Open()
if errOpen != nil {
return nil, errOpen
}
defer func() {
if errClose := d.Close(); errClose != nil {
err = errClose
}
}()
}
return d.Properties(), err
}

// Discover webcam attributes.
func Discover(ctx context.Context, getDrivers func() []driver.Driver, logger logging.Logger) (*pb.Webcams, error) {
mediadevicescamera.Initialize()
var webcams []*pb.Webcam
drivers := getDrivers()
for _, d := range drivers {
driverInfo := d.Info()

props, err := getProperties(d)
if len(props) == 0 {
logger.CDebugw(ctx, "no properties detected for driver, skipping discovery...", "driver", driverInfo.Label)
continue
} else if err != nil {
logger.CDebugw(ctx, "cannot access driver properties, skipping discovery...", "driver", driverInfo.Label, "error", err)
continue
}

if d.Status() == driver.StateRunning {
logger.CDebugw(ctx, "driver is in use, skipping discovery...", "driver", driverInfo.Label)
continue
}

labelParts := strings.Split(driverInfo.Label, mediadevicescamera.LabelSeparator)
label := labelParts[0]

name, id := func() (string, string) {
nameParts := strings.Split(driverInfo.Name, mediadevicescamera.LabelSeparator)
if len(nameParts) > 1 {
return nameParts[0], nameParts[1]
}
// fallback to the label if the name does not have an any additional parts to use.
return nameParts[0], label
}()

wc := &pb.Webcam{
Name: name,
Id: id,
Label: label,
Status: string(d.Status()),
Properties: make([]*pb.Property, 0, len(d.Properties())),
}

for _, prop := range props {
pbProp := &pb.Property{
WidthPx: int32(prop.Video.Width),
HeightPx: int32(prop.Video.Height),
FrameRate: prop.Video.FrameRate,
FrameFormat: string(prop.Video.FrameFormat),
}
wc.Properties = append(wc.Properties, pbProp)
}
webcams = append(webcams, wc)
}

return &pb.Webcams{Webcams: webcams}, nil
}

// WebcamConfig is the native config attribute struct for webcams.
type WebcamConfig struct {
CameraParameters *transform.PinholeCameraIntrinsics `json:"intrinsic_parameters,omitempty"`
Expand Down
41 changes: 0 additions & 41 deletions components/camera/videosource/webcam_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,47 +27,6 @@ func findWebcam(t *testing.T, webcams []*pb.Webcam, name string) *pb.Webcam {
return nil
}

func TestWebcamDiscovery(t *testing.T) {
logger := logging.NewTestLogger(t)

reg, ok := resource.LookupRegistration(camera.API, videosource.ModelWebcam)
test.That(t, ok, test.ShouldBeTrue)

ctx := context.Background()
discoveries, err := reg.Discover(ctx, logger)
test.That(t, err, test.ShouldBeNil)

webcams, ok := discoveries.(*pb.Webcams)
test.That(t, ok, test.ShouldBeTrue)
webcamsLen := len(webcams.Webcams)

// Video capture and overlay minor numbers range == [0, 63]
// Start from the end of the range to avoid conflicts with other devices
// Source: https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/diff-v4l.html
config, err := vcamera.Builder(logger).
NewCamera(62, "Lo Res Webcam", vcamera.Resolution{Width: 640, Height: 480}).
NewCamera(63, "Hi Res Webcam", vcamera.Resolution{Width: 1280, Height: 720}).
Stream()

test.That(t, err, test.ShouldBeNil)
defer config.Shutdown()

discoveries, err = reg.Discover(ctx, logger)
test.That(t, err, test.ShouldBeNil)

webcams, ok = discoveries.(*pb.Webcams)
test.That(t, ok, test.ShouldBeTrue)
test.That(t, len(webcams.Webcams), test.ShouldEqual, webcamsLen+2)

webcam := findWebcam(t, webcams.Webcams, "Hi Res Webcam")
test.That(t, webcam.Properties[0].WidthPx, test.ShouldEqual, 1280)
test.That(t, webcam.Properties[0].HeightPx, test.ShouldEqual, 720)

webcam = findWebcam(t, webcams.Webcams, "Lo Res Webcam")
test.That(t, webcam.Properties[0].WidthPx, test.ShouldEqual, 640)
test.That(t, webcam.Properties[0].HeightPx, test.ShouldEqual, 480)
}

func newWebcamConfig(name, path string) resource.Config {
conf := resource.NewEmptyConfig(
resource.NewName(camera.API, name),
Expand Down
47 changes: 0 additions & 47 deletions components/camera/videosource/webcam_test.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,13 @@
package videosource_test

import (
"context"
"testing"

"github.com/pion/mediadevices/pkg/driver"
"github.com/pion/mediadevices/pkg/prop"
"go.viam.com/test"

"go.viam.com/rdk/components/camera/videosource"
"go.viam.com/rdk/logging"
)

// fakeDriver is a driver has a label and media properties.
type fakeDriver struct {
label string
props []prop.Media
}

func (d *fakeDriver) Open() error { return nil }
func (d *fakeDriver) Properties() []prop.Media { return d.props }
func (d *fakeDriver) ID() string { return d.label }
func (d *fakeDriver) Info() driver.Info { return driver.Info{Label: d.label} }
func (d *fakeDriver) Status() driver.State { return "some state" }
func (d *fakeDriver) Close() error { return nil }

func newFakeDriver(label string, props []prop.Media) driver.Driver {
return &fakeDriver{label: label, props: props}
}

func testGetDrivers() []driver.Driver {
props := prop.Media{
Video: prop.Video{Width: 320, Height: 240, FrameFormat: "some format", FrameRate: 30.0},
}
withProps := newFakeDriver("some label", []prop.Media{props})
withoutProps := newFakeDriver("another label", []prop.Media{})
return []driver.Driver{withProps, withoutProps}
}

func TestDiscoveryWebcam(t *testing.T) {
logger := logging.NewTestLogger(t)
resp, err := videosource.Discover(context.Background(), testGetDrivers, logger)

test.That(t, err, test.ShouldBeNil)
test.That(t, resp.Webcams, test.ShouldHaveLength, 1)
test.That(t, resp.Webcams[0].Label, test.ShouldResemble, "some label")
test.That(t, resp.Webcams[0].Status, test.ShouldResemble, "some state")

respProps := resp.Webcams[0].Properties
test.That(t, respProps, test.ShouldHaveLength, 1)
test.That(t, respProps[0].WidthPx, test.ShouldResemble, int32(320))
test.That(t, respProps[0].HeightPx, test.ShouldResemble, int32(240))
test.That(t, respProps[0].FrameFormat, test.ShouldResemble, "some format")
test.That(t, respProps[0].FrameRate, test.ShouldResemble, float32(30))
}

func TestWebcamValidation(t *testing.T) {
webCfg := &videosource.WebcamConfig{
Width: 1280,
Expand Down
Loading