From f47074adfb28107157333b6e3b8b481df94218eb Mon Sep 17 00:00:00 2001 From: Stefan Jahn Date: Sun, 12 Feb 2023 20:13:36 +0100 Subject: [PATCH] Very preliminary code for VfW --- Makefile | 3 + Makefile.rules.windows | 12 ++- video.cc | 11 ++- videodev-vfw.cc | 203 +++++++++++++++++++++++++++++++++++++++++ videodev-vfw.h | 35 +++++++ videodev.h | 6 ++ 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 videodev-vfw.cc create mode 100644 videodev-vfw.h diff --git a/Makefile b/Makefile index 6a594c2..bf912d2 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,9 @@ ifeq ($(USE_DNG),1) endif ifeq ($(USE_V4L2),1) echo "#define USE_V4L2" >> config.h +endif +ifeq ($(USE_VFW),1) + echo "#define USE_VFW" >> config.h endif echo "" >> config.h ifeq ($(DEBUG_ANGLES),1) diff --git a/Makefile.rules.windows b/Makefile.rules.windows index ab7a60b..b68d23e 100644 --- a/Makefile.rules.windows +++ b/Makefile.rules.windows @@ -1,11 +1,12 @@ include Makefile.config +USE_VFW = 1 TARGET = $(APP).exe CPP = g++ CPPFLAGS = -ggdb -Wall -O0 `pkg-config --cflags gtk+-3.0 gmodule-export-2.0` -Wl,--export-dynamic -DBUILD_WINDOWS=1 -Wdeprecated -D_POSIX_C_SOURCE=200112L INCLUDES = -LDFLAGS = -lws2_32 -ljpeg +LDFLAGS = -lws2_32 -ljpeg LIBS = `pkg-config --libs gtk+-3.0 gmodule-export-2.0` -L/usr/lib -mwindows OBJECTS := $(OBJECTS) windows.oo @@ -19,3 +20,12 @@ LDFLAGS := $(LDFLAGS) -lSVBCameraSDK -L/usr/local/lib OBJECTS := $(OBJECTS) videodev-svbcam.oo endif # + +# +# add makefile configuration for vfw cams +# +ifeq ($(USE_VFW),1) +OBJECTS := $(OBJECTS) videodev-vfw.oo +LDFLAGS := $(LDFLAGS) -lvfw32 +endif +# diff --git a/video.cc b/video.cc index a9fe8e4..a9675c6 100644 --- a/video.cc +++ b/video.cc @@ -313,7 +313,10 @@ void cb_video_btnrefreshlist (GtkWidget *widget, gpointer data) { #ifdef USE_SVBONY VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist); #endif - VideoDev_Simulation vdef4; vdef4.GetDeviceList(&devlist); +#ifdef USE_VFW + VideoDev_VFW vdef4; vdef4.GetDeviceList(&devlist); +#endif + VideoDev_Simulation vdef5; vdef5.GetDeviceList(&devlist); for (iter = devlist.begin(); iter != devlist.end(); iter++) { gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1, @@ -361,6 +364,9 @@ void cb_video_btnrec (GtkWidget *widget, gpointer data) { #endif #ifdef USE_SVBONY else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; +#endif +#ifdef USE_VFW + else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW; #endif else if (driver.compare("SIMULATION") == 0) videodev = new VideoDev_Simulation; else videodev = new VideoDev; @@ -799,6 +805,9 @@ void cb_video_cbox_videodev (GtkWidget *widget, gpointer data) { #endif #ifdef USE_SVBONY else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; +#endif +#ifdef USE_VFW + else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW; #endif else videodev = new VideoDev; diff --git a/videodev-vfw.cc b/videodev-vfw.cc new file mode 100644 index 0000000..872707f --- /dev/null +++ b/videodev-vfw.cc @@ -0,0 +1,203 @@ +/* + * module to read video data from vfw. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include + +#include "convert.h" +#include "videodev-vfw.h" + +VideoDev_VFW::VideoDev_VFW() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + cap = NULL; +}; + + +VideoDev_VFW::~VideoDev_VFW() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + // if (running > 0) CaptureStop(); +} + +/* + * check for connected devices and return the result in a list. + */ +int VideoDev_VFW::GetDeviceList(std::list *list) { + + char name[256]; + char desc[256]; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (list == NULL) return VDEV_STATUS_ERROR; + + for(int i=0; i < 10; i++) + if(capGetDriverDescription(i, name, sizeof(name), desc, sizeof(desc))) { + std::string device; + + device = "VFW " + to_string(i) + " " + (string)name + " [" + (string)desc + "]"; + list->push_back(device); + } + + return VDEV_STATUS_OK; +} + + + +/* + * Open Device + * prepare the buffer + */ +int VideoDev_VFW::Open() { + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + camid = atoi (conf_device.c_str()); + printf ("%s:%d %s opening vfw id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + + cap = capCreateCaptureWindow("VFW", WS_CHILD, 0, 0, 0, 0, HWND_MESSAGE, camid); + if(!capDriverConnect(cap, 0)) { + printf ("%s:%d %s could not connect to vfw id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + return VDEV_STATUS_ERROR; + } + + capDlgVideoFormat(cap); + + BITMAPINFO bi; + capGetVideoFormat(cap, &bi, sizeof(BITMAPINFO)); + conf_width = bi.bmiHeader.biWidth; + conf_height = bi.bmiHeader.biHeight; + printf ("%s:%d %s current size %dx%d\n", __FILE__, __LINE__, __FUNCTION__, conf_width, conf_height); + + conf_format = convert_from_pixelformat(bi.bmiHeader.biCompression); + printf ("%s:%d %s current format %s\n", __FILE__, __LINE__, __FUNCTION__, conf_format.c_str()); + + switch(bi.bmiHeader.biCompression) { + case MAKEFOURCC('M','J','P','G'): + inframe_pixfmt = V4L2_PIX_FMT_MJPEG; + break; + case MAKEFOURCC('Y','U','Y','2'): + inframe_pixfmt = V4L2_PIX_FMT_YUYV; + break; + } + + return VDEV_STATUS_OK; +}; + + +/* + * Close Device + * Free videobuffer + */ +int VideoDev_VFW::Close() { + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + capDriverDisconnect(cap); + return VDEV_STATUS_OK; +}; + + + +/***************************************************************************************************** + * VideoGrabbing + */ + +int VFW_frame_size; +unsigned char VFW_frame_buffer[640*480*3]; + +LRESULT CALLBACK VFW_frame_callback(HWND h, LPVIDEOHDR v) { + VFW_frame_size = v->dwBytesUsed; + printf("frame callback: %d bytes\n", VFW_frame_size); + memcpy(VFW_frame_buffer, v->lpData, VFW_frame_size); + return TRUE; +} + +LRESULT VFW_error_callback(HWND h, int nID, LPCSTR lpsz) { + printf("error callback: %d (%s)\n", nID, lpsz); +} + +/* + * prepare inframe for raw picture data, will hold a video frame with 16bit per channel or BGR32/BGR24 + * inframe size = 4*W*H + * send the start capture signal to the cam + */ +int VideoDev_VFW::CaptureStart() { + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + capSetCallbackOnError(cap, VFW_error_callback); + + if(!capSetCallbackOnFrame(cap, VFW_frame_callback)) { + printf ("%s:%d %s could not set callback to vfw id %d\n", __FILE__, __LINE__, __FUNCTION__, camid); + } + + ConvertStart(&cdata, inframe_pixfmt); + + return VDEV_STATUS_OK; +}; + + + +/* + * free inbuffer + */ +int VideoDev_VFW::CaptureStop() { + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + capCaptureAbort(cap); + capSetCallbackOnFrame(cap, NULL); + ConvertStop(&cdata, inframe_pixfmt); + 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. + */ +// FIXME: SVBGetVideoData needs to be outside of Lock/UnLockMutex - using inside thread inbuffer +int VideoDev_VFW::Grab(VideoFrame *vf) { + + //if (inframe == NULL) return VDEV_STATUS_ERROR; + + LockMutex(); + Convert(&cdata, vf, VFW_frame_buffer, VFW_frame_size, inframe_pixfmt, conf_width, conf_height); + UnLockMutex(); + + return VDEV_STATUS_OK; +} + + +int VideoDev_VFW::GetDeviceFormats(string device, std::list *formats) { + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + return VDEV_STATUS_OK; +} + + + +/***************************************************************************************************** + * Controls + */ + +/* + * set video control identified by id + */ +int VideoDev_VFW::SetDevCtrl(unsigned int id, int value) { + + return VDEV_STATUS_OK; +}; + + +/* + * get video control identified by id + */ +int VideoDev_VFW::GetDevCtrl(unsigned int id, int *value) { + return VDEV_STATUS_OK; +}; + diff --git a/videodev-vfw.h b/videodev-vfw.h new file mode 100644 index 0000000..561247d --- /dev/null +++ b/videodev-vfw.h @@ -0,0 +1,35 @@ + +#ifndef _H_VIDEODEV_VFW_H_ +#define _H_VIDEODEV_VFW_H_ + +#include "videodev.h" + +class VideoDev_VFW: public VideoDev { +private: + unsigned char *inframe; + int inframe_size; + int inframe_w, inframe_h; + int inframe_pixfmt; + + ConvertData cdata; + int camid; + HWND cap; + + 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_VFW(); + ~VideoDev_VFW(); + int GetDeviceList(std::list *list); + int GetDeviceFormats(string device, std::list *formats); + int GetDeviceResolutions(string device, std::list *formats) { return VDEV_STATUS_OK; }; +}; + +#endif diff --git a/videodev.h b/videodev.h index c4ec9dc..21c4528 100644 --- a/videodev.h +++ b/videodev.h @@ -127,6 +127,9 @@ private: #ifdef USE_SVBONY friend class VideoDev_SVBCam; #endif +#ifdef USE_VFW + friend class VideoDev_VFW; +#endif public: VideoDev(); virtual ~VideoDev(); @@ -165,5 +168,8 @@ public: #ifdef USE_SVBONY #include "videodev-svbcam.h" #endif +#ifdef USE_VFW +#include "videodev-vfw.h" +#endif #endif