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.
859 lines
19 KiB
859 lines
19 KiB
|
|
#define _LARGEFILE64_SOURCE 1
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
|
|
#include "miniwebcam.h"
|
|
#include "video.h"
|
|
#include "convert.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#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>
|
|
|
|
|
|
|
|
VideoDevice::VideoDevice() {
|
|
debug ("");
|
|
};
|
|
|
|
|
|
VideoDevice::~VideoDevice() {
|
|
debug ("");
|
|
};
|
|
|
|
/*********************************************************************************************************/
|
|
|
|
VideoDevice_V4L2::VideoDevice_V4L2() {
|
|
debug ("");
|
|
conf_height = 0;
|
|
conf_width = 0;
|
|
conf_videodev = "";
|
|
conf_iomode = 0;
|
|
conf_videofmt = 0;
|
|
fd = -1;
|
|
};
|
|
|
|
|
|
VideoDevice_V4L2::~VideoDevice_V4L2() {
|
|
debug ("");
|
|
if (fd != 0) Stop();
|
|
};
|
|
|
|
|
|
|
|
int VideoDevice_V4L2::SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) {
|
|
int isrunning = 0;
|
|
|
|
if (fd != -1) {
|
|
Stop();
|
|
isrunning = 1;
|
|
}
|
|
|
|
conf_videodev = newdevice;
|
|
conf_width = nwidth;
|
|
conf_height = nheight;
|
|
conf_videofmt = pixfmt;
|
|
|
|
if (isrunning) {
|
|
if (Start() == 0) return 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::SetIOMode(int newiomode) {
|
|
int isrunning = 0;
|
|
|
|
if (fd != -1) {
|
|
Stop();
|
|
isrunning = 1;
|
|
}
|
|
|
|
conf_iomode = newiomode;
|
|
|
|
if (isrunning) {
|
|
if (Start() == 0) return 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::Open() {
|
|
int i;
|
|
struct v4l2_capability vcap;
|
|
VideoDevCtrl vctl;
|
|
|
|
debug ("Device: '%s'", conf_videodev.c_str());
|
|
if (fd != -1) return 0;
|
|
|
|
//
|
|
// open device and get device name and capabilities | O_NONBLOCK
|
|
if((fd = open(conf_videodev.c_str(), O_RDWR)) == -1){
|
|
debug ("could not open 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);
|
|
|
|
debug ("Capabilities: %u", vcap.capabilities);
|
|
PrintCaps(vcap.capabilities);
|
|
debug ("Device Capabilities: %u", vcap.device_caps);
|
|
PrintCaps(vcap.device_caps);
|
|
|
|
if (!(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
|
debug ("Error: device has no video capture capabilities");
|
|
return 0;
|
|
Close();
|
|
}
|
|
|
|
//
|
|
// query controls
|
|
struct v4l2_queryctrl queryctrl;
|
|
uint32_t min;
|
|
debug ("Get Controls");
|
|
|
|
vidctrls.clear();
|
|
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)) {
|
|
vctl.name = (char*)queryctrl.name;
|
|
vctl.id = queryctrl.id;
|
|
vctl.min = queryctrl.minimum;
|
|
vctl.max = queryctrl.maximum;
|
|
GetDevCtrl(queryctrl.id, &vctl.value);
|
|
vidctrls.push_back(vctl);
|
|
}
|
|
}
|
|
debug ("got %d controls.", vidctrls.size());
|
|
|
|
//
|
|
// check for cropping.. if we have it setup default
|
|
debug ("setup cropping");
|
|
CLEAR (cropcap);
|
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
|
|
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
crop.c = cropcap.defrect; // reset to default
|
|
|
|
if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) {
|
|
debug ("VIDEOC_S_CROP Errorcode: %s", strerror(errno));
|
|
}
|
|
}
|
|
|
|
//
|
|
// prepare resolution and pixelformat
|
|
debug ("setup video resolution and pixeltype");
|
|
CLEAR (fmt);
|
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (conf_width != -1 && conf_height != -1) { // resolution
|
|
fmt.fmt.pix.width = conf_width;
|
|
fmt.fmt.pix.height = conf_height;
|
|
}
|
|
else {
|
|
fmt.fmt.pix.width = 1920;
|
|
fmt.fmt.pix.height = 1080;
|
|
}
|
|
|
|
// fixme: hardcoded video format?????
|
|
fmt.fmt.pix.pixelformat = conf_videofmt;
|
|
fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
|
if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {
|
|
debug ("VIDIOC_S_FMT : %s", strerror (errno));
|
|
close (fd);
|
|
fd = -1;
|
|
return 0;
|
|
}
|
|
|
|
// Note VIDIOC_S_FMT may change width and height.
|
|
// Buggy driver paranoia. - as written in the v4l2 api documentation
|
|
min = fmt.fmt.pix.width * 2;
|
|
if (fmt.fmt.pix.bytesperline < min)
|
|
fmt.fmt.pix.bytesperline = min;
|
|
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
|
if (fmt.fmt.pix.sizeimage < min)
|
|
fmt.fmt.pix.sizeimage = min;
|
|
conf_width = fmt.fmt.pix.width;
|
|
conf_height = fmt.fmt.pix.height;
|
|
conf_videofmt = fmt.fmt.pix.pixelformat;
|
|
PrintFmt (&fmt);
|
|
|
|
// init buffers
|
|
switch (conf_iomode) {
|
|
case IOMODE_MMAP:
|
|
if (InitMMap() == 0) {
|
|
debug ("could not setup MMap (memory mapping)");
|
|
Close();
|
|
}
|
|
break;
|
|
case IOMODE_READ:
|
|
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
|
inbuffer[i].size = fmt.fmt.pix.sizeimage;
|
|
inbuffer[i].data = (unsigned char*) malloc (fmt.fmt.pix.sizeimage);
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::InitMMap() {
|
|
struct v4l2_requestbuffers bufreq;
|
|
struct v4l2_buffer bufinfo;
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
int i;
|
|
|
|
CLEAR(bufreq);
|
|
CLEAR(bufinfo);
|
|
|
|
bufreq.count = VDEV_INBUFFERS;
|
|
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
bufreq.memory = V4L2_MEMORY_MMAP;
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &bufreq)) {
|
|
if (EINVAL == errno) {
|
|
printf("%s does not support memory mapping", conf_videodev.c_str());
|
|
return 0;
|
|
} else {
|
|
printf ("%s:%d %s Error %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (bufreq.count < 1) {
|
|
printf ( "Insufficient buffer memory on %s\n", conf_videodev.c_str());
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < VDEV_INBUFFERS; i++) {
|
|
CLEAR(bufinfo);
|
|
bufinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
bufinfo.memory = V4L2_MEMORY_MMAP;
|
|
bufinfo.index = i;
|
|
|
|
if(ioctl(fd, VIDIOC_QUERYBUF, &bufinfo) < 0){
|
|
perror("VIDIOC_QUERYBUF");
|
|
exit(1);
|
|
}
|
|
|
|
inbuffer[i].size = bufinfo.length;
|
|
inbuffer[i].data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, fd, bufinfo.m.offset);
|
|
if (inbuffer[i].data == MAP_FAILED) {
|
|
printf ( "%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno));
|
|
exit (1);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
int VideoDevice_V4L2::Close() {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (fd >= 0) {
|
|
UnInit();
|
|
close (fd);
|
|
fd = -1;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::UnInit() {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
switch (conf_iomode) {
|
|
case IOMODE_READ:
|
|
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
|
if (inbuffer[inbuffer_idx].data) {
|
|
free (inbuffer[inbuffer_idx].data);
|
|
inbuffer[inbuffer_idx].data = NULL;
|
|
inbuffer[inbuffer_idx].size = 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case IOMODE_MMAP:
|
|
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++)
|
|
if (inbuffer[inbuffer_idx].data) {
|
|
if (-1 == munmap(inbuffer[inbuffer_idx].data, inbuffer[inbuffer_idx].size)){
|
|
fprintf(stderr, "Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
exit(1);
|
|
}
|
|
inbuffer[inbuffer_idx].data = NULL;
|
|
inbuffer[inbuffer_idx].size = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::Start() {
|
|
enum v4l2_buf_type type;
|
|
|
|
debug ("V4L2");
|
|
|
|
if (Open() == 0) {
|
|
debug ("VideoDevice_V4L2::Start Open Device Failed.");
|
|
return 0;
|
|
}
|
|
|
|
switch (conf_iomode) {
|
|
case IOMODE_READ:
|
|
/* Nothing to do. */
|
|
break;
|
|
|
|
case IOMODE_MMAP:
|
|
struct v4l2_buffer buf;
|
|
|
|
for (inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
|
CLEAR(buf);
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
buf.index = inbuffer_idx;
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
debug ("error on VIDIOC_QBUF %s", strerror(errno));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
inbuffer_idx = 0;
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) {
|
|
debug ("VIDIOC_STREAMON %s", strerror(errno));
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
debug ("wrong IOMODE?");
|
|
return 0;
|
|
}
|
|
|
|
ConvertStart(&cdata, fmt.fmt.pix.pixelformat);
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::Stop() {
|
|
enum v4l2_buf_type type;
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
ConvertStop(&cdata, fmt.fmt.pix.pixelformat);
|
|
|
|
switch (conf_iomode) {
|
|
case IOMODE_READ:
|
|
/* Nothing to do. */
|
|
break;
|
|
case IOMODE_MMAP:
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) {
|
|
fprintf(stderr, "%s:%d VIDIOC_STREAMOFF Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
return 0;
|
|
}
|
|
Close();
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::GetFrame(VideoFrame *destframe) {
|
|
struct v4l2_buffer buf;
|
|
int len;
|
|
|
|
if (destframe == NULL) return 0;
|
|
|
|
switch (conf_iomode) {
|
|
case IOMODE_READ:
|
|
if ((len = read (fd, inbuffer[0].data, fmt.fmt.pix.sizeimage)) == -1) {
|
|
switch (errno) {
|
|
case EAGAIN:
|
|
return -1;
|
|
case EIO:
|
|
default:
|
|
debug ("v4l2_grab IOM_READ: %s dest:%p size:%d", strerror (errno), destframe, fmt.fmt.pix.sizeimage);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
Convert(&cdata, destframe, inbuffer[0].data, len,
|
|
fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
}
|
|
break;
|
|
|
|
case IOMODE_MMAP:
|
|
CLEAR(buf);
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
|
|
switch (errno) {
|
|
case EAGAIN:
|
|
return -1;
|
|
|
|
case EIO:
|
|
debug ("error on VIDIOC_DQBUF EIO %s", strerror(errno));
|
|
return 0;
|
|
|
|
default:
|
|
debug ("error on VIDIOC_DQBUF %s", strerror(errno));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
|
|
Convert(&cdata, destframe, inbuffer[buf.index].data, buf.bytesused,
|
|
fmt.fmt.pix.pixelformat, fmt.fmt.pix.width, fmt.fmt.pix.height);
|
|
}
|
|
|
|
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
|
debug ("error on VIDIOC_QBUF %s", strerror(errno));
|
|
return 0; }
|
|
|
|
if (++inbuffer_idx >= VDEV_INBUFFERS) inbuffer_idx = 0;
|
|
break;
|
|
|
|
default:
|
|
debug ("wrong IOMODE?");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::xioctl(int fd, int request, void *arg) {
|
|
int r;
|
|
int errnoioctl;
|
|
struct timeval to1;
|
|
struct timeval to2;
|
|
float to;
|
|
|
|
gettimeofday(&to1, NULL);
|
|
do {
|
|
r = ioctl(fd, request, arg);
|
|
errnoioctl = errno;
|
|
gettimeofday(&to2, NULL);
|
|
to = (float)(to2.tv_sec - to1.tv_sec) + ((to2.tv_usec - to1.tv_usec) / 1000000.0);
|
|
} while (r == -1 && errnoioctl == EINTR && to < 2.0);
|
|
|
|
return r;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::SetDevCtrl(unsigned int id, int value) {
|
|
struct v4l2_control ctrl;
|
|
|
|
CLEAR(ctrl);
|
|
ctrl.id = id;
|
|
ctrl.value = value;
|
|
if (-1 == xioctl (fd, VIDIOC_S_CTRL, &ctrl)) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_V4L2::GetDevCtrl(unsigned int id, int *value) {
|
|
struct v4l2_control ctrl;
|
|
|
|
CLEAR(ctrl);
|
|
ctrl.id = id;
|
|
if (-1 == xioctl (fd, VIDIOC_G_CTRL, &ctrl)) {
|
|
return 0;
|
|
}
|
|
*value = ctrl.value;
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
void VideoDevice_V4L2::PrintCaps(uint32_t caps) {
|
|
printf ("%s:%d %s Caps: %x\n", __FILE__, __LINE__, __FUNCTION__, caps);
|
|
|
|
if (caps & V4L2_CAP_VIDEO_CAPTURE) printf (" V4L2_CAP_VIDEO_CAPTURE\n");
|
|
if (caps & V4L2_CAP_EXT_PIX_FORMAT) printf (" V4L2_CAP_EXT_PIX_FORMAT\n");
|
|
#ifdef V4L2_CAP_META_CAPTURE
|
|
if (caps & V4L2_CAP_META_CAPTURE) printf (" V4L2_CAP_META_CAPTURE\n");
|
|
#endif
|
|
if (caps & V4L2_CAP_STREAMING) printf (" V4L2_CAP_STREAMING\n");
|
|
if (caps & V4L2_CAP_DEVICE_CAPS) printf (" V4L2_CAP_DEVICE_CAPS\n");
|
|
if (caps & V4L2_CAP_TUNER) printf (" V4L2_CAP_TUNER\n");
|
|
if (caps & V4L2_CAP_MODULATOR) printf (" V4L2_CAP_MODULATOR\n");
|
|
if (caps & V4L2_CAP_READWRITE) printf (" V4L2_CAP_READWRITE\n");
|
|
if (caps & V4L2_CAP_ASYNCIO) printf (" V4L2_CAP_ASYNCIO\n");
|
|
};
|
|
|
|
|
|
void VideoDevice_V4L2::PrintFmt(struct v4l2_format *f) {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
printf (" type : %u\n", f->type);
|
|
printf (" fmt.pix.width : %d\n", f->fmt.pix.width);
|
|
printf (" fmt.pix.height : %d\n", f->fmt.pix.height);
|
|
printf (" fmt.fmt.pix.pixelformat : %c%c%c%c\n", ((char*)&f->fmt.pix.pixelformat)[0],
|
|
((char*)&f->fmt.pix.pixelformat)[1],
|
|
((char*)&f->fmt.pix.pixelformat)[2],
|
|
((char*)&f->fmt.pix.pixelformat)[3]);
|
|
printf (" fmt.pix.field : %d\n", f->fmt.pix.field);
|
|
printf (" fmt.pix.bytesperline : %d\n", f->fmt.pix.bytesperline);
|
|
printf (" fmt.pix.sizeimage : %d\n", f->fmt.pix.sizeimage);
|
|
};
|
|
|
|
|
|
/*********************************************************************************************************/
|
|
|
|
VideoDevice_Dump::VideoDevice_Dump() {
|
|
debug ("");
|
|
filesize = 0;
|
|
filepos = 0;
|
|
fd = -1;
|
|
w = 0;
|
|
h = 0;
|
|
pixformat = 0;
|
|
inframe = NULL;
|
|
inframe_size = 0;
|
|
inframe_maxsize = 0;
|
|
inframe_nexttime = 0;
|
|
fixedframesize = 0;
|
|
};
|
|
|
|
|
|
VideoDevice_Dump::~VideoDevice_Dump() {
|
|
debug ("");
|
|
Stop();
|
|
Close();
|
|
};
|
|
|
|
|
|
//
|
|
// Open Device
|
|
// prepare the buffer, InitMMAP and read all controls
|
|
//
|
|
int VideoDevice_Dump::Open() {
|
|
debug ("OPEN");
|
|
if (config.vdev_device == "") return 0;
|
|
|
|
VideoDevCtrl vctl;
|
|
uint32_t inbuf[3];
|
|
int i;
|
|
struct stat s;
|
|
|
|
std::string fname = config.vdev_dumpfile;
|
|
|
|
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 0;
|
|
}
|
|
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 0;
|
|
}
|
|
|
|
//
|
|
// 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 0;
|
|
}
|
|
i = 0;
|
|
filepos = 12;
|
|
conf_width = w = ntohl(inbuf[i++]);
|
|
conf_height = h = ntohl(inbuf[i++]);
|
|
conf_videofmt = ntohl(inbuf[i++]);
|
|
|
|
vidctrls.clear();
|
|
vctl.name = "FilePosition";
|
|
vctl.id = 1;
|
|
vctl.min = 0;
|
|
vctl.max = 255;
|
|
vctl.value = 0;
|
|
vidctrls.push_back(vctl);
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
//
|
|
// Close Device
|
|
// Free videobuffer
|
|
//
|
|
int VideoDevice_Dump::Close() {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
if (fd >= 0) {
|
|
close(fd);
|
|
fd = -1;
|
|
filesize = 0;
|
|
filepos = 0;
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// send the start capture signal to the cam
|
|
//
|
|
int VideoDevice_Dump::Start() {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
Close();
|
|
if (Open() != 1) return 0;
|
|
gettimeofday(&starttv, NULL);
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
int VideoDevice_Dump::Stop() {
|
|
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 1;
|
|
};
|
|
|
|
//
|
|
// 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 VideoDevice_Dump::GetFrame(VideoFrame *destframe) {
|
|
struct timeval curtv;
|
|
unsigned int diff = 0;
|
|
std::list<VideoDevCtrl>::iterator ctrl;
|
|
|
|
if (fd == -1) return 0;
|
|
|
|
//
|
|
// 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);
|
|
|
|
ReadFrame();
|
|
Convert(&cdata, destframe, inframe, inframe_size,
|
|
conf_videofmt, w, h);
|
|
|
|
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 = 1 * w * h;
|
|
break;
|
|
case(V4L2_PIX_FMT_SGRBG16):
|
|
fixedframesize = 2 * 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++;
|
|
|
|
ReadFrame();
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Read Frame
|
|
//
|
|
int VideoDevice_Dump::ReadFrame() {
|
|
uint32_t inbuf[2];
|
|
|
|
if (fd < 0) return 0;
|
|
|
|
//
|
|
// 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 could not allocate enough memory\n", __FILE__, __LINE__);
|
|
return 0;
|
|
}
|
|
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 1;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// set video control identified by id
|
|
//
|
|
int VideoDevice_Dump::SetDevCtrl(unsigned int id, int value) {
|
|
std::list<VideoDevCtrl>::iterator ctrl;
|
|
int framerest;
|
|
off_t newfilepos = 0;
|
|
printf ("%s:%d VideoDev_Dumpfile::SetDevCtrl Set Offset to %d id:%d fixedframesize:%d\n", __FILE__, __LINE__, value, id, fixedframesize);
|
|
struct timeval curtv;
|
|
|
|
if (id == 1) {
|
|
ctrl = vidctrls.begin();
|
|
if (value != ctrl->value && value < ctrl->max) {
|
|
filepos = SIZE_DUMPHEADER + ((off_t)value * (SIZE_FRAMEHEADER + (off_t)fixedframesize));
|
|
printf ("%s:%d filepos:%ld\n", __FILE__, __LINE__, filepos);
|
|
|
|
if ((newfilepos = lseek (fd, filepos, SEEK_SET)) < 0) {
|
|
printf ("%s:%d ******* lseek error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
}
|
|
else {
|
|
framerest = (newfilepos - SIZE_DUMPHEADER)%(SIZE_FRAMEHEADER + fixedframesize);
|
|
ctrl->value = (newfilepos - SIZE_DUMPHEADER)/(SIZE_FRAMEHEADER + fixedframesize);
|
|
if (ctrl->value != value || framerest != 0) {
|
|
printf ("%s:%d could not set file to correct position. ctrl->value:%d value:%d Framerest:%d\n", __FILE__, __LINE__, ctrl->value, value, framerest);
|
|
}
|
|
else {
|
|
//
|
|
// read first frame
|
|
ReadFrame();
|
|
gettimeofday(&curtv, NULL);
|
|
starttv.tv_sec = curtv.tv_sec - (inframe_nexttime/1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// else printf ("%s:%d could not set video position (ctrl->value:%d value:%d max:%d)\n",
|
|
// __FILE__, __LINE__, ctrl->value, value, ctrl->max);
|
|
}
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
//
|
|
// get video control identified by id
|
|
//
|
|
int VideoDevice_Dump::GetDevCtrl(unsigned int id, int *value) {
|
|
return 1;
|
|
};
|
|
|