You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SimpleSkyCam/videodev-dumpfile.cc

383 lines
8.6 KiB

/************************************************************************************
* 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 <sys/types.h>
#include <dirent.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef BUILD_WINDOWS
#include <winsock2.h>
#include <io.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
#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<std::string> *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<VideoDevCtrl>::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__);
std::list<VideoDevCtrl>::iterator ctrl;
ctrl = vidctrls.begin();
ctrl->value = 0;
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<VideoDevCtrl>::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;
};