diff --git a/Makefile b/Makefile index cbf7f1c..b5505b9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,10 @@ APP = simpleskycam -include Makefile.rules -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 ser.oo +OBJECTS := $(OBJECTS) gui.oo main.oo \ + video.oo videoframe.oo \ + videodev.oo videodev-v4l2.oo videodev-dumpfile.oo \ + convert.oo filter.oo detect.oo json.oo configuration.oo ser.oo DISTNAME=simpleskycam-$(VERSION) diff --git a/configuration.cc b/configuration.cc index 80ad0ee..0b93220 100644 --- a/configuration.cc +++ b/configuration.cc @@ -11,6 +11,8 @@ extern GtkBuilder *_builder_; // work around for threads Configuration::Configuration() { + debugpath = NULL; + readdumppath = NULL; }; diff --git a/configuration.h b/configuration.h index 4ab4c4f..20e07dc 100644 --- a/configuration.h +++ b/configuration.h @@ -8,7 +8,7 @@ #include #include -#include "video.h" +#include "videodev.h" #include "json.h" #define CONFIGURATION_DEFAULTFILE ".simpleskycam.config" @@ -20,6 +20,9 @@ private: std::string GetDefaultFileName(); list presetbtn[BTN_PRESET_MAX]; public: + char *debugpath; + char *readdumppath; + Configuration(); ~Configuration(); @@ -33,6 +36,6 @@ public: list GetPresetButton (int btn); }; -extern char *debugpath; +extern Configuration config; #endif diff --git a/convert.cc b/convert.cc index 3181ed9..18fc44a 100644 --- a/convert.cc +++ b/convert.cc @@ -54,7 +54,7 @@ int convert_debug_open(uint32_t pixelformat, int srcw, int srch) { char fname[LEN_FILENAME]; char fullfname[LEN_FULLFILENAME]; - if (debugpath == NULL) return -1; + if (config.debugpath == NULL) return -1; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); @@ -62,14 +62,14 @@ int convert_debug_open(uint32_t pixelformat, int srcw, int srch) { // check to create file, if not possible try creating the directory and create the file again tmptr = localtime(&t); strftime(fname, LEN_FILENAME, "%F-%R", tmptr); - snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", debugpath, fname); + snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", config.debugpath, fname); if ((convert_debug_fd = creat (fullfname, 0666)) == -1) { printf ("%s:%d could not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno)); printf ("%s:%d try to create folder\n", __FILE__, __LINE__); // create folder - if ((mkdir (debugpath, 0777)) == -1) { + if ((mkdir (config.debugpath, 0777)) == -1) { printf ("%s:%d could not create debug folder.\n", __FILE__, __LINE__); return -1; } @@ -107,7 +107,7 @@ void convert_debug_dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelf uint32_t wsize; if (ptrsrc == NULL) return; - if (debugpath == NULL) return; + if (config.debugpath == NULL) return; if (convert_debug_fd == -1) if (convert_debug_open(pixelformat, srcw, srch) == -1) return; @@ -215,7 +215,7 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr unsigned char cb, cr, y1; unsigned char *ptrdst = NULL; - if (debugpath != NULL) convert_debug_dumpframe(ptrsrc, srcsize, pixelformat, srcw, srch); + if (config.debugpath != NULL) convert_debug_dumpframe(ptrsrc, srcsize, pixelformat, srcw, srch); struct jpg_error_mgr jerr; if (cdata == NULL) return VDEV_STATUS_ERROR; diff --git a/main.cc b/main.cc index a2893d2..d3d3363 100644 --- a/main.cc +++ b/main.cc @@ -22,8 +22,6 @@ GtkBuilder *_builder_ = NULL; // work around for the thread situation Filter filter; Detect detect; Configuration config; -char *debugpath = NULL; -char *readdumppath = NULL; int main (int argc, char **argv) { GtkBuilder *builder; @@ -48,15 +46,15 @@ int main (int argc, char **argv) { for (int i = 1; i < argc; i++) { if (strcmp (argv[i], "-d") == 0) { i++; - debugpath = argv[i]; + config.debugpath = argv[i]; } if (strcmp (argv[i], "-dd") == 0) { i++; - debugpath = NULL; + config.debugpath = NULL; } if (strcmp (argv[i], "-rd") == 0) { i++; - readdumppath = argv[i]; + config.readdumppath = argv[i]; } } diff --git a/video.cc b/video.cc index af18d23..68fd798 100644 --- a/video.cc +++ b/video.cc @@ -15,12 +15,6 @@ #include "configuration.h" #include "video.h" #include "videodev.h" -#include "videodev-v4l2.h" - -#ifdef USE_SVBONY -#include "videodev-svbcam.h" -#endif - VideoDev *videodev = NULL; @@ -319,10 +313,10 @@ void cb_video_btnrefreshlist (GtkWidget *widget, gpointer data) { devlist.clear(); - VideoDev vdef1; vdef1.GetDeviceList(&devlist); - VideoDev_V4L2 vdef2; vdef2.GetDeviceList(&devlist); + VideoDev_Dumpfile vdef1; vdef1.GetDeviceList(&devlist); + VideoDev_V4L2 vdef2; vdef2.GetDeviceList(&devlist); #ifdef USE_SVBONY - VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist); + VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist); #endif for (iter = devlist.begin(); iter != devlist.end(); iter++) { @@ -369,7 +363,7 @@ void cb_video_btnrec (GtkWidget *widget, gpointer data) { #ifdef USE_SVBONY else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; #endif - else if (driver.compare("DUMMY") == 0) videodev = new VideoDev; + else if (driver.compare("VIDEODUMP") == 0) videodev = new VideoDev_Dumpfile; else videodev = new VideoDev; std::string format = gtk_entry_get_text(GTK_ENTRY(cbfmtentry)); diff --git a/video.h b/video.h index b89af88..6c153c2 100644 --- a/video.h +++ b/video.h @@ -18,7 +18,6 @@ #include "gui.h" #include "config.h" #include "videoframe.h" -#include "videodev.h" extern void videoframe_to_pixbuf(GdkPixbuf* dest, VideoFrame *src); diff --git a/videodev-dummy.h b/videodev-dummy.h index 4a2f14b..b3c51ae 100644 --- a/videodev-dummy.h +++ b/videodev-dummy.h @@ -1,6 +1,6 @@ -#ifndef _H_VIDEODEV_V4L2_H_ -#define _H_VIDEODEV_V4L2_H_ +#ifndef _H_VIDEODEV_DUMPFILE_H_ +#define _H_VIDEODEV_DUMPFILE_H_ #include #include @@ -26,14 +26,6 @@ #include "gui.h" #include "videodev.h" - -enum { - IOMODE_READ, - IOMODE_MMAP -}; - - - class VideoDev_Dummy: public VideoDev { private: ConvertData cdata; diff --git a/videodev-dumpfile.cc b/videodev-dumpfile.cc new file mode 100644 index 0000000..3a8f97a --- /dev/null +++ b/videodev-dumpfile.cc @@ -0,0 +1,274 @@ +/************************************************************************************ + * videodev-dumpfile: + * raw videodump input file support. It will scan the directory givin by the command + * line argument -rd DIRECTORY and for each it will create an own device. This file + * will be read in a loop. + * + * This is needed only for debugging. + ************************************************************************************/ + +#include +#include +#include +#include +#include + + +#include "convert.h" +#include "configuration.h" +#include "videodev-dumpfile.h" + +VideoDev_Dumpfile::VideoDev_Dumpfile() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + fd = -1; + w = 0; + h = 0; + pixformat = 0; + inframe = NULL; + inframe_size = 0; + inframe_maxsize = 0; + inframe_nexttime = 0; +}; + + +VideoDev_Dumpfile::~VideoDev_Dumpfile() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (running > 0) CaptureStop(); + Close(); +} + + + +/* + * searchs in the given path for any videodump files and present them as + * video device. + */ +int VideoDev_Dumpfile::GetDeviceList(std::list *list) { + std::string device; + DIR *dir; + struct dirent *de = NULL; + char fname[256]; + int i; + + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + if (list == NULL || config.readdumppath == NULL) return 0; + + if ((dir = opendir (config.readdumppath)) == NULL) { + printf ("%s:%d could not read directory '%s'\n", __FILE__, __LINE__, config.readdumppath); + return 0; + } + + while ((de = readdir (dir))) { + if (de->d_type & DT_REG) { + for (i = 0; i < 255 && de->d_name[i] != 0; i++) fname[i] = toupper(de->d_name[i]); + fname[i] = 0; + if (strstr (fname, ".VIDEODUMP") != NULL) { + device = (std::string) "VIDEODUMP " + (std::string) de->d_name; + list->push_back(device); + } + } + } + + closedir(dir); + + return 1; +} + + + +/* + * Open Device + * prepare the buffer, InitMMAP and read all controls + */ +int VideoDev_Dumpfile::Open() { + std::string fname = config.readdumppath; + fname = fname + "/" + conf_device; + + uint32_t inbuf[3]; + int i; + + printf ("%s:%d %s file %s\n", __FILE__, __LINE__, __FUNCTION__, fname.c_str()); + + if (fd >= 0) close (fd); + + if ((fd = open(fname.c_str(), O_RDONLY)) == -1) { + printf ("%s:%d could not open file '%s' error:%s\n", __FILE__, __LINE__, fname.c_str(), strerror(errno)); + return VDEV_STATUS_ERROR; + } + + // + // read header + if (read (fd, inbuf, 12) != 12) { + printf ("%s:%d could not read all header data.\n", __FILE__, __LINE__); + close (fd); + fd = -1; + return VDEV_STATUS_ERROR; + } + i = 0; + w = ntohl(inbuf[i++]); + h = ntohl(inbuf[i++]); + pixformat = ntohl(inbuf[i++]); + + return VDEV_STATUS_OK; +}; + + +/* + * Close Device + * Free videobuffer + */ +int VideoDev_Dumpfile::Close() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + if (fd >= 0) { + close(fd); + fd = -1; + } + + return VDEV_STATUS_OK; +}; + + + +/***************************************************************************************************** + * VideoGrabbing + */ + + +/* + * send the start capture signal to the cam + */ +int VideoDev_Dumpfile::CaptureStart() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + Close(); + if (Open() != VDEV_STATUS_OK) return VDEV_STATUS_ERROR; + + // read timestamp and first header and frame + gettimeofday(&starttv, NULL); + + ConvertStart(&cdata, pixformat); + ReadFrame(); + + return VDEV_STATUS_OK; +}; + + +int VideoDev_Dumpfile::CaptureStop() { + printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); + + if (fd >= 0) { + close(fd); + fd = -1; + } + + if (inframe != NULL) { + free (inframe); + inframe_size = 0; + inframe = NULL; + } + + ConvertStop(&cdata, pixformat); + + 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_Dumpfile::Grab(VideoFrame *vf) { + struct timeval curtv; + unsigned int diff = 0; + + if (fd == -1) return VDEV_STATUS_ERROR; + + // + // is it time? + do { + gettimeofday(&curtv, NULL); + diff = 1000 * (curtv.tv_sec - starttv.tv_sec) + + (curtv.tv_usec - starttv.tv_usec) / 1000; + + if (diff < inframe_nexttime) + usleep ((inframe_nexttime-diff)*1000); + } while (diff < inframe_nexttime); + + LockMutex(); + Convert(&cdata, vf, inframe, inframe_size, pixformat, w, h); + UnLockMutex(); + + // + // read next frame + ReadFrame(); + + return VDEV_STATUS_OK; +} + + +/***************************************************************************************************** + * Read Frame + */ +int VideoDev_Dumpfile::ReadFrame() { + uint32_t inbuf[2]; + + if (fd < 0) return VDEV_STATUS_ERROR; + + // read header + if (read (fd, inbuf, 4*2) != 4*2) { + printf ("%s:%d could not read frame header\n", __FILE__, __LINE__); + Close(); + } + inframe_size = ntohl(inbuf[0]); + inframe_nexttime = ntohl(inbuf[1]); + + // read header + if (inframe == NULL) { + inframe = (unsigned char*) malloc (inframe_size); + inframe_maxsize = inframe_size; + } + else if (inframe_maxsize < inframe_size) { + inframe = (unsigned char*) realloc (inframe, inframe_size); + inframe_maxsize = inframe_size; + } + + // allocate memory and read frame + if (inframe == NULL) { + Close(); + printf ("%s:%d cloud not allocate enought memory\n", __FILE__, __LINE__); + return VDEV_CBSTATUS_ERROR; + } + + if (read (fd, inframe, inframe_size) != inframe_size) { + printf ("%s:%d could not read frame\n", __FILE__, __LINE__); + Close(); + } + + return VDEV_STATUS_OK; +} + + + +/***************************************************************************************************** + * Controls + */ + +/* + * set video control identified by id + */ +int VideoDev_Dumpfile::SetDevCtrl(unsigned int id, int value) { + return VDEV_STATUS_OK; +}; + + +/* + * get video control identified by id + */ +int VideoDev_Dumpfile::GetDevCtrl(unsigned int id, int *value) { + return VDEV_STATUS_OK; +}; + + diff --git a/videodev-dumpfile.h b/videodev-dumpfile.h new file mode 100644 index 0000000..4f9396d --- /dev/null +++ b/videodev-dumpfile.h @@ -0,0 +1,60 @@ + +#ifndef _H_VIDEODEV_DUMPFILE_H_ +#define _H_VIDEODEV_DUMPFILE_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_Dumpfile: public VideoDev { +private: + ConvertData cdata; + int fd; + uint32_t w; + uint32_t h; + uint32_t pixformat; + struct timeval starttv; + unsigned char *inframe; + uint32_t inframe_nexttime; + int inframe_maxsize; + int inframe_size; + + 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); + + int ReadFrame(); +public: + VideoDev_Dumpfile(); + ~VideoDev_Dumpfile(); + int GetDeviceList(std::list *list); + int GetDeviceFormats(string device, std::list *formats) { return VDEV_STATUS_OK; }; + int GetDeviceResolutions(string device, std::list *formats) { return VDEV_STATUS_OK; }; +}; + +#endif diff --git a/videodev.h b/videodev.h index 4287128..a53ef01 100644 --- a/videodev.h +++ b/videodev.h @@ -13,6 +13,7 @@ #include "json.h" #include "gui.h" #include "config.h" +#include "convert.h" #include "video.h" #include "videoframe.h" @@ -119,6 +120,7 @@ private: /* read a value from the control */ virtual int GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; }; + friend class VideoDev_Dumpfile; friend class VideoDev_V4L2; #ifdef USE_SVBONY friend class VideoDev_SVBCam; @@ -152,4 +154,10 @@ public: }; +#include "videodev-v4l2.h" +#include "videodev-dumpfile.h" +#ifdef USE_SVBONY +#include "videodev-svbcam.h" +#endif + #endif