diff --git a/ChangeLog b/ChangeLog index 2781b6b..2ae2543 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2021-11-17: +- adding basic support for SBVcams like SV-305 + + 2021-11-15: - JSON read changed, space was interpreted as '\n' - adding support for multiple drivers diff --git a/Makefile b/Makefile index 049cd1e..9bddcee 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ APP = simpleskycam -include Makefile.rules -OBJECTS = gui.oo main.oo video.oo videoframe.oo videodev.oo videodev-v4l2.oo convert.oo filter.oo detect.oo json.oo configuration.oo +OBJECTS := $(OBJECTS) gui.oo main.oo video.oo videoframe.oo videodev.oo videodev-v4l2.oo convert.oo filter.oo detect.oo json.oo configuration.oo DISTNAME=simpleskycam-$(VERSION) ifeq ($(TARGET),) diff --git a/Makefile.rules.linux b/Makefile.rules.linux index 9b719ae..d86e186 100644 --- a/Makefile.rules.linux +++ b/Makefile.rules.linux @@ -6,4 +6,15 @@ CPPFLAGS = -std=c++11 -ggdb -Wall -Werror -O0 `pkg-config --cflags gtk+-3.0 gmod INCLUDES = LDFLAGS = LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -ljpeg +OBJECTS = + +# +# Uncomment to enable support for SVBONY Cammeras. +# +CPPFLAGS := $(CPPFLAGS) -DUSE_SVBONY -I/usr/local/include +LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib +OBJECTS := $(OBJECTS) videodev-svbcam.oo +# + + diff --git a/configuration.cc b/configuration.cc index 4de2964..30e5c60 100644 --- a/configuration.cc +++ b/configuration.cc @@ -3,9 +3,10 @@ #include "video.h" #include "gui.h" +#include #include -extern VideoDev *videodev; +// extern VideoDev *videodev; extern GtkBuilder *_builder_; // work around for threads @@ -19,14 +20,12 @@ Configuration::~Configuration() { std::string Configuration::GetDefaultFileName() { std::string fn = ""; - char *hd = NULL; + char *hd = getenv ((char*)"HOME"); - if ((hd = getenv ("HOME")) == NULL) { - // no homedir defined? - return ""; + if (hd != NULL) { + fn = hd; + fn = fn + "/" + CONFIGURATION_DEFAULTFILE; } - fn = hd; - fn = fn + "/" + CONFIGURATION_DEFAULTFILE; return fn; }; diff --git a/video.cc b/video.cc index de2a8f9..aee4791 100644 --- a/video.cc +++ b/video.cc @@ -10,12 +10,18 @@ #include #include #include "gui.h" -#include "video.h" -#include "videodev.h" -#include "videodev-v4l2.h" #include "filter.h" #include "detect.h" #include "configuration.h" +#include "video.h" +#include "videodev.h" +#include "videodev-v4l2.h" + +#ifdef USE_SVBONY +#include "videodev-svbcam.h" +#endif + + VideoDev *videodev = NULL; GThread *videodev_thread = NULL; @@ -259,6 +265,9 @@ void cb_video_btnrefreshlist (GtkWidget *widget, gpointer data) { VideoDev vdef1; vdef1.GetDeviceList(&devlist); VideoDev_V4L2 vdef2; vdef2.GetDeviceList(&devlist); +#ifdef USE_SVBONY + VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist); +#endif for (iter = devlist.begin(); iter != devlist.end(); iter++) { gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1, @@ -314,7 +323,14 @@ void cb_video_btnrec (GtkWidget *widget, gpointer data) { delete videodev; videodev = NULL; } + + // + // load the selected driver if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2; + +#ifdef USE_SVBONY + else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; +#endif else if (driver.compare("DUMMY") == 0) videodev = new VideoDev; else videodev = new VideoDev; diff --git a/videodev-dummy.cc b/videodev-dummy.cc new file mode 100644 index 0000000..de38f38 --- /dev/null +++ b/videodev-dummy.cc @@ -0,0 +1,107 @@ + +#include "convert.h" +#include "videodev-svbcam.h" + +VideoDev_SVBCam::VideoDev_SVBCam() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); +}; + + +VideoDev_SVBCam::~VideoDev_SVBCam() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (running > 0) CaptureStop(); +} + + + +/* + * return a list of /dev/video* devices found on the system, and read out its human friendly name + * output will be a lit of: "V4L2 /dev/videoX [Name]" + */ +int VideoDev_SVBCam::GetDeviceList(std::list *list) { + std::string device; + int devnum; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + if (list == NULL) return 0; + + return 1; +} + + + +/* + * Open Device + * prepare the buffer, InitMMAP and read all controls + */ +int VideoDev_SVBCam::Open() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_OK; +}; + + +/* + * Close Device + * Free videobuffer + */ +int VideoDev_SVBCam::Close() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_OK; +}; + + + +/***************************************************************************************************** + * VideoGrabbing + */ + + +/* + * send the start capture signal to the cam + */ +int VideoDev_SVBCam::CaptureStart() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_OK; +}; + + +int VideoDev_SVBCam::CaptureStop() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_OK; +}; + + +/* + * try to grab one frame and convert it into RGB32. + * If something goes wrong return an error code. + * Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read. + */ +int VideoDev_SVBCam::Grab(VideoFrame *vf) { + return VDEV_STATUS_OK; +} + + + + + +/***************************************************************************************************** + * Controls + */ + +/* + * set video control identified by id + */ +int VideoDev_SVBCam::SetDevCtrl(unsigned int id, int value) { + return VDEV_STATUS_OK; +}; + + +/* + * get video control identified by id + */ +int VideoDev_SVBCam::GetDevCtrl(unsigned int id, int *value) { + return VDEV_STATUS_OK; +}; + + diff --git a/videodev-dummy.h b/videodev-dummy.h new file mode 100644 index 0000000..4b68a59 --- /dev/null +++ b/videodev-dummy.h @@ -0,0 +1,54 @@ + +#ifndef _H_VIDEODEV_V4L2_H_ +#define _H_VIDEODEV_V4L2_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include "convert.h" +#include "gui.h" +#include "videodev.h" + + +enum { + IOMODE_READ, + IOMODE_MMAP +}; + + + +class VideoDev_SVBCam: public VideoDev { +private: + ConvertData cdata; + + int Grab(VideoFrame *vf); + int Open(); + int Close(); + int CaptureStart(); + int CaptureStop(); + int SetDevCtrl(unsigned int id, int value); + int GetDevCtrl(unsigned int id, int *value); +public: + VideoDev_SVBCam(); + ~VideoDev_SVBCam(); + int GetDeviceList(std::list *list); +}; + +#endif diff --git a/videodev-svbcam.cc b/videodev-svbcam.cc new file mode 100644 index 0000000..ac41e5b --- /dev/null +++ b/videodev-svbcam.cc @@ -0,0 +1,306 @@ +/* + * module to read video data from SVBcams. + * maybe you have to add something like: /etc/udev.d/90-svbony.rules to get read/wirte access for users in 'plugdev' + * SUBSYSTEMS=="usb", ATTRS{idVendor}=="f266", ATTRS{idProduct}=="9a0a", GROUP="plugdev", MODE="0660" + */ + +#include +#include "convert.h" +#include "videodev-svbcam.h" + +VideoDev_SVBCam::VideoDev_SVBCam() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + camid = -1; +}; + + +VideoDev_SVBCam::~VideoDev_SVBCam() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (running > 0) CaptureStop(); +} + + +void VideoDev_SVBCam::print_error(int err) { + switch (err) { + case SVB_ERROR_INVALID_ID: + printf ("SVB_ERROR_INVALID_ID\n"); + break; + case SVB_ERROR_CAMERA_REMOVED: + printf ("SVB_ERROR_CAMERA_REMOVED\n"); + break; + case SVB_ERROR_CAMERA_CLOSED: + printf ("SVB_ERROR_CAMERA_CLOSED\n"); + break; + case SVB_ERROR_INVALID_SIZE: + printf ("SVB_ERROR_INVALID_SIZE\n"); + break; + case SVB_ERROR_INVALID_IMGTYPE: + printf ("SVB_ERROR_INVALID_IMGTYPE\n"); + break; + case SVB_ERROR_INVALID_MODE: + printf ("SVB_ERROR_INVALID_MODE\n"); + break; + case SVB_ERROR_EXPOSURE_IN_PROGRESS: + printf("SVB_ERROR_EXPOSURE_IN_PROGRESS\n"); + break; + case SVB_ERROR_GENERAL_ERROR: + printf("SVB_ERROR_GENERAL_ERROR\n"); + break; + case SVB_ERROR_TIMEOUT: + printf("SVB_ERROR_TIMEOUT\n"); + break; + default: + printf ("unknown %d\n", err); + break; + } + exit (0); +}; + + + +/* + * check for connected devices and return the result in a lite. + */ +int VideoDev_SVBCam::GetDeviceList(std::list *list) { + int iNumofConnectCameras = SVBGetNumOfConnectedCameras(); + std::string device; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (list == NULL) return VDEV_STATUS_ERROR; + + // from sample code + SVB_CAMERA_INFO *caminfo = (SVB_CAMERA_INFO *)malloc(sizeof(SVB_CAMERA_INFO)*iNumofConnectCameras); + for (int i = 0; i < iNumofConnectCameras; i++) { + SVBGetCameraInfo(&caminfo[i], i); + device = "SVBCAM " + to_string(caminfo[i].CameraID) + " [" + caminfo[i].FriendlyName + "]"; + list->push_back(device); + } + + return VDEV_STATUS_OK; +} + + + +/* + * Open Device + * prepare the buffer + */ +int VideoDev_SVBCam::Open() { + int camnumcontrols, err; + SVB_CONTROL_CAPS *camcontrols = NULL; + SVB_CAMERA_PROPERTY camprop; + VideoDevCtrl vctl; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + camid = atoi (conf_device.c_str()); + printf ("%s:%d %s opening cam %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + + if ((err = SVBOpenCamera(camid)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + + // + // get cam property + if ((err = SVBGetCameraProperty(camid, &camprop)) != SVB_SUCCESS) { + print_error(err); + Close(); + return VDEV_STATUS_ERROR; + } + printf ("%s:%d %s height: %ld width: %ld\n", __FILE__, __LINE__, __FUNCTION__, camprop.MaxHeight, camprop.MaxWidth); + + for(int i=0; i < 8 && camprop.SupportedVideoFormat[i] == SVB_IMG_END; i++) { + printf ("%s:%d %s VideoFormat Index:%d ", __FILE__, __LINE__, __FUNCTION__, i); + switch (camprop.SupportedVideoFormat[i]) { + case SVB_IMG_RAW8: + printf("\t\tSVB_IMG_RAW8\n"); + break; + case SVB_IMG_RAW10: + printf("\t\tSVB_IMG_RAW10\n"); + break; + case SVB_IMG_RAW12: + printf("\t\tSVB_IMG_RAW12\n"); + break; + case SVB_IMG_RAW14: + printf("\t\tSVB_IMG_RAW14\n"); + break; + case SVB_IMG_RAW16: + printf("\t\tSVB_IMG_RAW16\n"); + break; + case SVB_IMG_Y8: + printf("\t\tSVB_IMG_Y8\n"); + break; + case SVB_IMG_Y10: + printf("\t\tSVB_IMG_Y10\n"); + break; + case SVB_IMG_Y12: + printf("\t\tSVB_IMG_Y12\n"); + break; + case SVB_IMG_Y14: + printf("\t\tSVB_IMG_Y14\n"); + break; + case SVB_IMG_Y16: + printf("\t\tSVB_IMG_Y16\n"); + break; + case SVB_IMG_RGB24: + printf("\t\tSVB_IMG_RGB24\n"); + break; + case SVB_IMG_RGB32: + printf("\t\tSVB_IMG_RGB32\n"); + break; + case SVB_IMG_END: + printf("\t\tSVB_IMG_END\n"); + break; + default: + printf ("\t\tunbekannt\n"); + break; + } + } + + + // + // get controls + vidctrls.clear(); + if ((err = SVBGetNumOfControls(camid, &camnumcontrols)) != SVB_SUCCESS) print_error(err); + camcontrols = (SVB_CONTROL_CAPS*) malloc (sizeof(SVB_CONTROL_CAPS) * camnumcontrols); + for (int i = 0; i < camnumcontrols; i++) { + if ((err = SVBGetControlCaps(camid, i, &camcontrols[i])) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + printf ("%s:%d %s Got Control idx: %d name:%s desc:%s\n", __FILE__, __LINE__, __FUNCTION__, + i, camcontrols[i].Name, camcontrols[i].Description); + vctl.name = (char*)camcontrols[i].Name; + vctl.id = i; + vctl.min = camcontrols[i].MinValue; + vctl.max = camcontrols[i].MaxValue; + GetDevCtrl(i, &vctl.value); + vidctrls.push_back(vctl); + } + + // + // set ROI (region of interest) + if ((err = SVBSetROIFormat(camid, 0, 0, camprop.MaxWidth, camprop.MaxHeight, 1)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + + // Set Mode and IMG Format + if ((err = SVBSetCameraMode(camid, SVB_MODE_NORMAL)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + if ((err = SVBSetOutputImageType(camid, SVB_IMG_RGB24)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + + // + // preprare buffer + LockMutex(); + threaddata.vf.SetSize(camprop.MaxWidth, camprop.MaxHeight); + UnLockMutex(); + + return VDEV_STATUS_OK; +}; + + +/* + * Close Device + * Free videobuffer + */ +int VideoDev_SVBCam::Close() { + int err; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if ((err = SVBCloseCamera(camid)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + return VDEV_STATUS_OK; +}; + + + +/***************************************************************************************************** + * VideoGrabbing + */ + + +/* + * send the start capture signal to the cam + */ +int VideoDev_SVBCam::CaptureStart() { + int err; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + // start video capture + if ((err = SVBStartVideoCapture(camid)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + + return VDEV_STATUS_OK; +}; + + +int VideoDev_SVBCam::CaptureStop() { + int err; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if ((err = SVBStopVideoCapture(camid)) != SVB_SUCCESS) { + print_error(err); + return VDEV_STATUS_ERROR; + } + + return VDEV_STATUS_OK; +}; + + +/* + * try to grab one frame and convert it into RGB32. + * If something goes wrong return an error code. + * Return code VDEV_STATUS_AGAIN is not an error. There was no video image ready to read. + */ +int VideoDev_SVBCam::Grab(VideoFrame *vf) { + int err; + + LockMutex(); + if ((err = SVBGetVideoData(camid, threaddata.vf.data, (long)threaddata.vf.size, 50)) != SVB_SUCCESS) { + if (err != SVB_ERROR_TIMEOUT) { + print_error(err); + UnLockMutex(); + return VDEV_STATUS_ERROR; + } + } + UnLockMutex(); + + return VDEV_STATUS_OK; +} + + + + + +/***************************************************************************************************** + * Controls + */ + +/* + * set video control identified by id + */ +int VideoDev_SVBCam::SetDevCtrl(unsigned int id, int value) { + return VDEV_STATUS_OK; +}; + + +/* + * get video control identified by id + */ +int VideoDev_SVBCam::GetDevCtrl(unsigned int id, int *value) { + *value = 0; + return VDEV_STATUS_OK; +}; + + diff --git a/videodev-svbcam.h b/videodev-svbcam.h new file mode 100644 index 0000000..a4828fb --- /dev/null +++ b/videodev-svbcam.h @@ -0,0 +1,52 @@ + +#ifndef _H_VIDEODEV_SVBCAM_H_ +#define _H_VIDEODEV_SVBCAM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include "convert.h" +#include "gui.h" +#include "videodev.h" + + +class VideoDev_SVBCam: public VideoDev { +private: + VideoFrame vf; + + ConvertData cdata; + int camid; + + int Grab(VideoFrame *vf); + int Open(); + int Close(); + int CaptureStart(); + int CaptureStop(); + int SetDevCtrl(unsigned int id, int value); + int GetDevCtrl(unsigned int id, int *value); + + void print_error(int err); +public: + VideoDev_SVBCam(); + ~VideoDev_SVBCam(); + int GetDeviceList(std::list *list); +}; + +#endif diff --git a/videodev.h b/videodev.h index 6a4e457..e2c5fb7 100644 --- a/videodev.h +++ b/videodev.h @@ -119,6 +119,7 @@ private: virtual int GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; }; friend class VideoDev_V4L2; + friend class VideoDev_SVBCam; public: VideoDev(); virtual ~VideoDev();