/************************************************************************************ * 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. ************************************************************************************/ /* enable files > 2GB on 32 bit systems */ #define _LARGEFILE64_SOURCE 1 #define _FILE_OFFSET_BITS 64 #include #include #include #include #ifdef BUILD_WINDOWS #include #include #include #else #include #endif #include #include "configuration.h" #include "videodev-dumpfile.h" VideoDev_Dumpfile::VideoDev_Dumpfile() { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); filesize = 0; filepos = 0; 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))) { #ifndef BUILD_WINDOWS if (de->d_type & DT_REG) { #endif 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); } #ifndef BUILD_WINDOWS } #endif } closedir(dir); return 1; } /* * Open Device * prepare the buffer, InitMMAP and read all controls */ int VideoDev_Dumpfile::Open() { if (config.readdumppath == NULL) return VDEV_STATUS_ERROR; VideoDevCtrl vctl; uint32_t inbuf[3]; int i; struct stat s; std::string fname = config.readdumppath; fname = fname + "/" + conf_device; printf ("%s:%d %s file %s\n", __FILE__, __LINE__, __FUNCTION__, fname.c_str()); if (fd >= 0) close (fd); fd = -1; // // read filesize if (stat (fname.c_str(), &s) != 0) { printf ("%s:%d %s could not read stat of file '%s'. Error:%s\n", __FILE__, __LINE__, __FUNCTION__, fname.c_str(), strerror(errno)); Close(); return VDEV_STATUS_ERROR; } filesize = s.st_size; #ifdef BUILD_WINDOWS if ((fd = open(fname.c_str(), O_RDONLY | O_BINARY)) == -1) { #else if ((fd = open(fname.c_str(), O_RDONLY)) == -1) { #endif 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; filepos = 12; conf_width = w = ntohl(inbuf[i++]); conf_height = h = ntohl(inbuf[i++]); pixformat = ntohl(inbuf[i++]); conf_format = convert_from_pixelformat (pixformat); vidctrls.clear(); vctl.name = "FilePosition"; vctl.id = 1; vctl.min = 0; vctl.max = 255; vctl.value = 0; vidctrls.push_back(vctl); 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; filesize = 0; filepos = 0; } 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); pixelformat = 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; } 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. */ #define SIZE_FRAMEHEADER 8 #define SIZE_DUMPHEADER 12 int VideoDev_Dumpfile::Grab(VideoFrameRaw *vf) { struct timeval curtv; unsigned int diff = 0; std::list::iterator ctrl; 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); // if (diff - inframe_nexttime > 1000) // printf ("%s:%d time difference to big. (%dms) Maybe to slow hard drive?\n", // __FILE__, __LINE__, (diff - inframe_nexttime)); LockMutex(); vf->CopyFrom(pixformat, w, h, inframe_size, inframe); ctrl = vidctrls.begin(); if (ctrl->value == 0) { // fixed framesize -> calculate frames switch (pixformat) { case(V4L2_PIX_FMT_RGB24): case(V4L2_PIX_FMT_BGR24): fixedframesize = 3 * w * h; break; case(V4L2_PIX_FMT_RGB32): case(V4L2_PIX_FMT_BGR32): fixedframesize = 4 * w * h; break; case(V4L2_PIX_FMT_SGRBG8): fixedframesize = 2 * w * h; break; case(V4L2_PIX_FMT_SGRBG16): fixedframesize = 4 * w * h; break; default: ctrl->max = 0; ctrl->value = -1; fixedframesize = 0; break; } if (fixedframesize > 0) ctrl->max = (filesize-SIZE_DUMPHEADER) / (fixedframesize + SIZE_FRAMEHEADER); } if (ctrl->value != -1) ctrl->value++; 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; // // check position, if end of file restart from beginning if (filepos == filesize) { printf ("%s:%d end of file start with first frame\n", __FILE__, __LINE__); if (lseek(fd, 12, SEEK_SET) != 12) { printf ("%s:%d %s lseek returned: %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno)); Close(); } else { // reset filepos and starttime filepos = 12; gettimeofday(&starttv, NULL); } } // // read frame if (read (fd, inbuf, 4*2) != 4*2) { printf ("%s:%d could not read frame header: %s\n", __FILE__, __LINE__, strerror(errno)); Close(); } filepos += (4*2); 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: %s\n", __FILE__, __LINE__, strerror(errno)); Close(); } filepos += inframe_size; return VDEV_STATUS_OK; } /***************************************************************************************************** * Controls */ /* * set video control identified by id */ int VideoDev_Dumpfile::SetDevCtrl(unsigned int id, int value) { std::list::iterator ctrl; printf ("%s:%d VideoDev_Dumpfile::SetDevCtrl Set Offset to %d id:%d\n", __FILE__, __LINE__, value, id); if (id == 1) { ctrl = vidctrls.begin(); if (value != ctrl->value && value < ctrl->max) { ctrl->value = value; lseek (fd, SEEK_SET, SIZE_DUMPHEADER + (value * (SIZE_FRAMEHEADER + fixedframesize))); } } return VDEV_STATUS_OK; }; /* * get video control identified by id */ int VideoDev_Dumpfile::GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; };