splitting videodevices into multiple source files.

main
Steffen Pohle 3 months ago
parent 0b7a1c267e
commit faf51fc2df

@ -12,7 +12,9 @@ DEFAULT_SERVERPORT=20010
CXX=g++ CXX=g++
CXXFLAGS= -ggdb -fPIC -Wall -std=c++11 -I/usr/local/include CXXFLAGS= -ggdb -fPIC -Wall -std=c++11 -I/usr/local/include
LDFLAGS= -lUDPTCPNetwork -L/usr/local/lib -ljpeg LDFLAGS= -lUDPTCPNetwork -L/usr/local/lib -ljpeg
OBJFILES= webserver.o configuration.o main.o video.o convert.o debayer.o inmemoryfile.o videoframe.o OBJFILES= webserver.o configuration.o main.o inmemoryfile.o \
convert.o debayer.o videoframe.o \
video.o videodevice_v4l2.o videodevice_dump.o
all: dep miniwebcam all: dep miniwebcam
miniwebcam: $(OBJFILES) miniwebcam: $(OBJFILES)

@ -17,8 +17,6 @@
#include "debayer.h" #include "debayer.h"
int debayer_mode = 1; // testing 0 or 1 int debayer_mode = 1; // testing 0 or 1
int convert_debug_fd = -1;
struct timeval convert_debug_tv;
uint32_t convert_pixelformats [] = { uint32_t convert_pixelformats [] = {
V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_MJPEG,
@ -44,100 +42,6 @@ uint32_t convert_pixelformats [] = {
/* /*
* will be called on first frame * will be called on first frame
*/ */
int convert_debug_open(uint32_t pixelformat, int srcw, int srch) {
time_t t = time(NULL);
struct tm *tmptr;
char fname[LEN_FILENAME];
char fullfname[LEN_FULLFILENAME];
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
if (config.vdev_dumppath.length() == 0) return -1;
//
// check to create file, if not possible try creating the directory and create the file again
tmptr = localtime(&t);
strftime(fname, LEN_FILENAME, "%Y%m%d-%H%M%S", tmptr);
snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", config.vdev_dumppath.c_str(), 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
// FIXME: how to do thin on windows
#ifdef BUILD_WINDOWS
if ((mkdir (config.debugpath)) == -1) {
#else
if ((mkdir (config.vdev_dumppath.c_str(), 0777)) == -1) {
#endif
printf ("%s:%d could not create debug folder.\n", __FILE__, __LINE__);
return -1;
}
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
printf ("%s:%d could again not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno));
return -1;
}
}
//
// file is open for writing, write header information
uint32_t wwidth = htonl(srcw);
uint32_t wheight = htonl(srch);
uint32_t wpixfmt = htonl(pixelformat);
write (convert_debug_fd, &wwidth, 4);
write (convert_debug_fd, &wheight, 4);
write (convert_debug_fd, &wpixfmt, 4);
//
// save start time, this is needed to calculate the time between the frames
gettimeofday (&convert_debug_tv, NULL);
return 0;
}
/*
* if fd is not open open file and set up header
*/
void convert_debug_dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch) {
struct timeval tv;
uint32_t wts, ts;
uint32_t wsize;
if (ptrsrc == NULL) return;
if (config.vdev_dumppath.length() == 0) return;
if (convert_debug_fd == -1)
if (convert_debug_open(pixelformat, srcw, srch) == -1) return;
//
// construct and write header
wsize = htonl(srcsize);
gettimeofday (&tv, NULL);
ts = 1000 * (tv.tv_sec - convert_debug_tv.tv_sec) +
(tv.tv_usec - convert_debug_tv.tv_usec) / 1000;
wts = htonl(ts);
write (convert_debug_fd, &wsize, 4);
write (convert_debug_fd, &wts, 4);
//
// write frame
write (convert_debug_fd, ptrsrc, srcsize);
};
/*
* close file and reset all data
*/
void convert_debug_close() {
if (convert_debug_fd != -1) {
close (convert_debug_fd);
convert_debug_fd = -1;
}
}
// //
// jpeg: replacement for error_exit // jpeg: replacement for error_exit
@ -187,7 +91,7 @@ int ConvertStart(ConvertData *cdata, uint32_t pixelformat) {
}; };
int ConvertStop(ConvertData *cdata, uint32_t pixelformat) { int ConvertStop(ConvertData *cdata, uint32_t pixelformat) {
convert_debug_close(); dumpframe_close();
if (cdata == NULL) return 0; if (cdata == NULL) return 0;
if (pixelformat == V4L2_PIX_FMT_MJPEG) jpeg_destroy_decompress(&cdata->cinfo); if (pixelformat == V4L2_PIX_FMT_MJPEG) jpeg_destroy_decompress(&cdata->cinfo);
@ -207,7 +111,7 @@ int Convert (ConvertData *cdata, VideoFrame *dest, unsigned char *ptrsrc, int sr
unsigned char *ptrdst = NULL; unsigned char *ptrdst = NULL;
debug ("srcsize:%d pixfmt:%s size: %dx%d", srcsize, convert_from_pixelformat(pixelformat).c_str(), srcw, srch); debug ("srcsize:%d pixfmt:%s size: %dx%d", srcsize, convert_from_pixelformat(pixelformat).c_str(), srcw, srch);
if (config.vdev_dumppath.length() > 0) convert_debug_dumpframe(ptrsrc, srcsize, pixelformat, srcw, srch); if (config.vdev_dumppath.length() > 0) dumpframe(ptrsrc, srcsize, pixelformat, srcw, srch);
struct jpg_error_mgr jerr; struct jpg_error_mgr jerr;
if (cdata == NULL) return 0; if (cdata == NULL) return 0;

@ -371,10 +371,17 @@ void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h,
} }
int MAX(int a, int m) { if (a > m) return m; else return a; }; int MAX(int a, int m) { if (a > m) return m; else return a; };
#define PRGGB10P_U ((uint16_t)(*(psrc-src_w*2*10/8)))
#define PRGGB10P_D ((uint16_t)(*(psrc+src_w*2*10/8)))
#define PRGGB10P_L ((uint16_t)(*(psrc-2)*10/8))
#define PRGGB10P_R ((uint16_t)(*(psrc+2)*10/8))
#define PRGGB10P_UL ((uint16_t)(*(psrc-2-src_w*2*10/8)))
#define PRGGB10P_UR ((uint16_t)(*(psrc+2-src_w*2*10/8)))
#define PRGGB10P_DL ((uint16_t)(*(psrc-2-src_w*2*10/8)))
#define PRGGB10P_DR ((uint16_t)(*(psrc+2+src_w*2*10/8)))
void debayer_rggb10packet_simple (uint8_t * src, int src_w, int src_h, void debayer_rggb10packet_simple (uint8_t * src, int src_w, int src_h,
uint8_t * dst, int dst_w, int dst_h) { uint8_t * dst, int dst_w, int dst_h) {
/* int s, d; int s, d;
int xs, ys, xd, yd; int xs, ys, xd, yd;
unsigned char r, g, b; unsigned char r, g, b;
int max = dst_w * dst_h * 3; int max = dst_w * dst_h * 3;
@ -400,24 +407,24 @@ void debayer_rggb10packet_simple (uint8_t * src, int src_w, int src_h,
if (ys&1) { if (ys&1) {
if (xs&1) { if (xs&1) {
b = *psrc; b = *psrc;
g = (P_L + P_R + P_U + P_D)/4; g = (PRGGB10P_L + PRGGB10P_R + PRGGB10P_U + PRGGB10P_D)/4;
r = (P_UL + P_DL + P_UR + P_UL)/4; r = (PRGGB10P_UL + PRGGB10P_DL + PRGGB10P_UR + PRGGB10P_UL)/4;
} }
else { else {
b = (P_L + P_R)/2; b = (PRGGB10P_L + PRGGB10P_R)/2;
g = *psrc; g = *psrc;
r = (P_U + P_D)/2; r = (PRGGB10P_U + PRGGB10P_D)/2;
} }
} }
else { else {
if (xs&1) { if (xs&1) {
b = (P_U + P_D)/2; b = (PRGGB10P_U + PRGGB10P_D)/2;
g = *psrc; g = *psrc;
r = (P_L + P_R)/2; r = (PRGGB10P_L + PRGGB10P_R)/2;
} }
else { else {
g = (P_L + P_R + P_U + P_D)/4; g = (PRGGB10P_L + PRGGB10P_R + PRGGB10P_U + PRGGB10P_D)/4;
b = (P_UL + P_DL + P_UR + P_UL)/4; b = (PRGGB10P_UL + PRGGB10P_DL + PRGGB10P_UR + PRGGB10P_UL)/4;
r = *psrc; r = *psrc;
} }
} }
@ -440,7 +447,7 @@ void debayer_rggb10packet_simple (uint8_t * src, int src_w, int src_h,
psrc++; psrc++;
if (xs && (xs % 4 == 0)) psrc++; if (xs && (xs % 4 == 0)) psrc++;
} }
} */ }
}; };

@ -22,8 +22,6 @@
#endif #endif
#include <sys/stat.h> #include <sys/stat.h>
VideoDevice::VideoDevice() { VideoDevice::VideoDevice() {
debug (""); debug ("");
}; };
@ -33,826 +31,3 @@ VideoDevice::~VideoDevice() {
debug (""); 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;
};

@ -85,72 +85,7 @@ class VideoDevice {
virtual int GetDevCtrl(unsigned int id, int *value) { debug (""); return 0; }; virtual int GetDevCtrl(unsigned int id, int *value) { debug (""); return 0; };
}; };
#include "videodevice_v4l2.h"
#include "videodevice_dump.h"
class VideoDevice_V4L2 : public VideoDevice {
private:
int inbuffer_idx;
VideoInBuffer inbuffer[VDEV_INBUFFERS];
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
int fd; // filedescriptor to the video device file
int Open();
int Close();
int UnInit();
int InitMMap();
int xioctl(int fd, int request, void *arg);
protected:
public:
VideoDevice_V4L2();
~VideoDevice_V4L2();
int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt);
int SetIOMode(int newiomode);
int Start();
int Stop();
int GetFrame (VideoFrame *destframe);
int SetDevCtrl(unsigned int id, int value);
int GetDevCtrl(unsigned int id, int *value);
void PrintCaps(uint32_t caps);
void PrintFmt(struct v4l2_format *f);
};
class VideoDevice_Dump : public VideoDevice {
private:
int fd;
uint32_t w;
uint32_t h;
uint32_t pixformat;
off_t filesize;
off_t filepos;
struct timeval starttv;
unsigned char *inframe;
uint32_t inframe_nexttime;
int inframe_maxsize;
int inframe_size;
int fixedframesize;
int Open();
int Close();
int ReadFrame();
protected:
public:
VideoDevice_Dump();
~VideoDevice_Dump();
int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) { config.vdev_device = newdevice; return 1; };
int SetIOMode(int newiomode) { return 1; };
int Start();
int Stop();
int GetFrame (VideoFrame *destframe);
int SetDevCtrl(unsigned int id, int value);
int GetDevCtrl(unsigned int id, int *value);
};
#endif #endif

@ -0,0 +1,419 @@
#include "video.h"
#include "videoframe.h"
int convert_debug_fd = -1;
struct timeval convert_debug_tv;
int dumpframe_open(uint32_t pixelformat, int srcw, int srch) {
time_t t = time(NULL);
struct tm *tmptr;
char fname[LEN_FILENAME];
char fullfname[LEN_FULLFILENAME];
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
if (config.vdev_dumppath.length() == 0) return -1;
//
// check to create file, if not possible try creating the directory and create the file again
tmptr = localtime(&t);
strftime(fname, LEN_FILENAME, "%Y%m%d-%H%M%S", tmptr);
snprintf (fullfname, LEN_FULLFILENAME, "%s/%s.videodump", config.vdev_dumppath.c_str(), 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
// FIXME: how to do thin on windows
#ifdef BUILD_WINDOWS
if ((mkdir (config.debugpath)) == -1) {
#else
if ((mkdir (config.vdev_dumppath.c_str(), 0777)) == -1) {
#endif
printf ("%s:%d could not create debug folder.\n", __FILE__, __LINE__);
return -1;
}
if ((convert_debug_fd = creat (fullfname, 0666)) == -1) {
printf ("%s:%d could again not create file '%s'. Error:%s\n", __FILE__, __LINE__, fullfname, strerror(errno));
return -1;
}
}
//
// file is open for writing, write header information
uint32_t wwidth = htonl(srcw);
uint32_t wheight = htonl(srch);
uint32_t wpixfmt = htonl(pixelformat);
write (convert_debug_fd, &wwidth, 4);
write (convert_debug_fd, &wheight, 4);
write (convert_debug_fd, &wpixfmt, 4);
//
// save start time, this is needed to calculate the time between the frames
gettimeofday (&convert_debug_tv, NULL);
return 0;
}
/*
* if fd is not open open file and set up header
*/
void dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch) {
struct timeval tv;
uint32_t wts, ts;
uint32_t wsize;
if (ptrsrc == NULL) return;
if (config.vdev_dumppath.length() == 0) return;
if (convert_debug_fd == -1)
if (dumpframe_open(pixelformat, srcw, srch) == -1) return;
//
// construct and write header
wsize = htonl(srcsize);
gettimeofday (&tv, NULL);
ts = 1000 * (tv.tv_sec - convert_debug_tv.tv_sec) +
(tv.tv_usec - convert_debug_tv.tv_usec) / 1000;
wts = htonl(ts);
write (convert_debug_fd, &wsize, 4);
write (convert_debug_fd, &wts, 4);
//
// write frame
write (convert_debug_fd, ptrsrc, srcsize);
};
/*
* close file and reset all data
*/
void dumpframe_close() {
if (convert_debug_fd != -1) {
close (convert_debug_fd);
convert_debug_fd = -1;
}
}
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;
};

@ -0,0 +1,42 @@
#ifndef _VIDEODEVICE_DUMP_H_
#define _VIDEODEVICE_DUMP_H_
#include "video.h"
int dumpframe_open(uint32_t pixelformat, int srcw, int srch);
void dumpframe(unsigned char *ptrsrc, int srcsize, uint32_t pixelformat, int srcw, int srch);
void dumpframe_close();
class VideoDevice_Dump : public VideoDevice {
private:
int fd;
uint32_t w;
uint32_t h;
uint32_t pixformat;
off_t filesize;
off_t filepos;
struct timeval starttv;
unsigned char *inframe;
uint32_t inframe_nexttime;
int inframe_maxsize;
int inframe_size;
int fixedframesize;
int Open();
int Close();
int ReadFrame();
protected:
public:
VideoDevice_Dump();
~VideoDevice_Dump();
int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt) { config.vdev_device = newdevice; return 1; };
int SetIOMode(int newiomode) { return 1; };
int Start();
int Stop();
int GetFrame (VideoFrame *destframe);
int SetDevCtrl(unsigned int id, int value);
int GetDevCtrl(unsigned int id, int *value);
};
#endif

@ -0,0 +1,507 @@
#include "video.h"
#include "videoframe.h"
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);
};

@ -0,0 +1,41 @@
#ifndef _VIDEODEVICE_V4L2_H_
#define _VIDEODEVICE_V4L2_H_
#include "video.h"
class VideoDevice_V4L2 : public VideoDevice {
private:
int inbuffer_idx;
VideoInBuffer inbuffer[VDEV_INBUFFERS];
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
int fd; // filedescriptor to the video device file
int Open();
int Close();
int UnInit();
int InitMMap();
int xioctl(int fd, int request, void *arg);
protected:
public:
VideoDevice_V4L2();
~VideoDevice_V4L2();
int SetDevice(std::string newdevice, int nwidth, int nheight, uint32_t pixfmt);
int SetIOMode(int newiomode);
int Start();
int Stop();
int GetFrame (VideoFrame *destframe);
int SetDevCtrl(unsigned int id, int value);
int GetDevCtrl(unsigned int id, int *value);
void PrintCaps(uint32_t caps);
void PrintFmt(struct v4l2_format *f);
};
#endif
Loading…
Cancel
Save