From 72b847a691c97b024f1f96e0917627affc3a7066 Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Sat, 31 Jan 2026 17:29:56 +0100 Subject: [PATCH] adding controls via subdevice --- configuration.cc | 15 +++++++++++++-- configuration.h | 9 +++++---- main.cc | 38 +++++++++++++++++++------------------- miniwebcam.h | 3 +++ video.cc | 1 + video.h | 3 ++- videodevice_dump.h | 2 +- videodevice_v4l2.cc | 29 ++++++++++++++++++++++++----- videodevice_v4l2.h | 3 ++- videoframe.cc | 5 +++++ 10 files changed, 75 insertions(+), 33 deletions(-) diff --git a/configuration.cc b/configuration.cc index 680c381..b19b476 100644 --- a/configuration.cc +++ b/configuration.cc @@ -35,13 +35,14 @@ Configuration::Configuration() { vdev_format = ""; vdev_dumpfile = ""; vdev_dumppath = ""; + vdev_cdevice = ""; ssl_key = DEFAULT_SSL_KEY; ssl_cert = DEFAULT_SSL_CERT; initflags = 0; vdev_height = DEFAULT_VDEV_HEIGHT; vdev_width = DEFAULT_VDEV_WIDTH; - web_height = DEFAULT_WEB_HEIGHT; - web_width = DEFAULT_WEB_WIDTH; + web_height = -1; + web_width = -1; web_imagerefresh = 250; }; @@ -66,6 +67,7 @@ int Configuration::PrintConfig() { jp.AddObject("ssl-cert-file", ssl_cert); jp.AddObject("vdev-iomode", vdev_iomode); jp.AddObject("vdev-device", vdev_device); + jp.AddObject("vdev-cdevice", vdev_cdevice); jp.AddObject("vdev-size", to_string(vdev_width) + "x" + to_string(vdev_height)); jp.AddObject("vdev-format", vdev_format); jp.AddObject("web-size" , to_string(web_width) + "x" + to_string(web_height)); @@ -112,6 +114,7 @@ int Configuration::LoadFile(std::string fn) { if (jp.GetValueInt("web-refresh", &i)) web_imagerefresh = i; if (jp.GetValueString("vdev-device", &s)) vdev_device = s; + if (jp.GetValueString("vdev-cdevice", &s)) vdev_cdevice = s; if (jp.GetValueString("vdev-format", &s)) vdev_format = s; if (jp.GetValueString("vdev-dumppath", &s)) vdev_dumppath = s; if (jp.GetValueInt("vdev-iomode", &i)) vdev_iomode = i; @@ -203,6 +206,13 @@ int Configuration::LoadArgs(int argc, char **argv) { else ErrorExit("missing device parameter", -1); } + if (strcmp(argv[i], "-vdevcdevice") == 0) { + if (++i < argc) { + vdev_cdevice = argv[i]; + } + else + ErrorExit("missing ctrl (subdev) device parameter", -1); + } if (strcmp(argv[i], "-vdevdumpfile") == 0) { if (++i < argc) { vdev_dumpfile = argv[i]; @@ -252,6 +262,7 @@ void Configuration::Help() { printf ("\n"); printf (" -vdeviomode INT IOMode to read the video data, 0-read, 1-MMap\n"); printf (" -vdevdevice FILE Device File i.e. /dev/video2\n"); + printf (" -vdevcdevice FILE Device File i.e. /dev/v4l-subdev2\n"); printf (" -vdevsize INTxINT define video input resolution\n"); printf (" -vdevformat FORMAT 4 Char Format code - see v4l2 documentation (videodev2.h)\n"); printf (" -vdevdumpfile FILE file to read raw image data\n"); diff --git a/configuration.h b/configuration.h index fceb608..7dc070f 100644 --- a/configuration.h +++ b/configuration.h @@ -15,10 +15,10 @@ #define DEFAULT_SSL_CERT "/etc/miniwebcam/ssl-cert.pem" #define DEFAULT_VDEV_IOMODE 1 #define DEFAULT_VDEV_DEVICE "/dev/video0" -#define DEFAULT_VDEV_HEIGHT -1 -#define DEFAULT_VDEV_WIDTH -1 -#define DEFAULT_WEB_WIDTH 1024 -#define DEFAULT_WEB_HEIGHT 768 +#define DEFAULT_VDEV_WIDTH 1920 +#define DEFAULT_VDEV_HEIGHT 1080 +#define DEFAULT_WEB_WIDTH -1 +#define DEFAULT_WEB_HEIGHT -1 #define CONF_INITFLAGS_PRINT 0x0001 #define CONF_INITFLAGS_HELP 0x0002 @@ -42,6 +42,7 @@ public: int vdev_width; int vdev_iomode; std::string vdev_device; + std::string vdev_cdevice; std::string vdev_format; std::string vdev_dumpfile; std::string vdev_dumppath; diff --git a/main.cc b/main.cc index 01b8a95..97471e5 100644 --- a/main.cc +++ b/main.cc @@ -19,23 +19,6 @@ std::string GetDefaultConfig(std::string name); VideoFrame inputimage; VideoFrame currentimage; -void ErrorExit(std::string text, int errorcode) { - printf ("Error: %s\n", text.c_str()); - exit (errorcode); -}; - - -int Lock () { - if (pthread_mutex_lock(&mtx) == 0) return 1; - else return 0; -}; - - -int UnLock () { - if (pthread_mutex_unlock(&mtx) == 0) return 1; - else return 0; -}; - static void *thread_webserver(void *ignored_argument) { WebCamServer webserver; @@ -56,7 +39,6 @@ static void *thread_webserver(void *ignored_argument) { }; - static void *thread_video(void *ignored_argument) { VideoDevice *vdev= NULL; @@ -67,7 +49,7 @@ static void *thread_video(void *ignored_argument) { vdev = new VideoDevice_V4L2(); } - if (vdev->SetDevice (config.vdev_device, config.vdev_width, config.vdev_height, convert_to_pixelformat(config.vdev_format)) == 0) { + if (vdev->SetDevice (config.vdev_device, config.vdev_cdevice, config.vdev_width, config.vdev_height, convert_to_pixelformat(config.vdev_format)) == 0) { debug ("could not setup device.\n"); goto thread_video_exit; // we use goto for a better cleanup of the thread } @@ -102,6 +84,24 @@ thread_video_exit: +void ErrorExit(std::string text, int errorcode) { + printf ("Error: %s\n", text.c_str()); + exit (errorcode); +}; + + +int Lock () { + if (pthread_mutex_lock(&mtx) == 0) return 1; + else return 0; +}; + + +int UnLock () { + if (pthread_mutex_unlock(&mtx) == 0) return 1; + else return 0; +}; + + int main(int argc, char **argv) { pthread_t thr_webserver; pthread_t thr_video; diff --git a/miniwebcam.h b/miniwebcam.h index 4d4023c..f3f6707 100644 --- a/miniwebcam.h +++ b/miniwebcam.h @@ -27,6 +27,9 @@ int Lock(); int UnLock(); extern VideoFrame currentimage; +extern VideoFrame inputimage; +extern VideoFrame currentimage; +extern int running; #endif diff --git a/video.cc b/video.cc index 9a54595..a71621f 100644 --- a/video.cc +++ b/video.cc @@ -31,3 +31,4 @@ VideoDevice::~VideoDevice() { debug (""); }; + diff --git a/video.h b/video.h index 8f3a240..70d4121 100644 --- a/video.h +++ b/video.h @@ -67,6 +67,7 @@ class VideoDevice { protected: std::list vidctrls; std::string conf_videodev; + std::string conf_videocdev; uint32_t conf_videofmt; int conf_width; int conf_height; @@ -76,7 +77,7 @@ class VideoDevice { VideoDevice(); virtual ~VideoDevice(); - virtual int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) { debug (""); return 0; }; + virtual int SetDevice(std::string newdevice, std::string newcdevice, int nwidth, int nheight, uint32_t pixfmt) { debug (""); return 0; }; virtual int SetIOMode(int newiomode) { debug (""); return 0; }; virtual int Start() { debug (""); return 0; }; virtual int Stop() { debug (""); return 0; }; diff --git a/videodevice_dump.h b/videodevice_dump.h index 4ed7503..794c202 100644 --- a/videodevice_dump.h +++ b/videodevice_dump.h @@ -30,7 +30,7 @@ class VideoDevice_Dump : public VideoDevice { VideoDevice_Dump(); ~VideoDevice_Dump(); - int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) { config.vdev_device = newdevice; return 1; }; + int SetDevice(std::string newdevice, std::string newcdevice, int nwidth, int nheight, uint32_t pixfmt) { config.vdev_device = newdevice; return 1; }; int SetIOMode(int newiomode) { return 1; }; int Start(); int Stop(); diff --git a/videodevice_v4l2.cc b/videodevice_v4l2.cc index fae998c..d89b3e7 100644 --- a/videodevice_v4l2.cc +++ b/videodevice_v4l2.cc @@ -5,12 +5,14 @@ VideoDevice_V4L2::VideoDevice_V4L2() { debug (""); - conf_height = 0; - conf_width = 0; + conf_height = -1; + conf_width = -1; conf_videodev = ""; + conf_videocdev = ""; conf_iomode = 0; conf_videofmt = 0; fd = -1; + cfd = -1; }; @@ -21,7 +23,7 @@ VideoDevice_V4L2::~VideoDevice_V4L2() { -int VideoDevice_V4L2::SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) { +int VideoDevice_V4L2::SetDevice(std::string newdevice, std::string newcdevice, int nwidth, int nheight, uint32_t pixfmt) { int isrunning = 0; if (fd != -1) { @@ -30,6 +32,7 @@ int VideoDevice_V4L2::SetDevice(std::string newdevice, int nwidth, int nheight, } conf_videodev = newdevice; + conf_videocdev = newcdevice; conf_width = nwidth; conf_height = nheight; conf_videofmt = pixfmt; @@ -65,8 +68,9 @@ int VideoDevice_V4L2::Open() { struct v4l2_capability vcap; VideoDevCtrl vctl; - debug ("Device: '%s'", conf_videodev.c_str()); + debug ("Device: '%s' Ctrl Device: '%s'", conf_videodev.c_str(), conf_videocdev.c_str()); if (fd != -1) return 0; + if (cfd != -1) return 0; // // open device and get device name and capabilities | O_NONBLOCK @@ -75,6 +79,15 @@ int VideoDevice_V4L2::Open() { return 0; } + // + // open device and get device name and capabilities | O_NONBLOCK + if (conf_videocdev.length() > 0) { + if((cfd = open(conf_videocdev.c_str(), O_RDWR)) == -1){ + debug ("could not open ctrl device error: %s", strerror(errno)); + return 0; + } + } + if(ioctl(fd, VIDIOC_QUERYCAP, &vcap) == -1) strncpy ((char*)&vcap.card, "unknown", sizeof(vcap.card)); debug ("VideoDevice_V4L2::Open Devicefile:%s Card:%s fd:%d", conf_videodev.c_str(), vcap.card, fd); @@ -100,11 +113,13 @@ int VideoDevice_V4L2::Open() { memset (&queryctrl, 0, sizeof (queryctrl)); for (i = V4L2_CID_BASE; i < V4L2_CID_DETECT_CLASS_BASE+0x1000; i++) { queryctrl.id = i; - if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { + if (0 == ioctl (cfd != -1 ? cfd : fd, VIDIOC_QUERYCTRL, &queryctrl)) { vctl.name = (char*)queryctrl.name; vctl.id = queryctrl.id; vctl.min = queryctrl.minimum; vctl.max = queryctrl.maximum; + debug ("CTRL: id:%p name:%s range:%d %d step:%d type:%d", queryctrl.id, queryctrl.name, + queryctrl.minimum, queryctrl.maximum, queryctrl.step, queryctrl.type); GetDevCtrl(queryctrl.id, &vctl.value); vidctrls.push_back(vctl); } @@ -147,6 +162,10 @@ int VideoDevice_V4L2::Open() { debug ("VIDIOC_S_FMT : %s", strerror (errno)); close (fd); fd = -1; + if (cfd != -1) { + close (cfd); + cfd = -1; + } return 0; } diff --git a/videodevice_v4l2.h b/videodevice_v4l2.h index a52bd63..647d7b2 100644 --- a/videodevice_v4l2.h +++ b/videodevice_v4l2.h @@ -14,6 +14,7 @@ class VideoDevice_V4L2 : public VideoDevice { struct v4l2_format fmt; int fd; // filedescriptor to the video device file + int cfd; // filedescriptor to the ctrl video device file int Open(); int Close(); @@ -25,7 +26,7 @@ class VideoDevice_V4L2 : public VideoDevice { VideoDevice_V4L2(); ~VideoDevice_V4L2(); - int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt); + int SetDevice(std::string newdevice, std::string newcdevice, int nwidth, int nheight, uint32_t pixfmt); int SetIOMode(int newiomode); int Start(); int Stop(); diff --git a/videoframe.cc b/videoframe.cc index ae992e9..9162193 100644 --- a/videoframe.cc +++ b/videoframe.cc @@ -125,6 +125,11 @@ int VideoFrame::CopyTo(VideoFrame *dest, int destw, int desth) { unsigned char *destptr; if (dest == NULL) return 0; + if (destw <= 0 || desth <= 0) { + destw = width; + desth = height; + } + dest->SetSize(destw, desth); destptr = dest->GetPixBuf(); if (destptr == NULL) return 0;