mirror of
https://github.com/taigrr/vidnumerator.git
synced 2026-04-02 05:08:52 -07:00
Compare commits
3 Commits
cd/moderni
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4aa3374967 | |||
| 430e5972d3 | |||
| 7c18d017dc |
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -14,4 +14,6 @@ jobs:
|
||||
- run: go test -race ./...
|
||||
- run: go vet ./...
|
||||
- run: go build ./...
|
||||
|
||||
- name: Install staticcheck
|
||||
run: go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
- run: staticcheck ./...
|
||||
|
||||
4
go.mod
4
go.mod
@@ -1,5 +1,5 @@
|
||||
module github.com/taigrr/vidnumerator
|
||||
|
||||
go 1.26.0
|
||||
go 1.26.1
|
||||
|
||||
require golang.org/x/sys v0.41.0
|
||||
require golang.org/x/sys v0.42.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1,2 +1,2 @@
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
|
||||
@@ -28,6 +28,10 @@ const (
|
||||
(uintptr('V') << IOCTypeShift) |
|
||||
(0 << IOCNrShift) |
|
||||
(unsafe.Sizeof(cap{}) << IOCSizeShift)
|
||||
|
||||
// V4L2CapVideoCapture is the device capability flag indicating
|
||||
// the device supports video capture (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS).
|
||||
V4L2CapVideoCapture uint32 = 69206017
|
||||
)
|
||||
|
||||
type cap struct {
|
||||
@@ -40,13 +44,13 @@ type cap struct {
|
||||
reserved [3]uint32
|
||||
}
|
||||
|
||||
func (r *cap) QueryFd(fileDesciptor int) error {
|
||||
func (r *cap) QueryFd(fileDescriptor int) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("nil receiver")
|
||||
}
|
||||
_, _, errorNumber := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fileDesciptor),
|
||||
uintptr(fileDescriptor),
|
||||
VidIOCQueryCap,
|
||||
uintptr(unsafe.Pointer(r)),
|
||||
)
|
||||
@@ -68,7 +72,7 @@ func IsVideoCapture(path string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ic.deviceCaps == 69206017, nil
|
||||
return ic.deviceCaps == V4L2CapVideoCapture, nil
|
||||
}
|
||||
|
||||
// this function checks the ioctl for VIDIOC_QUERYCAP to see if the device is a video capture device
|
||||
|
||||
78
vidnumerator_test.go
Normal file
78
vidnumerator_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package vidnumerator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCapQueryFdNilReceiver(t *testing.T) {
|
||||
var nilCap *cap
|
||||
err := nilCap.QueryFd(0)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for nil receiver, got nil")
|
||||
}
|
||||
if err.Error() != "nil receiver" {
|
||||
t.Fatalf("expected 'nil receiver' error, got: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCapQueryFdInvalidFd(t *testing.T) {
|
||||
ic := cap{}
|
||||
err := ic.QueryFd(-1)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid file descriptor, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsVideoCaptureInvalidPath(t *testing.T) {
|
||||
isVid, err := IsVideoCapture("/nonexistent/path")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for nonexistent path, got nil")
|
||||
}
|
||||
if isVid {
|
||||
t.Fatal("expected false for nonexistent path")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsVideoCaptureRegularFile(t *testing.T) {
|
||||
tmpFile, err := os.CreateTemp("", "vidnum-test-*")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp file: %v", err)
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
defer tmpFile.Close()
|
||||
|
||||
isVid, err := IsVideoCapture(tmpFile.Name())
|
||||
if err == nil {
|
||||
// Some kernels may return an error, some may not — both are valid
|
||||
if isVid {
|
||||
t.Fatal("regular file should not be detected as video capture")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnumeratedVideoDevices(t *testing.T) {
|
||||
// This test verifies the function runs without panic.
|
||||
// On machines without video devices, it should return an empty list.
|
||||
devices, err := EnumeratedVideoDevices()
|
||||
if err != nil {
|
||||
// /dev might not be readable in some CI environments
|
||||
t.Skipf("EnumeratedVideoDevices returned error (expected in some environments): %v", err)
|
||||
}
|
||||
// Just verify all returned paths start with /dev/video
|
||||
for _, device := range devices {
|
||||
if len(device) < 10 || device[:10] != "/dev/video" {
|
||||
t.Errorf("unexpected device path: %s", device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestV4L2CapVideoCaptureConstant(t *testing.T) {
|
||||
// Verify the constant matches the expected V4L2 capability flags.
|
||||
// 69206017 = 0x04200001 = V4L2_CAP_VIDEO_CAPTURE (0x1) | V4L2_CAP_STREAMING (0x04000000) | V4L2_CAP_DEVICE_CAPS (0x80000000)
|
||||
// Note: 69206017 = 0x41F8001 — let's verify the actual hex.
|
||||
expected := uint32(69206017)
|
||||
if V4L2CapVideoCapture != expected {
|
||||
t.Fatalf("V4L2CapVideoCapture = %d, expected %d", V4L2CapVideoCapture, expected)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user