From 982ce077c562ee983e74dfb1262e82f7d8a500d0 Mon Sep 17 00:00:00 2001 From: seanavery Date: Tue, 27 Aug 2024 15:44:06 -0400 Subject: [PATCH 1/7] Change triplet --- cam/cam.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index 0ebcd8e..aa13988 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -20,7 +20,7 @@ import ( // Model is the model for the filtered video camera component. // TODO(seanp): Personal module for now, should be movied to viam module in prod. -var Model = resource.ModelNamespace("seanavery").WithFamily("camera").WithModel("filtered-video") +var Model = resource.ModelNamespace("seanavery").WithFamily("video").WithModel("storage") const ( defaultClipLength = 30 // seconds @@ -77,9 +77,6 @@ type Config struct { Storage storage `json:"storage"` Video video `json:"video"` - Classifications map[string]float64 `json:"classifications,omitempty"` - Objects map[string]float64 `json:"objects,omitempty"` - // TODO(seanp): Remove once camera properties are returned from camera component. Properties cameraProperties `json:"cam_props"` } From dd098b3a2f281b60a892481a8ef795a93d0be009 Mon Sep 17 00:00:00 2001 From: seanavery Date: Tue, 27 Aug 2024 16:05:00 -0400 Subject: [PATCH 2/7] Update storage config --- cam/cam.go | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index aa13988..22fe60e 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -4,7 +4,6 @@ package filteredvideo import ( "context" "errors" - "sync" "time" "go.viam.com/rdk/components/camera" @@ -23,14 +22,14 @@ import ( var Model = resource.ModelNamespace("seanavery").WithFamily("video").WithModel("storage") const ( - defaultClipLength = 30 // seconds - defaultStorageSize = 10 // GB - defaultVideoCodec = "h264" - defaultVideoBitrate = 1000000 - defaultVideoPreset = "medium" - defaultVideoFormat = "mp4" - defaultLogLevel = "error" - uploadPath = "/.viam/video-upload/" + defaultSegmentSeconds = 30 // seconds + defaultStorageSize = 10 // GB + defaultVideoCodec = "h264" + defaultVideoBitrate = 1000000 + defaultVideoPreset = "medium" + defaultVideoFormat = "mp4" + defaultLogLevel = "error" + uploadPath = "/.viam/video-upload/" ) type filteredVideo struct { @@ -49,13 +48,11 @@ type filteredVideo struct { enc *encoder seg *segmenter - - mu sync.Mutex } type storage struct { - ClipLength int `json:"clip_length"` - Size int `json:"size"` + SegmentSeconds int `json:"segment_seconds"` + SizeGB int `json:"size_gb"` } type video struct { @@ -150,13 +147,13 @@ func newFilteredVideo( return nil, err } - if newConf.Storage.ClipLength == 0 { - newConf.Storage.ClipLength = defaultClipLength + if newConf.Storage.SegmentSeconds == 0 { + newConf.Storage.SegmentSeconds = defaultSegmentSeconds } - if newConf.Storage.Size == 0 { - newConf.Storage.Size = defaultStorageSize + if newConf.Storage.SizeGB == 0 { + newConf.Storage.SizeGB = defaultStorageSize } - fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.Size, newConf.Storage.ClipLength) + fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds) if err != nil { return nil, err } From d3335f817e74ab60e3d77020eb24e8270a100df1 Mon Sep 17 00:00:00 2001 From: seanavery Date: Wed, 28 Aug 2024 13:21:11 -0400 Subject: [PATCH 3/7] Add optional storage_path --- cam/cam.go | 22 ++++++++++++++++------ cam/segmenter.go | 9 ++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index 22fe60e..1f819d5 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -29,7 +29,8 @@ const ( defaultVideoPreset = "medium" defaultVideoFormat = "mp4" defaultLogLevel = "error" - uploadPath = "/.viam/video-upload/" + defaultUploadPath = "/.viam/video-upload/" + defaultStoragePath = "/.viam/video-storage/" ) type filteredVideo struct { @@ -51,8 +52,10 @@ type filteredVideo struct { } type storage struct { - SegmentSeconds int `json:"segment_seconds"` - SizeGB int `json:"size_gb"` + SegmentSeconds int `json:"segment_seconds"` + SizeGB int `json:"size_gb"` + UploadPath string `json:"upload_path"` + StoragePath string `json:"storage_path"` } type video struct { @@ -117,7 +120,8 @@ func newFilteredVideo( } // TODO(seanp): make this configurable - logLevel := lookupLogID(defaultLogLevel) + // logLevel := lookupLogID(defaultLogLevel) + logLevel := lookupLogID("debug") ffmppegLogLevel(logLevel) // TODO(seanp): Forcing h264 for now until h265 is supported. @@ -153,12 +157,18 @@ func newFilteredVideo( if newConf.Storage.SizeGB == 0 { newConf.Storage.SizeGB = defaultStorageSize } - fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds) + if newConf.Storage.UploadPath == "" { + newConf.Storage.UploadPath = getHomeDir() + defaultUploadPath + } + if newConf.Storage.StoragePath == "" { + newConf.Storage.StoragePath = getHomeDir() + defaultStoragePath + } + fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds, newConf.Storage.StoragePath) if err != nil { return nil, err } - fv.uploadPath = getHomeDir() + uploadPath + fv.uploadPath = newConf.Storage.UploadPath err = createDir(fv.uploadPath) if err != nil { return nil, err diff --git a/cam/segmenter.go b/cam/segmenter.go index 1dcbf73..669245f 100644 --- a/cam/segmenter.go +++ b/cam/segmenter.go @@ -20,8 +20,7 @@ import ( ) const ( - outputDirectory = "/.viam/video-storage/" - outputPattern = outputDirectory + "%Y-%m-%d_%H-%M-%S.mp4" + outputPattern = "%Y-%m-%d_%H-%M-%S.mp4" ) type segmenter struct { @@ -39,6 +38,7 @@ func newSegmenter( enc *encoder, storageSize int, clipLength int, + storagePath string, ) (*segmenter, error) { s := &segmenter{ logger: logger, @@ -47,13 +47,12 @@ func newSegmenter( // TODO(seanp): MB for testing, should be GB in prod. s.maxStorageSize = int64(storageSize) * 1024 * 1024 - homeDir := getHomeDir() - s.storagePath = homeDir + outputDirectory + s.storagePath = storagePath err := createDir(s.storagePath) if err != nil { return nil, err } - outputPatternCStr := C.CString(homeDir + outputPattern) + outputPatternCStr := C.CString(storagePath + "/" + outputPattern) defer C.free(unsafe.Pointer(outputPatternCStr)) // Allocate output context for segmenter. The "segment" format is a special format From 3f4c883af2ce899c897ee8c0dc897c254d1b7fe6 Mon Sep 17 00:00:00 2001 From: seanavery Date: Wed, 28 Aug 2024 13:50:06 -0400 Subject: [PATCH 4/7] Add name to default storage and upload path --- cam/cam.go | 9 +++++---- cam/utils.go | 11 ++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index 1f819d5..76111d7 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -4,6 +4,7 @@ package filteredvideo import ( "context" "errors" + "path/filepath" "time" "go.viam.com/rdk/components/camera" @@ -29,8 +30,8 @@ const ( defaultVideoPreset = "medium" defaultVideoFormat = "mp4" defaultLogLevel = "error" - defaultUploadPath = "/.viam/video-upload/" - defaultStoragePath = "/.viam/video-storage/" + defaultUploadPath = ".viam/video-upload" + defaultStoragePath = ".viam/video-storage" ) type filteredVideo struct { @@ -158,10 +159,10 @@ func newFilteredVideo( newConf.Storage.SizeGB = defaultStorageSize } if newConf.Storage.UploadPath == "" { - newConf.Storage.UploadPath = getHomeDir() + defaultUploadPath + newConf.Storage.UploadPath = filepath.Join(getHomeDir(), defaultUploadPath, fv.name.Name) } if newConf.Storage.StoragePath == "" { - newConf.Storage.StoragePath = getHomeDir() + defaultStoragePath + newConf.Storage.StoragePath = filepath.Join(getHomeDir(), defaultStoragePath, fv.name.Name) } fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds, newConf.Storage.StoragePath) if err != nil { diff --git a/cam/utils.go b/cam/utils.go index 1c49033..a0b4fab 100644 --- a/cam/utils.go +++ b/cam/utils.go @@ -71,7 +71,7 @@ func getHomeDir() string { // createDir creates a directory at the provided path if it does not exist. func createDir(path string) error { if _, err := os.Stat(path); os.IsNotExist(err) { - err := os.Mkdir(path, 0755) + err := os.MkdirAll(path, 0755) if err != nil { return err } @@ -167,3 +167,12 @@ func copyFile(src, dst string) error { } return nil } + +// fetchCompName +func fetchCompName(resourceName string) string { + parts := strings.Split(resourceName, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "unkown" +} From 558ea9443a939f253796e39b0b0816156ac702f6 Mon Sep 17 00:00:00 2001 From: seanavery Date: Wed, 28 Aug 2024 13:57:47 -0400 Subject: [PATCH 5/7] Rename to video store --- cam/cam.go | 62 ++++++++++++++++++++++++------------------------ cam/encoder.go | 2 +- cam/segmenter.go | 2 +- cam/utils.go | 2 +- go.mod | 2 +- main.go | 4 ++-- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index 76111d7..425f4b4 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -1,5 +1,5 @@ -// Package filteredvideo contains the implementation of the filtered video camera component. -package filteredvideo +// Package videostore contains the implementation of the video storage camera component. +package videostore import ( "context" @@ -18,7 +18,7 @@ import ( "go.viam.com/utils" ) -// Model is the model for the filtered video camera component. +// Model is the model for the video storage camera component. // TODO(seanp): Personal module for now, should be movied to viam module in prod. var Model = resource.ModelNamespace("seanavery").WithFamily("video").WithModel("storage") @@ -34,7 +34,7 @@ const ( defaultStoragePath = ".viam/video-storage" ) -type filteredVideo struct { +type videostore struct { resource.AlwaysRebuild resource.TriviallyCloseable @@ -72,7 +72,7 @@ type cameraProperties struct { Framerate int `json:"framerate"` } -// Config is the configuration for the filtered video camera component. +// Config is the configuration for the video storage camera component. type Config struct { Camera string `json:"camera"` Storage storage `json:"storage"` @@ -87,11 +87,11 @@ func init() { camera.API, Model, resource.Registration[camera.Camera, *Config]{ - Constructor: newFilteredVideo, + Constructor: newvideostore, }) } -func newFilteredVideo( +func newvideostore( ctx context.Context, deps resource.Dependencies, conf resource.Config, @@ -102,20 +102,20 @@ func newFilteredVideo( return nil, err } - fv := &filteredVideo{ + vs := &videostore{ name: conf.ResourceName(), conf: newConf, logger: logger, } // Source camera that provides the frames to be processed. - fv.cam, err = camera.FromDependencies(deps, newConf.Camera) + vs.cam, err = camera.FromDependencies(deps, newConf.Camera) if err != nil { return nil, err } var errHandlers []gostream.ErrorHandler - fv.stream, err = fv.cam.Stream(ctx, errHandlers...) + vs.stream, err = vs.cam.Stream(ctx, errHandlers...) if err != nil { return nil, err } @@ -139,7 +139,7 @@ func newFilteredVideo( newConf.Video.Format = defaultVideoFormat } - fv.enc, err = newEncoder( + vs.enc, err = newEncoder( logger, newConf.Video.Codec, newConf.Video.Bitrate, @@ -159,28 +159,28 @@ func newFilteredVideo( newConf.Storage.SizeGB = defaultStorageSize } if newConf.Storage.UploadPath == "" { - newConf.Storage.UploadPath = filepath.Join(getHomeDir(), defaultUploadPath, fv.name.Name) + newConf.Storage.UploadPath = filepath.Join(getHomeDir(), defaultUploadPath, vs.name.Name) } if newConf.Storage.StoragePath == "" { - newConf.Storage.StoragePath = filepath.Join(getHomeDir(), defaultStoragePath, fv.name.Name) + newConf.Storage.StoragePath = filepath.Join(getHomeDir(), defaultStoragePath, vs.name.Name) } - fv.seg, err = newSegmenter(logger, fv.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds, newConf.Storage.StoragePath) + vs.seg, err = newSegmenter(logger, vs.enc, newConf.Storage.SizeGB, newConf.Storage.SegmentSeconds, newConf.Storage.StoragePath) if err != nil { return nil, err } - fv.uploadPath = newConf.Storage.UploadPath - err = createDir(fv.uploadPath) + vs.uploadPath = newConf.Storage.UploadPath + err = createDir(vs.uploadPath) if err != nil { return nil, err } - fv.workers = rdkutils.NewStoppableWorkers(fv.processFrames, fv.deleter) + vs.workers = rdkutils.NewStoppableWorkers(vs.processFrames, vs.deleter) - return fv, nil + return vs, nil } -// Validate validates the configuration for the filtered video camera component. +// Validate validates the configuration for the video storage camera component. func (cfg *Config) Validate(path string) ([]string, error) { if cfg.Camera == "" { return nil, utils.NewConfigValidationFieldRequiredError(path, "camera") @@ -194,27 +194,27 @@ func (cfg *Config) Validate(path string) ([]string, error) { return []string{cfg.Camera}, nil } -func (fv *filteredVideo) Name() resource.Name { - return fv.name +func (vs *videostore) Name() resource.Name { + return vs.name } -func (fv *filteredVideo) DoCommand(_ context.Context, _ map[string]interface{}) (map[string]interface{}, error) { +func (vs *videostore) DoCommand(_ context.Context, _ map[string]interface{}) (map[string]interface{}, error) { return nil, resource.ErrDoUnimplemented } -func (fv *filteredVideo) Images(_ context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) { +func (fv *videostore) Images(_ context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) { return nil, resource.ResponseMetadata{}, errors.New("not implemented") } -func (fv *filteredVideo) NextPointCloud(_ context.Context) (pointcloud.PointCloud, error) { +func (fv *videostore) NextPointCloud(_ context.Context) (pointcloud.PointCloud, error) { return nil, errors.New("not implemented") } -func (fv *filteredVideo) Projector(ctx context.Context) (transform.Projector, error) { +func (fv *videostore) Projector(ctx context.Context) (transform.Projector, error) { return fv.cam.Projector(ctx) } -func (fv *filteredVideo) Properties(ctx context.Context) (camera.Properties, error) { +func (fv *videostore) Properties(ctx context.Context) (camera.Properties, error) { p, err := fv.cam.Properties(ctx) if err == nil { p.SupportsPCD = false @@ -222,7 +222,7 @@ func (fv *filteredVideo) Properties(ctx context.Context) (camera.Properties, err return p, err } -func (fv *filteredVideo) Stream(_ context.Context, _ ...gostream.ErrorHandler) (gostream.VideoStream, error) { +func (fv *videostore) Stream(_ context.Context, _ ...gostream.ErrorHandler) (gostream.VideoStream, error) { return nil, errors.New("not implemented") } @@ -231,7 +231,7 @@ func (fv *filteredVideo) Stream(_ context.Context, _ ...gostream.ErrorHandler) ( // meant for long term storage of video clips that are not necessarily triggered by // detections. // TODO(seanp): Should this be throttled to a certain FPS? -func (fv *filteredVideo) processFrames(ctx context.Context) { +func (fv *videostore) processFrames(ctx context.Context) { for { // TODO(seanp): How to gracefully exit this loop? select { @@ -265,7 +265,7 @@ func (fv *filteredVideo) processFrames(ctx context.Context) { // deleter is a go routine that cleans up old clips if storage is full. It runs every // minute and deletes the oldest clip until the storage size is below the max. -func (fv *filteredVideo) deleter(ctx context.Context) { +func (fv *videostore) deleter(ctx context.Context) { // TODO(seanp): Using seconds for now, but should be minutes in prod. ticker := time.NewTicker(60 * time.Second) defer ticker.Stop() @@ -284,9 +284,9 @@ func (fv *filteredVideo) deleter(ctx context.Context) { } } -// Close closes the filtered video camera component. +// Close closes the video storage camera component. // It closes the stream, workers, encoder, segmenter, and watcher. -func (fv *filteredVideo) Close(ctx context.Context) error { +func (fv *videostore) Close(ctx context.Context) error { err := fv.stream.Close(ctx) if err != nil { return err diff --git a/cam/encoder.go b/cam/encoder.go index 9261d3f..26a564a 100644 --- a/cam/encoder.go +++ b/cam/encoder.go @@ -1,4 +1,4 @@ -package filteredvideo +package videostore /* #include diff --git a/cam/segmenter.go b/cam/segmenter.go index 669245f..5f7481b 100644 --- a/cam/segmenter.go +++ b/cam/segmenter.go @@ -1,4 +1,4 @@ -package filteredvideo +package videostore /* #include diff --git a/cam/utils.go b/cam/utils.go index a0b4fab..9cf31ae 100644 --- a/cam/utils.go +++ b/cam/utils.go @@ -1,4 +1,4 @@ -package filteredvideo +package videostore /* #include diff --git a/go.mod b/go.mod index 42f6297..531405b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/seanavery/filteredvideo +module github.com/seanavery/videostore go 1.22.4 diff --git a/main.go b/main.go index 49f1adf..79da5bf 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ package main import ( "context" - filteredvideo "github.com/seanavery/filteredvideo/cam" + videostore "github.com/seanavery/videostore/cam" "go.viam.com/rdk/components/camera" "go.viam.com/rdk/logging" "go.viam.com/rdk/module" @@ -21,7 +21,7 @@ func mainWithArgs(ctx context.Context, _ []string, logger logging.Logger) error return err } - err = module.AddModelFromRegistry(ctx, camera.API, filteredvideo.Model) + err = module.AddModelFromRegistry(ctx, camera.API, videostore.Model) if err != nil { return err } From 71194eeb5a70ae2c5aebe33264467662ee00a48f Mon Sep 17 00:00:00 2001 From: seanavery Date: Wed, 28 Aug 2024 14:02:19 -0400 Subject: [PATCH 6/7] Fix make naming --- .gitignore | 2 +- Makefile | 4 ++-- README.md | 8 ++++---- main.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index f085cb6..2a4316e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*filtered-video +*video-store FFmpeg *.mp4 .env diff --git a/Makefile b/Makefile index c327ec4..32959f9 100644 --- a/Makefile +++ b/Makefile @@ -37,9 +37,9 @@ export PKG_CONFIG_PATH=$(FFMPEG_BUILD)/lib/pkgconfig .PHONY: lint tool-install -$(BIN_OUTPUT_PATH)/filtered-video: *.go cam/*.go $(FFMPEG_BUILD) +$(BIN_OUTPUT_PATH)/video-store: *.go cam/*.go $(FFMPEG_BUILD) go mod tidy - CGO_LDFLAGS=$(CGO_LDFLAGS) CGO_CFLAGS=$(CGO_CFLAGS) go build -o $(BIN_OUTPUT_PATH)/filtered-video main.go + CGO_LDFLAGS=$(CGO_LDFLAGS) CGO_CFLAGS=$(CGO_CFLAGS) go build -o $(BIN_OUTPUT_PATH)/video-store main.go $(FFMPEG_VERSION_PLATFORM): git clone https://github.com/FFmpeg/FFmpeg.git --depth 1 --branch $(FFMPEG_TAG) $(FFMPEG_VERSION_PLATFORM) diff --git a/README.md b/README.md index 242a294..e7c2a87 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Filtered Video -The `filtered-video` module brings security camera functionality to your smart machine! The module consumes a source [Camera](https://docs.viam.com/components/camera/) and a [Vision Service](https://docs.viam.com/services/vision/), saves the camera output as video files to disk, and filters which video clips are uploaded to the cloud based on triggers from the vision service. +# Video Storage +The `video-store` module brings security camera functionality to your smart machine! The module consumes a source [Camera](https://docs.viam.com/components/camera/) and a [Vision Service](https://docs.viam.com/services/vision/), saves the camera output as video files to disk, and filters which video clips are uploaded to the cloud based on triggers from the vision service. > **Note:** This component is a work in progress and is not yet fully implemented. -## Configure your `filtered-video` component +## Configure your `video-store` component Fill in the attributes as applicable to the component, according to the example below. @@ -12,7 +12,7 @@ Fill in the attributes as applicable to the component, according to the example "name": "fv-cam", "namespace": "rdk", "type": "camera", - "model": "viam:camera:filtered-video", + "model": "viam:camera:video-store", "attributes": { "camera": "webcam-1", // name of the camera to use "vision": "vision-service-1", // name of the vision service dependency diff --git a/main.go b/main.go index 79da5bf..ea7d364 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( ) func main() { - utils.ContextualMain(mainWithArgs, logging.NewLogger("filtered-video-module")) + utils.ContextualMain(mainWithArgs, logging.NewLogger("video-store-module")) } func mainWithArgs(ctx context.Context, _ []string, logger logging.Logger) error { From d4010d2fc3c71cc291d3c1443245fe1b381b26e7 Mon Sep 17 00:00:00 2001 From: seanavery Date: Wed, 28 Aug 2024 14:10:15 -0400 Subject: [PATCH 7/7] Naming fix --- cam/cam.go | 46 +++++++++++++++++++++++----------------------- cam/utils.go | 4 ++-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cam/cam.go b/cam/cam.go index 425f4b4..411ad60 100644 --- a/cam/cam.go +++ b/cam/cam.go @@ -202,27 +202,27 @@ func (vs *videostore) DoCommand(_ context.Context, _ map[string]interface{}) (ma return nil, resource.ErrDoUnimplemented } -func (fv *videostore) Images(_ context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) { +func (vs *videostore) Images(_ context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) { return nil, resource.ResponseMetadata{}, errors.New("not implemented") } -func (fv *videostore) NextPointCloud(_ context.Context) (pointcloud.PointCloud, error) { +func (vs *videostore) NextPointCloud(_ context.Context) (pointcloud.PointCloud, error) { return nil, errors.New("not implemented") } -func (fv *videostore) Projector(ctx context.Context) (transform.Projector, error) { - return fv.cam.Projector(ctx) +func (vs *videostore) Projector(ctx context.Context) (transform.Projector, error) { + return vs.cam.Projector(ctx) } -func (fv *videostore) Properties(ctx context.Context) (camera.Properties, error) { - p, err := fv.cam.Properties(ctx) +func (vs *videostore) Properties(ctx context.Context) (camera.Properties, error) { + p, err := vs.cam.Properties(ctx) if err == nil { p.SupportsPCD = false } return p, err } -func (fv *videostore) Stream(_ context.Context, _ ...gostream.ErrorHandler) (gostream.VideoStream, error) { +func (vs *videostore) Stream(_ context.Context, _ ...gostream.ErrorHandler) (gostream.VideoStream, error) { return nil, errors.New("not implemented") } @@ -231,7 +231,7 @@ func (fv *videostore) Stream(_ context.Context, _ ...gostream.ErrorHandler) (gos // meant for long term storage of video clips that are not necessarily triggered by // detections. // TODO(seanp): Should this be throttled to a certain FPS? -func (fv *videostore) processFrames(ctx context.Context) { +func (vs *videostore) processFrames(ctx context.Context) { for { // TODO(seanp): How to gracefully exit this loop? select { @@ -239,25 +239,25 @@ func (fv *videostore) processFrames(ctx context.Context) { return default: } - frame, _, err := fv.stream.Next(ctx) + frame, _, err := vs.stream.Next(ctx) if err != nil { - fv.logger.Error("failed to get frame from camera", err) + vs.logger.Error("failed to get frame from camera", err) return } lazyImage, ok := frame.(*rimage.LazyEncodedImage) if !ok { - fv.logger.Error("frame is not of type *rimage.LazyEncodedImage") + vs.logger.Error("frame is not of type *rimage.LazyEncodedImage") return } - encoded, pts, dts, err := fv.enc.encode(lazyImage.DecodedImage()) + encoded, pts, dts, err := vs.enc.encode(lazyImage.DecodedImage()) if err != nil { - fv.logger.Error("failed to encode frame", err) + vs.logger.Error("failed to encode frame", err) return } // segment frame - err = fv.seg.writeEncodedFrame(encoded, pts, dts) + err = vs.seg.writeEncodedFrame(encoded, pts, dts) if err != nil { - fv.logger.Error("failed to segment frame", err) + vs.logger.Error("failed to segment frame", err) return } } @@ -265,7 +265,7 @@ func (fv *videostore) processFrames(ctx context.Context) { // deleter is a go routine that cleans up old clips if storage is full. It runs every // minute and deletes the oldest clip until the storage size is below the max. -func (fv *videostore) deleter(ctx context.Context) { +func (vs *videostore) deleter(ctx context.Context) { // TODO(seanp): Using seconds for now, but should be minutes in prod. ticker := time.NewTicker(60 * time.Second) defer ticker.Stop() @@ -275,9 +275,9 @@ func (fv *videostore) deleter(ctx context.Context) { return case <-ticker.C: // Perform the deletion of the oldest clip - err := fv.seg.cleanupStorage() + err := vs.seg.cleanupStorage() if err != nil { - fv.logger.Error("failed to clean up storage", err) + vs.logger.Error("failed to clean up storage", err) continue } } @@ -286,13 +286,13 @@ func (fv *videostore) deleter(ctx context.Context) { // Close closes the video storage camera component. // It closes the stream, workers, encoder, segmenter, and watcher. -func (fv *videostore) Close(ctx context.Context) error { - err := fv.stream.Close(ctx) +func (vs *videostore) Close(ctx context.Context) error { + err := vs.stream.Close(ctx) if err != nil { return err } - fv.workers.Stop() - fv.enc.Close() - fv.seg.Close() + vs.workers.Stop() + vs.enc.Close() + vs.seg.Close() return nil } diff --git a/cam/utils.go b/cam/utils.go index 9cf31ae..6b8d7e0 100644 --- a/cam/utils.go +++ b/cam/utils.go @@ -71,7 +71,7 @@ func getHomeDir() string { // createDir creates a directory at the provided path if it does not exist. func createDir(path string) error { if _, err := os.Stat(path); os.IsNotExist(err) { - err := os.MkdirAll(path, 0755) + err := os.MkdirAll(path, 0o755) if err != nil { return err } @@ -174,5 +174,5 @@ func fetchCompName(resourceName string) string { if len(parts) > 0 { return parts[len(parts)-1] } - return "unkown" + return "unknown" }