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.
358 lines
9.9 KiB
358 lines
9.9 KiB
|
|
#include "vidoiltank.h"
|
|
#define CLEAR(_var_) memset (&_var_, 0x0 , sizeof(_var_));
|
|
|
|
int xioctl(int fd, int request, void *arg);
|
|
void printcaps(uint32_t caps);
|
|
int vid_initmmap(Video* video);
|
|
|
|
/*
|
|
* helper functions
|
|
*/
|
|
|
|
int 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;
|
|
};
|
|
|
|
|
|
void 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");
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
Video *vid_open(char *name) {
|
|
Video* video = malloc (sizeof(Video));
|
|
strncpy (video->devname, name, LEN_FILENAME-1);
|
|
|
|
//
|
|
// open device and get device name and capabilities | O_NONBLOCK
|
|
if((video->fd = open(video->devname, O_RDWR)) == -1) {
|
|
free (video);
|
|
return NULL;
|
|
}
|
|
|
|
if(ioctl(video->fd, VIDIOC_QUERYCAP, &video->vcap) == -1)
|
|
strncpy ((char*)&video->vcap.card, "unknown", sizeof(video->vcap.card));
|
|
|
|
// printf ("%s:%d %s Capabilities: %u\n", __FILE__, __LINE__, __FUNCTION__, video->vcap.capabilities);
|
|
// printcaps(video->vcap.capabilities);
|
|
// printf ("%s:%d %s Device Capabilities: %u\n", __FILE__, __LINE__, __FUNCTION__, video->vcap.device_caps);
|
|
// printcaps(video->vcap.device_caps);
|
|
|
|
if (!(video->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
|
printf ("%s:%d %s device has no video capture capabilities\n", __FILE__, __LINE__, __FUNCTION__);
|
|
close(video->fd);
|
|
free (video);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// check for cropping.. if we have it setup default
|
|
CLEAR (video->cropcap);
|
|
video->cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
if (0 == xioctl (video->fd, VIDIOC_CROPCAP, &video->cropcap)) {
|
|
video->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
video->crop.c = video->cropcap.defrect; // reset to default
|
|
|
|
if (-1 == xioctl (video->fd, VIDIOC_S_CROP, &video->crop)) {
|
|
// errors here can be ignored
|
|
printf ("%s:%d %s VIDEOC_S_CROP Errorcode: %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
}
|
|
}
|
|
|
|
vid_getctrls(video);
|
|
|
|
return video;
|
|
}
|
|
|
|
|
|
|
|
void vid_close(Video *video) {
|
|
convertstop(&video->jpgcinfo, video->fmt.fmt.pix.pixelformat);
|
|
close (video->fd);
|
|
}
|
|
|
|
|
|
int vid_start(Video* video, int iomode, int width, int height) {
|
|
int min;
|
|
char txt[16] = "";
|
|
|
|
//
|
|
// prepare resolution and pixelformat
|
|
CLEAR (video->fmt);
|
|
video->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (height != -1 && width != -1) { // resolution
|
|
video->fmt.fmt.pix.width = width;
|
|
video->fmt.fmt.pix.height = height;
|
|
}
|
|
else {
|
|
video->fmt.fmt.pix.width = 1920;
|
|
video->fmt.fmt.pix.height = 1080;
|
|
}
|
|
|
|
video->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
|
video->fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
|
if (-1 == xioctl (video->fd, VIDIOC_S_FMT, &video->fmt)) {
|
|
fprintf (stderr, "%s:%d VIDIOC_S_FMT : %s\n", __FILE__, __LINE__, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
// Note VIDIOC_S_FMT may change width and height.
|
|
// Buggy driver paranoia. - as written in the v4l2 api documentation
|
|
min = video->fmt.fmt.pix.width * 2;
|
|
if (video->fmt.fmt.pix.bytesperline < min)
|
|
video->fmt.fmt.pix.bytesperline = min;
|
|
min = video->fmt.fmt.pix.bytesperline * video->fmt.fmt.pix.height;
|
|
if (video->fmt.fmt.pix.sizeimage < min)
|
|
video->fmt.fmt.pix.sizeimage = min;
|
|
video->width = video->fmt.fmt.pix.width;
|
|
video->height = video->fmt.fmt.pix.height;
|
|
snprintf (txt, 32, "%c%c%c%c", ((char*)&video->fmt.fmt.pix.pixelformat)[0],
|
|
((char*)&video->fmt.fmt.pix.pixelformat)[1],
|
|
((char*)&video->fmt.fmt.pix.pixelformat)[2],
|
|
((char*)&video->fmt.fmt.pix.pixelformat)[3]);
|
|
strncpy (video->format, txt, 16);
|
|
// printf ("%s:%d Video Format: %s\n", __FILE__, __LINE__, video->format);
|
|
|
|
// init buffers
|
|
video->iomode = iomode;
|
|
switch (video->iomode) {
|
|
case IOM_MMAP:
|
|
if (vid_initmmap(video) == -1)
|
|
return -1;
|
|
break;
|
|
case IOM_READ:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// convertstart // for mjpg only
|
|
convertstart (&video->jpgcinfo, video->fmt.fmt.pix.pixelformat);
|
|
|
|
return 0;
|
|
};
|
|
|
|
|
|
int vid_uninitmmap(Video *video) {
|
|
// printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
for (int inbuffer_idx = 0; inbuffer_idx < VDEV_INBUFFERS; inbuffer_idx++) {
|
|
if (video->inbuffer[inbuffer_idx].data) {
|
|
if (-1 == munmap(video->inbuffer[inbuffer_idx].data, video->inbuffer[inbuffer_idx].size)){
|
|
fprintf(stderr, "Fatal Error @ %s:%d munmap Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
exit(1);
|
|
}
|
|
video->inbuffer[inbuffer_idx].data = NULL;
|
|
video->inbuffer[inbuffer_idx].size = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int vid_initmmap(Video *video) {
|
|
struct v4l2_requestbuffers bufreq;
|
|
struct v4l2_buffer bufinfo;
|
|
struct v4l2_buffer buf;
|
|
int i, type;
|
|
|
|
CLEAR(bufreq);
|
|
CLEAR(bufinfo);
|
|
|
|
bufreq.count = VDEV_INBUFFERS;
|
|
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
bufreq.memory = V4L2_MEMORY_MMAP;
|
|
|
|
if (-1 == xioctl(video->fd, VIDIOC_REQBUFS, &bufreq)) {
|
|
if (EINVAL == errno) {
|
|
printf("device does not support memory mapping\n");
|
|
return -1;
|
|
} else {
|
|
printf ("%s:%d %s Error %s\n", __FILE__, __LINE__, __FUNCTION__, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (bufreq.count < 1) {
|
|
printf ( "Insufficient buffer memory\n");
|
|
return -1;
|
|
}
|
|
|
|
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(video->fd, VIDIOC_QUERYBUF, &bufinfo) < 0){
|
|
perror("VIDIOC_QUERYBUF");
|
|
exit(1);
|
|
}
|
|
|
|
video->inbuffer[i].size = bufinfo.length;
|
|
video->inbuffer[i].data = (unsigned char*)mmap(NULL, bufinfo.length, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, video->fd, bufinfo.m.offset);
|
|
if (video->inbuffer[i].data == MAP_FAILED) {
|
|
printf ( "%s:%d error on mmap %s\n", __FILE__, __LINE__, strerror(errno));
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
for (video->inbuffer_idx = 0; video->inbuffer_idx < VDEV_INBUFFERS; video->inbuffer_idx++) {
|
|
CLEAR(buf);
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
buf.index = video->inbuffer_idx;
|
|
|
|
if (-1 == xioctl(video->fd, VIDIOC_QBUF, &buf)) {
|
|
printf ( "%s:%d error on VIDIOC_QBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
video->inbuffer_idx = 0;
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (-1 == xioctl(video->fd, VIDIOC_STREAMON, &type)) {
|
|
printf ( "%s:%d VIDIOC_STREAMON %s\n", __FILE__, __LINE__, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
|
|
ImageRaw *vid_grabimage(Video* video, ImageRaw *img) {
|
|
struct v4l2_buffer buf;
|
|
int len;
|
|
ImageRaw *in = img;
|
|
|
|
if (in == NULL) in = image_alloc (video->width, video->height);
|
|
else if (img->w != video->width || img->h != video->height) {
|
|
image_resize(in, video->width, video->height);
|
|
}
|
|
|
|
switch (video->iomode) {
|
|
case IOM_READ:
|
|
if ((len = read (video->fd, video->inbuffer[0].data, video->fmt.fmt.pix.sizeimage)) == -1) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
convert(&video->jpgcinfo, in, video->inbuffer[0].data, len, video->fmt.fmt.pix.pixelformat, video->fmt.fmt.pix.width, video->fmt.fmt.pix.height);
|
|
}
|
|
break;
|
|
|
|
case IOM_MMAP:
|
|
CLEAR(buf);
|
|
|
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
buf.memory = V4L2_MEMORY_MMAP;
|
|
|
|
if (-1 == xioctl(video->fd, VIDIOC_DQBUF, &buf)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (buf.index >= 0 && buf.index < VDEV_INBUFFERS) {
|
|
convert(&video->jpgcinfo, in, video->inbuffer[buf.index].data, buf.bytesused, video->fmt.fmt.pix.pixelformat, video->fmt.fmt.pix.width, video->fmt.fmt.pix.height); }
|
|
|
|
if (-1 == xioctl(video->fd, VIDIOC_QBUF, &buf)) {
|
|
printf ( "%s:%d error on VIDIOC_QBUF %s\n", __FILE__, __LINE__, strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
if (++(video->inbuffer_idx) >= VDEV_INBUFFERS) video->inbuffer_idx = 0;
|
|
break;
|
|
|
|
default:
|
|
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
return in;
|
|
};
|
|
|
|
|
|
int vid_stop(Video* video) {
|
|
enum v4l2_buf_type type;
|
|
// printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
convertstop(&video->jpgcinfo, video->fmt.fmt.pix.pixelformat);
|
|
|
|
switch (video->iomode) {
|
|
case IOM_READ:
|
|
/* Nothing to do. */
|
|
break;
|
|
case IOM_MMAP:
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
if (-1 == xioctl(video->fd, VIDIOC_STREAMOFF, &type)) {
|
|
fprintf(stderr, "%s:%d VIDIOC_STREAMOFF Error:%s\n", __FILE__, __LINE__, strerror(errno));
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
printf ("%s:%d %s wrong IOMODE?\n", __FILE__, __LINE__, __FUNCTION__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
|
|
void vid_getctrls (Video* video) {
|
|
int i, j;
|
|
struct v4l2_queryctrl queryctrl;
|
|
memset (&queryctrl, 0, sizeof (queryctrl));
|
|
for (j = 0, i = V4L2_CID_BASE; i < V4L2_CID_DETECT_CLASS_BASE+0x1000; i++) {
|
|
queryctrl.id = i;
|
|
if (0 == ioctl (video->fd, VIDIOC_QUERYCTRL, &queryctrl)) {
|
|
if (j == 0) video->ctrl_bright = queryctrl.id;
|
|
else if (j == 1) video->ctrl_contrast = queryctrl.id;
|
|
j++;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
void vid_setctrls (Video* video, int bright, int contrast) {
|
|
struct v4l2_control ctrl;
|
|
|
|
CLEAR(ctrl);
|
|
ctrl.id = video->ctrl_bright;
|
|
ctrl.value = bright;
|
|
xioctl (video->fd, VIDIOC_S_CTRL, &ctrl);
|
|
|
|
CLEAR(ctrl);
|
|
ctrl.id = video->ctrl_contrast;
|
|
ctrl.value = contrast;
|
|
xioctl (video->fd, VIDIOC_S_CTRL, &ctrl);
|
|
};
|